User Account Creation (Email & Password) - FastAPI Beyond CRUD (Part 8)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up everyone welcome back now that we've been able to create our user authentication model let us build on top of that so that users can create user accounts within our applications now using this accounts they'll be able to perform various actions within our application as we shall see later on in the series so to begin we're going to go ahead and first of all create the routes that are responsible for our authentic if in one of the videos which is the video where I talked about routers we described how routers can help us to organize routes that are related together so that they are all accessed via a single router now we're going to create one for authentication so to begin I'm going to create a new file which I'm going to call routers pii and inside there I'm going to begin by creating the O router so shall import the API router class if you haven't checked this video out I'll leave it at the top so I say from first API we are going to go ahead and import our API router class once we've imported that we shall go ahead and create our o router and once we've imported our o router the next thing is going to be to create an instance of our Au router so once we've been able to create our Au router instance now let's go ahead and create the endpoint for creating our users or sending them up so that will be created by using the O router now remember all HTTP methods can be accessed on this o router so shall say o router. post and then you want this to be accessed on the slash sign up inpoint or the SL sign up route so I'll just say/ sign up and once that has been done now let's go ahead and Define the function that's going to handle this request so we shall say a sync Dev and this is going to be create user account now since we have been able to create the route Handler function now let's go ahead and Define the structure of the data that's needed to create a user so if we go back to one models.py right here we Define the fields that are required for a user account however if you to notice there's one important field that we forgot and that is the password hash field in this in this series of videos we're going to be making use of passwords to allow users access our application so we need to add that now like for us to set up alic which makes it easy for us to run these migrations so I'll begin by going right here and adding a field so I'm going to call this the password hash field it's going to be a string and we shall basically not serialize it when returning responses so this means we're going to exclude it and by doing so we shall use the field function and within the field function we're going to provide an agument which is going to be the exclude Adent arent now this exclude argument is a Boolean that specifies whether a field should be serialized using this model Now by serialization you mean uh when we are returning this in Json or when we are trying to convert it into a data type from this python class or this python object then rather than displaying it we shall hide it so that we do not expose this password hash now we're going to set this to false actually X is going to be true since we do not want it to be part of our Fields now once this is done let's go ahead and apply this to our database I'm going to pull up my terminal right here and I'll clear it with control and L and next thing I'm going to do is to say almic so this is going to be almic and in this case shall create a new revision now this is going to also be autogenerated so we shall specify Auto generate and in this case we shall call this uh we shall provide that message as ADD password hash or password field or whatever you want to call it so this will go ahead and create the migration within our database and to apply this migration then the next thing we're going to do is say alic and in this case we shall go ahead and finish this with olymic upgrade and then head so this is going to take that newly created migration and then add it to our database so if we go back to our migrations folder we can notice that the operations that are happening within our alic so the first thing we shall notice is we're going to add to our users table a column named password hash and this is going to be its STP so it shall g h a simple string just like we see right here and it's not going to be knowable so almic is going to automatically generate that for us and in case we wanted to undo this we can just run an almic downgrade and then that will go ahead and run the downgrade function to help us undo the creation of the password hash field now if it check with within our postgress we can now confirm that that password hash field has been created and is not now so let's go ahead and create the route for creating our users now to create our users just like I said our has been created right here so we need a structure of the data that's going to be used to create a user so I'm going to head over back to our source folder within our directory I'm going to create a new file which I'm going to call schemas dopy now in any front end application you're going to have forms and these schemas are kind of what you may have as forms on your back end why because they're going to allow you to be able to to pick data from a client and then validate that data before it's actually sent to the server so by creating this schema or this pantic model what we doing is to create a class or a form think of it as a form where our data is going to be sent by any client to our API and then it's going to validate that data check whether any validation errors are present so to begin we're going to import our pantic model P identic base model class so shall say from pantic we are going to go ahead and import base model and once we've imported base model now let's create our class for creating a new user so we need to create a class and this class is going to be called the user create model so this is going to also be a sub class to the base model class and it's going to have fields for creating a user so we going to start adding those so shall say user and our user is going to be a string so in this case we can actually have this as our username sorry for this so this is going to be our username and then we can have our email which is going to be a string and then you can also provide our password which shall be a string now in case you want to carry out validations for let's say the max length or the main length of a field then that's why our field function is going to be so important so we need to go ahead and import that and then we shall use it with our username so we shall say that our username is going to be a field but this is going to have let's say a max length of so this is going to be a max length of uh let's say 8 cars so the username is going to be maximum eight characters and then our email is going to be a field but let's say this is going to be a max length of uh this is going to be uh let's say 40 characters and then for our password we are going to just say this is going to be a field and we shall set mean length in this case so our mean length is going to be let's say uh six characters so minimum password we shall require is going to be six characters and once this has been created now let's go ahead and use this within our route or within our path Handler so I'll go back to routes. Pi which have actually called routers so let me go ahead and rename this to routes and what I'm going to do is to go ahead and provide that within our path hander function so I have to go ahead and import that I'll say from and in this case we're going to have our source or this is actually in the same folder so I can import it via schemers and then we can import our user create model once you imported our user create model let's go and provide it here so I'm just simply going to call this the user data so it will be our user create model so once we've done this now let's go ahead and Define a service file similar to what we did when creating our books or when carrying out C for our books so inside that service file is where are going to have the logic that's responsible for doing anything C on the user side so I'm just going to come and create that file I'll call it service. py and within service. py I'm first of all going to import the model so I'll say from models we are going to go ahead and import our user model and once we've been able to do that now let's also go ahead and import our asnc session class since the session is going to be an instance of the as sync session so shall save from SQL model do e XT do async iio do session we shall import our async session class and once that is done now let's go ahead and create our service class so we're going to create a class and this class is going to be our user service or you can call it old service or whatever you want to name it but I'll simply keep it to user service and this is going to of course have the different methods that shall use when creating a user reading up user updating a user and deleting a user but that's not the point of this video what you want is to go ahead and do two things we're going to check whether our user exists within our database and then if they exist we throw an error if they don't exist then we are going to go ahead and create their user account so let's go ahead and do that so I'm going to define a method and I'm going to call this a sync def so this is going to be a check user or we can call it uh get user let's actually create one to get the user account so we can have a field so let's just say we're going to use their email for checking whether they exist now this is also going to make use of our session so do not forget to provide that and our session is going to be of type A sync session now what we want to do is to go ahead and query our database to check whether a user exists or to check for the user who has that specific email so we're going to need to create a statement if you haven't watched this please go and watch the C where we did for the for the books so in SQL model we shall first of all create a statement and then this is going to be a select statement to get the user from our database so going to go at the top right here and import select from SQL model so shall say from SQL model import select and once that is done we're going to go ahead and make use of our select with our user model so this is Select user then we're going to select the user with the email which is our email right here so we shall say user do email is equal to what you have as our email so it's going to be our email and for us to access the first or the the the first object with this specific email we shall have to create a result object which is going to be a result of using our session so we shall say await session dot in this case we shall execute this statement and right after executing this statement the next thing is going to be for us to return the result or return the object so our book is going to be that specific object so in this case we shall say return book which our book is going to actually be the result of calling the the first method on the result object so so we shall say that our result or our book is going to be result. fast and by doing that we shall get access to the first object that has that specific email so the process is to create a statement create a result after executing the statement and then use any of the methods on that object to get what you want so that's what we have done right here so this is going to get the user by email let's actually modify this to get user by email so that we are a little bit clear so this is going to be get user by email and now right after getting the user by email we're going to also create another method which is going to be called a user exists so in this case we are also going to provide our email as well as our session now this is going to also be of type A sync session and once we've been able to do that now let's go ahead and make use of this method we've used right here so we're going to say at we have actually call this book but this is going to be user so I'm sorry for this I'm really sorry for this confusion so what we trying to do here is to first of all get the user object and once you've got the user object we're now going to return true or false for whether that user exists so in this case we shall say that our user is going to be self which is actually her weight because the method is with her sync so it's a COR routine we have to call it with a weight so I'll say a weight self in this case we shall say self. get user by email and what we shall have here is going to be so one thing I'm forgetting is the self so I'll also have to provide it since we want to call this on the objects of this user class so if you want to access this method right here we shall have to provide self which is going to allow us to get the method so in this case if we say self. getet user by email then we shall have to provide the email which is going to be our email as well as our session and once you've been able to to do that now let's go ahead and check whether the user exists so in this case we shall say if user is none in this case we shall go ahead and return true actually false because th doesn't exist so this is going to return false and then if they don't in case they do they are not none then we are going to Simply return true so this case shall return turn true and once that is done then uh one thing we can do is to go ahead and change this to use something like aary operator so the way you can do this is by changing this statement to say return true if user is not none else false and that will just be the equivalent of the if statement we had written so this will return true if our user is not n else it will return false and that is just a simple syntactical sugar right there so so created two methods one to get our user by email the second one is to check if our user exists and that uses our get user by email thirdly what we're going to do is to use the data that comes from our client to create our user so going to go ahead and do that so I'll say a sync Dev and in this case we shall say create so let's just just say create user so this will be our create user method to take in self to take in the credentials of the user or the information that comes from the client so let's say the user data and once we've been able to create that user data or get that user data let's go ahead and modify it to make it of a type that is similar to the schema that we have created right here so we shall have to import that I'll just come at the top right here and say from dot schemers uh in this case we are going to go ahead and import our user create model so once that is done shall go ahead and provide the type hint and this is going to be of our user create model and then we shall provide that session and our session is going to be type A sync session now once this is done let's go ahead and create our user so to create our user we are going to go ahead and get the data that's coming from our client and let's convert it to a dictionary so I'm just going to say user data dictionary is going to be equal to the user data because this is now an object of type user create model but you can convert it to our dictionaries by calling the model Dum function the model Dum method and once that is done we are going to create a new user object so we shall say new user and our new user is going to be equal to a new user so let's go ahead and create a new user object and then we shall just unpack whatever we've got from our user data so that is going to be it but one thing that we also need to note is that our password is going to be hashed so for us to Hash our password we're going to need to use a path passle so passle is this library that is necessary for us to go ahead and hash our passwords all we do is to get user passwords as strings but store them in a very unreadable format in our database which is just so easy to verify with so when you store this has database we're going to require a string and then check or verify whether that string matches the hash that we have in the database so let's go ahead and do that so the first thing we're going to do is to head over to our terminal and install pass so you shall sa install pass and this will go ahead and collect pass Li and add it to our virtual environment once that is done we are now going to create a utils file we're going to look into the methods that or the function that are going to help us to Hash our password I'm going to come right in here and the first thing I'll do is to create a new file and I'm going to call this our utils.py so in idea is where going to create uh all utility function that shall use as far as authentication is concerned so I'll begin by creating a crypt context object now what this is is simply a way for us to define the algorithms we're going to use to Hash our passwords so I'm going to say from asle do context we are going to go ahead and access the Crypt context class now the next thing is going to be for us to create the context object so we're simply going to say that our password context so let's just call it our password context our password context is going to be an object of type Crypt context and in this case we shall have to specify schem so shall say the our schemes is going to be a list and this list is going to be a list of the algorithms that we going to use to Hash our passwords but in this case we're going to be using bcrypt so I'll just go ahead and provide bcrypt in there and then right after doing this we are going to create the functions that are going to be necessary for us to create our password hashes as well as to verify password strings of the hashes that we have stored in our database now let us go ahead and do that I'll begin by defining a function this is going to be called well let's just call it generate hash or generate password hash now let me just say it's going to be generate password uncore has and this will taking a password or a password string and to go ahead and also return a string so this is basically what we're going to need so when we have a password all we going to do is simply generate an unreadable string of that password that is going to be stored within our database so we're going to say that our hash is going to be a result of using our password context object to Hash our string password so I'll just say this is going to be our password once this has been done now the next thing is going to be to just return our hash once we've returned our hash now let's go ahead and simply go to verifying our password so I'm going to create another function and that is going to be one to verify our passwords so we shall use this when logging in or when creating adj as we shall see so this is going to take in the password which is our secret and then it will also take in the hash that is stored within our database so going to have a password hash and this also will be a string so in this case this shall return a Boolean to tell us whether the password has matched or not so in this case we shall go ahead and say return and in this case shall use our password context object dot in this case we shall call the verify method shall take in the secret which is our password and then the hash which is going to be the password hash that we've stored in our database let me fix this and once that is done now let's go ahead and call this method to Hash our password before we store it in our database I'm simply going to go back right within our service and then I'll say from dot in this case we are going to save from do service we shall import our so this is going to be our generate password hash this is not actually service it's going to be from utils which shall import our generate password hash once you import a generate password hash now let's go ahead and make use of it we inst storing our password so we can update the password hash by saying new user so in this case we shall say new user. password hash is going to be equal to generate password hash and in this case what we want to do is to access the user data Di iary and then shall go ahead and get our password so whatever we shall get as our password from the user data dictionary is going to be hashed and then we shall use our session to go ahead and save our user so let's do that we shall say session do add and in this case we shall add our new user after adding our new user then we shall use this session to commit that to the database so we shall say await session. commit and this will go ahead and finally commit the transaction to our database so right after doing that we shall now go ahead and return our newly created user so we shall say return new user and this is going to be just what we need to create our new user so if you can look at this file what we have done is to first of all create a method that's going to get our user by email and we've also created a new method that's going to allow us to check if the user exists by using this same method and right after doing that then we are going to go ahead and create that user so let's go ahead and make use of these methods so I'm going to go back to our routes and the first thing I'll do is to go ahead and extract our email so I'll say the our email in this case is going to be equal to our user date or this is actually going to be our user data so change this to user data and in case we want to access the email we shall access it via email so let's go ahead and make use of our user service so I'll go ahead and import it I'll say from do service we shall import our user service once that is done now let's go ahead and create a new object of that so I'll say that our user service object is going to be equal to our user service and once we've created that object now let's go ahead and make use of it so shall create a variable called user exists and this is going to be equal to our user service object dot user exists so this will take in the email as well as well as our session and one thing we haven't yet done is to inject our session object inside this router or this rout Handler function so let's go ahead and import that independency so we shall import it from source. db. Main if you haven't checked out the introduction to dependency injection please feel free to goe and watch that cir with SQL model video on this playlist I'll say from source. db. Main we shall import our get session dependency and then the next thing is going to be for us to inject it within our path Handler or within our R Handler function so I'm going to go ahead and do that I'll add the comma right here and then I'll say the our session is going to be of type A sync session so I'll just go ahead and import that let me just copy what I have here and then I'll paste it right here so this is going to be of type A sync session and then we shall just uh inject this object within our route Handler so for us to inject a dependency within our Handler we shall make use of the depend function from first and once this is done then we're going to go ahead and say depends and in this case have have to provide the dependency which is our get session object now once we've got our session let's make use of it so in this case we shall provide our email and then right after providing our email the next thing is going to be the session object which shall provide just like you see right here now remember that this method right here is one that's going to return which is actually a COR routine so we have to await it I'll say await user service. user access now once we've been able to do that now this is going to return a Boolean based on whether the user exists or not just like you see right here it checks whether the user exists or and returns none if it returns false if the iser does not exist so if we go back right here we are going to now make use of this so shall just say if user exists then we're going to throw an exceptions so let's go ahead and do that we shall raise an HTTP exception so let's go ahead and import that we shall say from past apaa do exceptions in this case we shall import our HTTP exception class once you've been able to import that now let's go ahead and finish this by saying raise HTTP exception and in this case it's going to raise the status code of uh so in this case we shall say uh let's go ahead and import the status module from first API so shall just come right here and the top and say import status and then let's make use of that right here by saying status do HTTP 43 forbidden so shall also provide the detail and let's say this is going to be detail is equal to user with email already exists so in this case shall say user with email already exists now when you go ahead and uh pass this line of cod right here that returns true from the user existing we're now going to return what is going to happen when creating a new user so to do that we are simply going to create our new user shall say our new user is going to be equal to a result of using our user service object to go ahead and create a user now remember that is a qu rtin so we shall have to await it which shall say user service do create user and in this case we shall provide our user creation data which we have provided right here as our user data and then we are going to go ahead and provide our session object which is going to be our our session so once our user has been created uh then the next thing is going to be for us to return our response so to do that we shall simply just come right here and say return our new user then we shall specify both the status code and the way to serialize this new user because this is going to be a new user object so for us to do that we are going to go back right here where we created our path so I'm just going to enter in here then I sign up route and then I'll provide some other arguments so after providing the sign up path we now going to also provide the response model so our response model is going to be equal to our so let's just make use of whatever we have on our model so I'll just go ahead and get our model or we can even modify create a schema that will be responsible for returning all these fields as they exist on our user model so let's go ahead and do that I'll just simply come and say class and this is going to be our user model because it's going to return all the information of our user so this is going to be our base model and then we shall just go ahead and copy all the fields that exist within our moderate here except for the database specific stuff now just go ahead and provide it just like we see it right here I'll copy what you have here and then I'll go ahead and paste it right here and one thing I'm going to do is to get rid of anything that has anything to do with our database so I'll just remove this and then I'll remove uh so I'll just go ahead and remove these uh fields or this extra information that links it to our database so once that is done then I'm simply also going to remove this default and then the only field I'm going to not is going to be our password hash because we want to exclude it when we are returning our response so what I'm going to do is to import what is missing and that is our uid module as well as our daytime class so I'll say from date time we shall import our date time and once that is imported then let's go ahead and make use of this user model so inside ours I'm simply going to go ahead and import that I'll say put user create model as well as our user model and now I'll have to just provide it right here so this is going to be our user model so once that has been done now let's finalize this by also returning your status code so shall say the our status code is going to be status Dot HTTP 2011 created which is the right status code for a newly created object to finish this let me format my code I'm having a black vs code extension so it's going to format my code and my code will look a little bit more spaced and organized so right after doing this let's go ahead and test this endpoint out if I pull up my terminal I'll run the server with fast sorry for this this is going to be fast AP Dev and then we shall put to the source folder this will run our server then I'll go to our rest forx right here and I'll create a new request so this request is going to be one for o and in here is where are going to provide all the authentication routes oh this is a new request so let me just create it as a folder I'll create a new folder and this new folder is going to be called o and the first endpoint or request we're going to create within our within our o folder is going to be the create user account request so I'm going to say this going to be create user account so this is going to be a post request just like we've defined it in here and then it's going to be on HTTP SL SL can say Local Host 8,000 slash so the next thing we have have to do before we go ahead is to register this router on our app which we haven't yet done so I'm going to go ahead and save and then I'll head over to our D init.py within our source folder and then we are going to go ahead and register our router so to begin we have to import it so I'll just come right here and say from Source sorry for this so this is going to be from source. o sorry from source. o. routes we shall go ahead and import our o router and once this is imported then let's go ahead and register it I'm going to copy what we have here and then paste it down here so what is our book router in this case is going to be our o so shall say o and then instead of having o we're going to have slash o and then this is going to be our o tag and once this is done hoping that our server is still running we're now going to go ahead and create our first request on our authentication prefix so I'll say API SL version one slash in this case o and then slash sign up so when we send we didn't see theb is missing so let's go ahead and provide it going to come and say that it's going to be Json and if you try to submit f fields that do not have our Fields they're going to be missing so let's start with our test email so I'll just say that our email is going to be our test mail at let's say company.com and then our email so email has been provided we now going to provide our username so our username is going to be our test user one two three then to provide that password I am going to go ahead and provide our test pass 1 2 3 and then when I send this and now going to see that this password should be a string with at most eight characters so we have 1 2 3 so this exits exits the number of characters so I valid is working so you now have to go ahead and provide a shorter password so I'll say test 1 2 3 4 and I think this password will now work so if we go ahead and send so we see uh this is still 1 2 3 4 1 2 3 4 so at most eight characters should we provide less let me provide less so I guess I have to change that so that we have uh our main length only so I'll do that within our scamers and then here we're going to have our password having so I think that's something we did on the models is it on our models I don't think that is if we go back to our schem right here we have uh minan length six max length so our max length should be oh it's our username that's so I'm going to change that so I'll say test user one which is actually also greater than eight characters so let me change that provide this so we have an internal server error let's go ahead and fix that so we now see that user argument that that must be a mapping note user create model so I I think we made that mistake if we go back to our service um we have what went ahead and created the user by unpacking so this should be our user data dictionary so we are go ahead and set this up and when you go back right here we send this request we still have an error so this error is saying that so insertion is fading and we are being told that not now in the column first name or relation users well it's not now constraint so let's go ahead and also fix that so that means we shall have to add that field to our user create model so I'm going to add our first name as well as our last name cuz I think they're all not now if to check within our database we have not now for our first name and not now for our last name now these are going to be automatically added so we don't have to worry about them so I'm just simply going to come and provide them so let's first do that within our schema so our user create model is also going to have those fields so shall have our first name so this shall be a string and this shall be filled we can also parate the max length to be uh 25 characters and then you can also have the last name to be so this is going to be filled and we can have also the max length to be 25 characters once that is done now let's go ahead and try to add those to our to our client now I'm going to come right here and provide them so I'll just come and say our first name is going to be equal to so this is going to be our test and then we shall have a last name so this last name is going to be uh so let's call this test and then user so we shall send and now we see that our user has been created so if we try to send this again we now going to see that our user has been created so this user already exists and we and not allow to create that user again so we have pretty much created our user account so let's create another user we are going to call this uh Jen or John and then we also going to have this second name called do then you shall have the email Being John do at company then you can have the username being Jade door 1 2 3 and then the password so if you send we're now having this being returned now notice how our password hash is not being returned and that is being done because we already set this exclude being to true meaning that that field is not going to be returned when we are serializing the user object so we have been successful in creating our user in fact if we try to create this user we now going to see that our user with email exists so in this video we've successfully been able to create user accounts using the database model or the user authentication model we created in the previous video If you like this video please leave a like it's the way that you can support my video cheaply thanks for watching and I hope to see you in the next video have a good day bye
Info
Channel: Ssali Jonathan
Views: 290
Rating: undefined out of 5
Keywords: fastapi, passlib
Id: iIwKWNGWtyk
Channel Id: undefined
Length: 43min 29sec (2609 seconds)
Published: Fri Jun 07 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.