NestJS: Basic User Endpoints, with Password Hashing | Realtime Chat App | 02/17

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi and welcome to the next video this is video number two from the real-time chat app series with nest gas and angular and here we are adding some basic user end points in sjs so basically we make get in point to get all the users that is paginated we want to or we are making a post endpoint for logging in that also checks for the credentials and we make a post endpoint um to create a new user we also work with beacon password hashing and comparing and we also validate um the incoming requests of it as a dto so we check for example for the login request is where an email provided is where password provided is the email from type email and we also if we try to create a user we check if the email is already in use and so on so our [Music] structure is as always first we have like a look at the video outcome then we read the user story for this outcome and then we implement the user story and close it so let's have a quick over view what we are doing here in this video so here you can see we then have a post request for users where we can create a new user it will check if the user is already existing in the database so it says here email already in use if i for example provide no email at all then we also validate and say email is missing that request but if i give him like a new email let's say like i think free is not given at the moment when we have created a new user we also have another endpoint that is returning all our users and that is pageable and we have a login endpoint where we can log in with the right credentials and we get like true and in the next video series we will also return here jwt and we also check here if the password is valid so we store password hash from the database so if we provide a wrong password we say login was not successful or if we for example provide an email that is not existing when we say we are not even finding the user so let's have a quick look at the story for video number two the story is as a developer i want to be able to create one user we actually can open this in preview here i also want to log in with user credentials and i want to be able to find all users all these three via api calls and if i try to create a user it should first be tracked if the email for example is already in use the password should always be stored as a hash in the database so never store a plain password in your database and if i try to log in the provided password that i enter should be compared with the hash that is stored in the database so we have some acceptance criteria here first you want to have like a new user module for nestgs and there we have our user service our user controller where we have the end points we have like our user models everything that we need for this um part of our application then we have in our user controller new endpoints that are a get endpoint to get all users and we want to have a paginated response so that we can piggy nate through them so we can if we later have for example hundred users we can for example ask our api for and return the first 10 users or return the second page of 10 users and so on then we want to have a post endpoint where we create a new user so we provide an email a password a username for example and we check if he already exists or not and create it and we also want to be able to make a post request against the login route um and we want to log in based on email and password so we want to check always every email if we create a user is already in use we will always want to store the password as a hash in our database and never store the plain password and we want to if i try to log in we want to compare the provided password against we have in the database so this is basically our story and now we can try or we can implement it so first as you remember in the last time we can start everything here with docker compose up and then we have our api in our front end and at the moment our api is just having one endpoint here that is returning from our user service hello youtube and we fetch or we get this response in our angular front end so if everything here is started we can just go to our front end on localhost 4200. and wait till it's built takes a bit time and then we should get displayed hello youtube so you can see now here we get hello youtube from our api so if we change this here for example to hello twitch and we save when the siri compiles and when we reload we see hello twitch but since we are here on youtube we changed the spec so we can now finish this here for the moment and now we can start implement our api so first we want to go our cd into our api folder now we are here in our nest folder and now we can use our nest cli to generate our module so we can say nest generate module user so we want to generate a user module where we can handle all the stuff that is related to user now you see we have here created our user module empty at the moment but we have can fill it up so then what we need is we want to [Music] be able to hash our password for this we are going to use um decrypt so with this we can hack our password um and we also can compare it so when we search for compare you can use bcrypt compare you can use your plain password and compare it against the hash or for example if you want to have a hash you can make it with bcrypt.hash give it a plain password and then store it in your db database we also want to install an sgs typo and paginate so this is like a very yeah easy package that you can use to make pagination requests so you can see it here you can just use paginate from this [Music] package provide some options and then you get a paginated response here let's see you can have here when as a response you get items and you have all your items here and you also get meter data how many items are there so total items items per page what is the current page and you get links so you can for example build a linkable api so we want to install both of them so we install or we copy this here and we want to save it also also i think it's default so first this then we also want to to use bcrypt for hashing the password so we install this or save it here also to our package json and we later also do some validation stuff with dtos so we can search for class validator npm for this package here and can install this also um then there is another um yeah when we can if this is installed we can create here our controller our services and our models so the first thing that we want to do is here to create our models or our entities so we can just call it the folder model and then we have here like another folder for dtos and we also first need our entity so that we can store something to our database so here we can simply say export class and this is our user entity and since we are using here type or m we can say at entity from type o m and then we have to think about what properties just like the user has so the user always has a number and this is like the primary column and this should be generated so we can use a primary generated column from type or orm the user should also have a username from type string it should also have an email which is also a string a password so this is also a string so here we want just to store the hash and we always want to store the email as lowercase in our database so we can easily compare against it so we search for it so we can say this.email is always this email to lowercase so and we have to annotate this with before insert so before we insert a value we always [Music] make the email lowercase and now we can adhere some stuff so the username should be a column the email also but this should also be unique because [Music] there can never be two users that are having the same email and then we can make something because if we later make for example a find one so where we just want to return user or return multiple users from the database then we don't always want to use the password and so we can give the column here some options and this means select so you can see here the column decorator select is used to mark a specific class property as a table i mean select so here indicates that the column is always selected by query builder and find operations default developed value is true so we can set this to false and this means um if we make a request with type or m and try to find a user here then it all automatically strips off the password from the return so we don't have to do this manually in our code and if we want to get the password we have to yeah specifically um select the password also in our code but this saves us here quite some time then we can add here like a user interface that we also need so we can say user dot interface dot ts and here we can say export interface user interface and then we have here like an optional id number username email and password also optional and save it and then we can go to our like the dtos so that we need um to validate incoming requests but before we do this we can also start by making our controller so we can here again use the nest cli and say nest generate controller user this should generate here user controller i hope so and not on the top user controller and we already imported this here so but to make it easier um to find let's make here our own folder for controller and then in our module we have to update the path so this is now controller slash user controller and here we have to specify all the stuff that we are using so we can for example cd here cd into user and now we can also say nest generate service and now we want to generate our user service for our user module and you see it here now we automatically have it provide here as a provider our user service and we rename rename this folder to service and this updates automatically and another thing that we have to do is we need to have some imports and here we need the type of n module and we have to import for feature so this is basically um type or m module dot for feature and i think here we have to provide um the entities for this module and this is just our user entity for the user module here the user entities the type or module knows how to configurate everything so now we have here our controller and this should be like a plural and then we can make um our api or we can build our api and here we then also use the dtos and the interfaces and everything so the models so of course we need a constructor because we need to inject our user service so we can say here private user service user service and then first probably we can make a post request to create a user so here we can make a post request we use this from nestress common and say we want to create a user and so we want to as a response return an observable from a user interface type and then we can we have to do here some logic to create the user and the first thing that we want to check here is um we get something in the body from the request this is um the user for example the email the username the password then we want to check um if these are all provided and if they are there so we say we have here like our create user dto and we first have to create it so we can go into here and we can say [Music] create user.dto.ts and we can export a class create user dto and we can also have a dto for login user dto and so we first can make this class here and this is very simple we have like the email which is from type string and we have a password that is also a string and then with the class validator we can check for example it is email so this checks if it is an email and the password should never be empty so if we register user or if someone is logging in we always need a not empty we always need the password so we annotate it with this and here we can we also need the email and the password and we extend just our user or login user dto but we also need one more that is the username and here we can for example click this string and we can click it is not empty so then we can use them in our controller and here we can check for this and if we want to check for this here we also have to include it here app dot i think we can google it so yes js validation type so we can just you see the validation pipe and then always if it finds the dto it dries to validated we can check this then later in our api if everything works fine so for example we can just check this out at the moment so we can say return true and we have to make it an observable and then we can build it so we can say first we have to cd to our docker compose file so then we can say double compose build and then we can start it and then we can try to access this endpoint and then we should see that it tries to validate the user dto so we can already start up postman and then we also i think have to have a deeper look um and to be crypt this is working all correctly so here we have um postman so we can for example try to make then our post request against the local host thousand slash api slash users we make a post request we have to wait till our api is up and then this year should work or it should try to validate the dto that we provide or that we not provide the properties so let's in the meantime check our compose file and i think this year is probably wrong so we want to make this inside our container so we can update this and we can also remove this here because otherwise um we would copy this stuff here and it wouldn't make any sense because then we would copy the b crypt stuff from our node modules here into our application so we can remove this and then we can also restart this here i hope this goes a lot faster so now it's building the front end and then we can try to make some requests so we can also i can already go on docker compose up and try to start everything here so let's make a little bit bigger for you to see now let's give it some time so here's our api so the classroom smart package is missing please make sure to install this library class transformer i thought we had installed it let's have a quick look all right now we didn't install it so we need the class transformer package so let's see can we find it here no and then we can just use it from here cd in outdoor api save it and then we have to rebuild our docker stuff so we can search here npm class transformer package and then we can build it again and while this is running we can already add some endpoints here so we want for example to have another find all here where we find all our users so we can make it as simple get and then we want also to have a login endpoint from type post so these are just empty but we will fill them later we are finished here so let's read a bit [Music] here so here we have like our validation pipe and we can just use it like we did so then we ensure that all end points are protected from receiving incorrect data and for example with your create user dto create usage oh basically the same that we are having here in our code and then this checks for example for email for is not empty exactly like we do and if it for example checks that there is an email that is not having an add or something like this and it says bad request the value has to be for example email so we can start again now let's see when all the packages are there so now let's see if everything works fine here and then we can try to check it but it's working so now we have our api started so we can make like a post request and now you see we have all the validations that fail so we have username is not should not be empty must be a string email must be email and password should not be empty so for example we could now give him some values and we can say first we have our email let's say thomas thomas.com we have password let's go with easy password and uh yeah i think that should be the username username and now we can try again and now it returns true and if i for example provide an email without an ad then this should also fail because email is not an email so the validation works and now we have to implement the rest so because we don't want to just return a boolean so first we want to if the user dto is correct we want to map it to like our interface so for this we can for example create a new um or a helper service so we can say nest generate service user helper and then we can say in our service we have a user service this is our existing user service so we just moved into this folder we have our user helper service that we also move to service and here we can just map something and here we have to update the import so now we can go to our user helper service and add two simple functions here so first we want to make create user dto to our entity so our input is like our create user dto from type create user dto and we want to return observable from user interface so we can simply say return when we make it observable often we return an object and here we say email is create user dto dot email we have our user name create user fault create user dto dot username and we have the password createuserdto.password and the second is we want the login user dto to entity also so we have here login user dto log in user dto and we also return here an observable from user interface and we make the same turn off and then we return our object and here we have our email login user dto.email and we have the password from login user dto dot password you can save this and then we can also import the service here so we say private user helper service user helper service and we also have to make sure that our providers here and we can use it so we can then simply start here with return this dot user helper service dot create user dto to entity we use here we create user dto so as soon as we did this endpoint here the validation pipe clicks if this is valid like we saw in our postman request and when we go into it we create our user interface or our user and then we can make it pipe and switch map and then we have here our user and then from our user service we want to call our create and now we have to make our everything here in our user service so first we need our constructor and we have to inject our repository so this is basically simple so we use incorrect repository from ministry as typeom and this is for our user entity and then we say private read-only user repository from type repository user entity and then we want to make like our create where we have our new user from user interface and we map all um the dtos on the controller level and then here in our service we just work with the objects or the entities or the interfaces and so that like controller you can change everything but this here will still work um and here yeah we want to make an observable or return observable from the user interface and here first we want to check if our email exists so before we enter this we make like a private function here and we check if the mail exists and as input we get the email from type string and we will return an observable as a boolean value so we can easily then say return from so here we just make from our user repository we use defined1 and then we provide an option and we want to query for email or only for email and then we can type this and we map the user that we get back and we have to import map from air x js operators and then we can say if we have an existing user then we return true if not we return of course false so then the first function or the first that we do here in our create we say we want to return this dot mail exists and then we give him our email and check for this then we can pipe it and make a switch map and then we get like in boolean deck so we can name this for example exist so if the user exists which is from type boolean and then we can make or we can check so if the user is not existing we want just think about this so basically we want to say it exists is true then we want to make some stuff and else we can actually throw an exception so we throw new http exception and say for example email is already in use and we have to provide http stratus code and here we can say conflict because it's already existing and then if we have it we can say um what is it saying here so then we can return this and then we want to hash our password so we need here like another function private let's say password and this should take like the password from type string and we also wanted to return an observable from type string because this is vendor hash and here we simply want to use bcrypt so let's check this here so we decrypt when we can use this should return something like a string and then we simply convert our b crypt and use our hash and here we just provide a password and we say 12 salt rounds and then we can use it here so then we want to hash our password and for this we say new user dot password and we pipe this here again and then we want to return from our user repository and want to save the new user so we make a save we save the new user and we have to pipe the outcome also because the safe would return the user with [Music] sorry here we need the password which was a string so i think we have here there we are so this pipe closes here this closes here and we need this and this should be fine we can reformat it so then we want to save the new user and since we don't want to store the plain password we have to overwrite um the password from our user with um the password that we are getting here so we could for example name this password hash that we get back from our function and so we can just make a comment to make it easier overwrite the user password with the hash to store v hash in the database to make it clearer and then this save would normally return the complete user object so with password but we don't want this in return so we have to make a switch map and then we could either strip a password of it or we can simply make another find one request and use here the user.id and then since we have no entity with select faults it should not return the password so for this we can make here like another function so we can say private find one we say we have as an input to the id number and we have here also an observable and we return the user and then we can simply say return from then we use our user repository and we look for him by the id and then this should work i think so we can now in our user controller you spend here our user and then we are not returning here a boolean anymore on the user interface and we have to import switch map and then we can check if this works so we can fire it up and then we can try um yeah to create a user and we can also connect against our database so as you remember we have here our postgres adminer that we can access on port 5050 i think so you can go to localhost 5050 and if it started correctly we should be able to access it yeah so we have it here then we have to look up what was the credentials so admin and admin and password so we can then log in and connect to our database so we can add a new server let's call it database say the connection is postgres the maintenance database is db so all as we set it here in our postgres and the username was user and we have password so user password we try to connect and then we see that we have here our database and we can also check that we have like created everything so you see we have here our user entity table at the moment it is empty i think now we can make here our request with this stuff now email is already in use so let's try with another email maybe i tried something with this before or our code is incorrect so let's see what we get in return here and when we create so you see here we get files so we have to change this up so if the user is not existing of course then we want to have the password so we can actually shorten this to if it's not existing we want to have the password and we want to create the user so let's remove this here cancel the request and you see now we have it created and now we should find the user in our database let's have a look how i can query this here select all from user entity maybe this works yeah so you see here now we have id1 my username my email and we store the password as a hash so then we can make like the next or the other requests so let's make it a bit this is just the postgresql tool logging everything out we have to so then for example we could do the yeah let's which point can we do maybe define all so this is also get request and what we can also do as we see here we get and return it 201 created this is good and undefined all we say we have like here query parameters this is page we name it page which should be from type number and the default if nothing is provided we have the first page and then we have the limit from time number and default to 10. and then we want to return also an observable and here we use the pagination from the necessary speculation package and then here this should also be from type user so our items here and then we can check them because you never want to return more than 100 users we say if the limit is bigger than 100 and can make it a shortcut then use 100 or else use this bit the number that is given so then we want to return our user service dot find all and i think this is at the moment not existing so we have to do this and this is very easy because um we get like a pagination object so this is pagination options from the package nest class type of impaggy nade we return an observable also from type pagination and user interface and then we can very simple make it from we call the piggy nade from the same package we want to return the user entity and we use our report user repository and then we specify the options and this should work fine so then here in our find oil we have to specify the pagination options so we can pass an object and first we have our page we have our limit for example we want to return the first page with 10 users whatever and we can specify a route so the base route that should be added to the links so at the moment this could be localhost 3000 slash api select users then we can try to make get requests against this year so let's say localhost 3000 api users and make a get and now you see we get like our pagination object which has items so just one user at the moment meter data how many total items count items per page and so on and also links so we don't have a previous and next because we just have one at the moment if i create here another user with another email and then run this request again when you see we have here two users so this also works fine and then the third one is we want to be able to log in and here yeah we can yeah we have to provide also in our request body some stuff so this is our login user dto so that the validation pipe will check if all um stuff that we need is provided and this correctly and right now we can just return a boolean but in the next video we will generate a jwt with all the user properties that we need so that we can later save all our requests from our front end to our backend with this jwt so to authenticate the user so first here again we have to use our user helper service and create our user entity from our dto so we pass in our login user dto and then we use our outcome here to make a switch map because then we do have a user and then we can go against our user service and then we need like a login function that we now have to do so we make it or we name it login and here we take a user on user interface and we return at the moment an observable boolean and we can annotate this here with a comment and say um change to trade wt in next video or let's say refactor to use jwt in the next video so then we say we first want to find our user by email and we also have to create this here so we say private find by email and of course we have to provide our email which is a string and as a return we have an observable user interface and then we make return from this dot user repository we want to find one you want to find with the email but as you remember here we find one here we would not return the password but since we are logging in we have we need the password so because we have here provided password and then we get the password hash from our database so here so that we can check it the password is correct so we can specify here some stuff and we can say for options so we want to select and what we want to select are we want to have the id we want to have the email we want to have the username and we want to have the password and then this returns also the password because since you remember our user entity we have select fault so by default find one it will not return the password but if we specify it here with select it returns the password so we hash and we can compare it so then our login or we can also make a comment here also returns the password so then we can use it here so we can simply say that we want to do this function here so find user by email and we specify the user.email and then we type the outcome and we make a switch map and our user is our user interface or let's say found user so that we name it differently and then we make some stuff with it so if we have found a user when we do something else we will throw an exception so we could say we throw new http exception [Music] user not found http status not found and then if we have found a user we want to validate our password so at the moment we also don't have this function here so we need it and here we can also use uh decrypt so we have our password as a string that is from our request and then we have like our let's say stored password hash but that's also a string and we get like the boolean back and then we can very simply use bcrypt dot compare and we can just have a quick look at it so you can see when we go to the compare we have here the plane pass text password so this is what the user is providing in his request so if you log in then we have here our user and we have the password that he's providing and then we get here from our database find by email our you found user deck with the password hash so then we have to compare our password again the password hash that is stored in the database so like we do here and then it this either will return true or false if the password and the hash or we have is mattress or not so we say compare and then we just give him the password and the stored password hash so we can then use it here and simply give him first our user dot password and second the found user dot password and then we can pipe the outcome again make a switch map and we can simply say this this mattress so if we match we have a true and if not we have a false so if mattress is true or else so if it is not true we can simply again thrown http exception and say login was not successful wrong credentials and we can provide the http status for example unauthorized here we can return this dot find one because we don't want to return the user that we found here because he has a password and we can simply name found user dot id and at the moment we are returning here boolean so we can simply say pipe and map to so we map it to a true value the pipe and then in the next video we change this to trade wt so what is he saying here empty block statement why no no no no well i think this is let's open this again yeah now it's done um here so now we should have um this working so here we have to provide then our user here that we converted from our user dto and then we should return true so we can also check this endpoint here so we say localhost 3000 api users slash login because here we have to make it of course login route and then we can try so if we now make a simple pause request against it the validation pipe says we need an email and we need a password so we have to give him an email and a password so we say email and we say password so now it should say email must be email so we can for example use here this email so both users remember has have the same password at the moment so this should return true and if i now give him a false password then the password validation in our login so here the password validation should fail and we should throw like a http exception locking not successful from credentials and you see we get a 401 unauthorized login was not successful from credentials if i change this up again i get it mapped to true so like i said in the next video we want to make this here that this returns a valid trade wt and then we also make like an authentication module so that we can then move all the stuff for authentication and password hashing and so on move them to the other modules so that we have separated everything correctly so now i think we are already at the end of this video we can check against our user story if everything was correct um yeah so we are in story number two of course so we have now a new user module for an s3s we have a new get endpoint we have a new users endpoint and we have a login endpoint and we check if the email is already in use otherwise we are not creating anything we check or we always say password as a hacker in our database so we can click this also and we compare the password to the hash on login as you remember if not this fails here so in the next video on the next story we want to then return proper jwt we want yeah to make something to check the roles if you are able to access or to get all users for example yeah so i think here is everything done now so now just commit everything so we can stop docker compose here and then we say get at a and we make a commit message so let's first have a quick look for the commits how we named the last okay video one prefix okay so let's do it the same here video two and now we can say edit user module and endpoints for creating login and get all users and can push it
Info
Channel: Thomas Oliver
Views: 866
Rating: undefined out of 5
Keywords: javascript, typescript, nest, nestjs, nest.js, typeorm, git, gitflow, node, development, api, observables, rxjs, nestjs7, bcrypt, jwt, authentication, git-flow, gitFlow, docker, docker-compose, pg-adminer, debugging, hot-reload, angular, angular material, angular lazy loading, material, realtime chat, real time chat, chat app, realtime chat app, live chat, live chat app, nestjs8, nest js 8, nestjs 8, NestJS8, NestJS, nestJS, postgres, angular 12, reactive forms, login form angular, register form angular
Id: Hi6V6RbTmNM
Channel Id: undefined
Length: 65min 17sec (3917 seconds)
Published: Mon Jun 21 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.