NestJs Course for Beginners - Create a REST API

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Thanks. I'll be checking it out after work.

👍︎︎ 3 👤︎︎ u/MoesAccount 📅︎︎ Feb 22 2022 🗫︎ replies

Great tutorial!

👍︎︎ 2 👤︎︎ u/marius4896 📅︎︎ Feb 22 2022 🗫︎ replies
Captions
s js is a framework for building scalable Node js  web applications with TypeScript in this course,   Vlad will teach you an S JS by teaching you how  to build a REST API. Hello, and welcome to this   course. My name is Vladimir, I am a full stack  software developer. In this course, we are going   to build a CRUD REST API with Nest. Yes, our goal  is to build something as close as possible to a   production app, we will implement authentications  and to and tests. And we will work with relational   databases as well as with a modern development RM  such as prisoner. My teaching style is very hands   on. I'm a firm believer that you only learn by  doing all my code is very easy to follow. But if   you're stuck, you will find a GitHub repository  with the completed project in the description   below. Additionally, feel free to leave questions  in the comment section or on my channel code with   flood. I will try to answer to them as soon as I  can. This course requires a basic understanding of   JavaScript ESX and TypeScript. But don't worry if  you don't have it, as I will explain everything in   a step by step fashion. So what is nest GS?  Not to be confused with Nex GS, which is a   front end react framework. NES GS is a no GS  backend framework. It fully embraces TypeScript.   And it's also very different problem from  let's say, express GS, it solves architecture,   the weak point of Express GS, see, if you're  using Express GS, it's very unimplemented, it   doesn't give you a direction of how your product  should be structured, or how you should do things.   And while Express GS can work out very fine for  small projects once your product starts to grow.   And if you are not an experienced developer that  knows how to structure it and scale it properly,   it can quickly become a mess. But NES GS is not  just another framework in the sense that it does   not try to reinvent the wheel, it actually uses  Express GS under the hood. So you can see it as   an abstraction of Express GS. And in a nutshell,  it allows to create testable, scalable, and easily   maintainable applications for NSGs. Modularity is  very important. It uses concept like dependency   injection, and it is often branded as the Angular  for backhand. So now that you have an idea of   what NES GS is, why would you use it? Well,  structure, modularity, native TypeScript support   a lot of functionality out of the box easily  integrates with Graph QL micro services REST API,   and has very good documentation on security. It  also tremendously grows in popularity, which is a   very important factor to consider. In fact, right  now, NES GS is the most popular back end framework   below express on the same level as Koa, Gs, and  above, Adonis, loopback, feather Gs, and even   Meteor. Plus, employers really love it because it  brings architecture structure. And it's easier to   hire developers because they don't need to learn  a new custom architecture every time they are   on boarded on a Express GS project. So after that  long explanation, let's jump into our project and   code our NSGs application. And in this project, we  are going to build a API application programming   interface. This will be a CRUD API Lucia's very  common terms for API's and the resources that   we're going to either update, read, delete, or  create will be bookmarks. So without further ado,   let's get started. Before we start, we need to  have no GS installed. I'm using version 16. But   any future version with a long term support should  work. You also need to have Ness GS installed.   So you need to install their CLI globally and  yes, yes CLI. Then we can drop into our terminal   and create our new project with Nest new.  And let's name it nest GS API tutorial.   The CLI will ask you to choose a package manager.  I usually like to go ahead with yarn. Perfect. Now   our product is installed, we can navigate into it.  I will open it with code VS code. But you can of   course use any editor of your choice. And let me  make the code bigger. This is the VS code Visual   Studio Code. The theme I'm using here is material  theme. And the icons you see here is material   icons. You can download them and install it here  via their extension menu. So NES GS has created a   starter project for us. It has a source folder  where our files are, it has a test folder,   where it keeps the end to end tests. And it  has some configuration files here. Let's first   clean it up, we don't need the app controllers  back. And we don't need the app dot service.   And nor do we need the app dot controller.   And since all those files were imported into the  app module, we need to go and delete them here.   So for NES modules are very important. You  see that this file, the global file is called   app.module.ts. This is similar to something  that we have in React, where we have an app.gs   or app.ts file. So this will be the main module or  the app that will import other modules. So I have   talked about modules, but I haven't introduced  what is a module. So for any concept related to   nest, yes, you can just go into the nest Yes,  documentation, and it's on the nest years.com.   And you click on documentation, and you'll have  this page where you will have a lot of docs on   any concept that you want. And for instance,  here module, it's written that it's a class   annotated with the module decorator. And in fact,  we have a class called app module that has been   annotated with the module decorator, if it's not  annotated with the module decorator for net, yes,   it's not a module. And if you don't know what a  decorator is a decorator is just a function that   adds some metadata to the to the  current class or function that it is   kind of decorating. So just adds more property to  to that class. So if we go back to the modules,   documentation, we see that a module can import  other modules. And it is the case for the   application module. So the main module, the root  module, it can, for instance, import User Module,   or there's model chat module, any module that  you want. And every module can itself import,   also controllers, and providers, we are going  to talk about those a bit later. But for now   know that a module can import other modules.  And usually I like to organize my modules into   feature modules. So if I have an application,  where, for instance, we have bookmarks, well,   what would be the part of the like the  application, right, you will have the   authentication logic where a user can create its  profile login sign up. So for me to be ot module,   then you will have maybe user module that will  handle the logic related to the user will have   also the bookmarks module, and maybe the database  module. So you see, you organize your app into   those features, right, and you break it down into  modules. And the result is that it makes your app   much more easier to handle. And to reason about,  let me show you a another project I'm working on,   just to illustrate the structure. So I have a  source folder. And you see I have an old module,   category, common post Prisma, which you see all  around for the database user. And if I click here,   you see that you have some data, you have the  module as as, as we expect, and we have some   providers, those we are going to talk about it  a bit later. But this is an example of a kind of   production ready, project. So you guys can see the  organization and the cost structure in a nutshell   of of next year's projects. Okay, so we now know  that modules organize your app, right? And they   are declared with a class annotated by a decorator  module. So let's go ahead and declare another   class another module to break down our application  into those small sub modules. So we know that we   are creating a bookmark application, what would  there be in a bookmark application, while I have   already touched upon the authentication. So in our  CRUD API, I want to be able to create users and   to allow them to log in, right, so we will have  an authentication module. But let's go ahead and   create a auth module. And usually the convention  is that you need to put the modules to create   in a folder, and the only time that you can not  respect this convention is when you're using the   main app module component that will import all  the other kind of modules or components. So   let's go ahead and create the  folder here and let's name it out.   And at first, I'm going to show you how to  create it manually when you're using a framework   for the first time. It's Better to actually write  everything on your own and not use any generators.   Because nest yes has a generator has a CLI command  that allows you to kind of automate that creation.   And we're going to see that in a moment. But at  first just write it by hand. So we get a bit of a   muscle memory going on. So we create a folder  called auth. Right? What do we know about modules,   we know that it should be it should be a class  that should be annotated by decorator module.   So let's create a file. And we just respect that  convention that if we have a file, we try to add   the its kind of function to its extension. So this  is an extension right.gs is an extension.ts is an   extension dot, CPP for C++ would be an extension  as well. So here, it's since it's module, it   will be.out.module.ts. And we're using TypeScript  for all the products. So it's Ts, and we need to   create a class. So it will be od module, right.  And we need to decorate it with a decorator,   called module. And that decorator  comes from the Nash Yes, common   module, and we just need to open it provide  an object. And that's it. That's the minimum   requirements to create a module. So all we need  to do is to save. And that's it, we have created a   module, and we have forgotten something important,  we have forgotten to export that class. So if we   don't type export, this class will be available  only inside that module only inside that file,   when you export it to allow other files of our  application to use it. So we go back to app   module. And now we can just import our module.  And we can use TypeScript intelligence to help   us to find our modules and files. So here, it  knows that the auth module exists inside out. So   all we need to do is to click here. If it doesn't  appear, you can always do command.or control dot,   and it will propose you an option to import it  from the odd module file. And here it is to verify   that our logic works, let's go ahead and launch  our NES GS application. So the bootstrap logic   is inside the main.ts. It looks a bit like what  we could expect from a Express GS application,   right? So we have the app that is being  instantiated here. And then we launch a server   on port 3000, I will use Port 3000 333, because  usually, the port 3000 is reserved for react in   my development pipeline. So I prefer to use  3333. I save it. And now I open the terminal   in the project. Let me clean that out. And all I  need to do is I need to do yarn, start Dev. And   all those scripts are actually defined here inside  the package that Jason, we have start. And we have   start Dev. So the reason why I'm using start Dev  and not start is because start dev What are files,   and recompile the code when needed. So if we  do yarn, start Dev, it will launch NES Gs,   and we don't have any errors, which means that  it's very good. Everything has compiled correctly,   NES GS has generated a dist file, so a kind of  output compiled JavaScript file from TypeScript,   we don't need to really worry about it. It's just  how naseous works. And that's it, we have our   API working. So let's clean that up and, and come  back here. So modules allow us to break our app   down into smaller components that we can easily  manage. Let's go ahead and create the user module   and the bookmark module. In this case, I'm going  to use the nest CLI to create those modules. So   you have an idea about how it works. Just open the  terminal, and we'll going to open a new terminal   session. And we execute nest G for generate  module. And we name it user and nest will generate   the module for us and automatically imported into  the app dot module for us. So we have a folder   user, with the user, that module class here.  And we do the same thing with a bookmark.   Right. And it also generates a bookmark  module for us. And if we check our terminal,   let's kill this one. We see that the application  is still logging. If I for instance, press Ctrl   save, you see that it is recompiled so everything  is working correctly. Now let's add more logic to   our application. So let's add the login logic. So  when we build a nest GS application will usually   separate our logic into controllers and service,  we can refer to the documentation. And basically   it says that controllers are responsible for  handling incoming requests and returning responses   for the clients and providers or services are  responsible for executing the business logic.   So we separate our logic into controllers and  service providers to be able to, to simplify   what we do, right. So let's go ahead and implement  it. We go now into ot module, and we create a   service and a controller. So again, the same can  be done with the NES GS CLI, and we're going to   do it by hand the first time. So let's create  a controller, dot Ts, and ot.service.ts. If we   go to the controller, we need to create a class  class or controller, we need to annotate it with   the decorator controller. So nest years knows that  it's a controller. And we need to do the same for   that service class service. For the service, we  need to annotate it with the decorator injectable.   And that just means that it's going to be able  to use the dependency injection that NES GS   uses under the hood. But more on that  a bit later. And we need to of course,   export those otherwise, we will not be able  to import those classes in our application.   And since we have added that, we need to add  that to the module as well. So controllers, or   controller, and providers, or that service, let's  check our application if it's running correctly.   Okay, no errors. Cool, running good. So I've  introduced the dependency injection, but I haven't   really said what it is, you can of course Google  it online. But let's go ahead and introduce it   with a concrete example to see how it works. So we  have a auth service class and we have a controller   Christ, right? What is happening usually is that  the controller will need to call the service. So   the controller will receive a request from  the internet, for instance, a post request   asking to login a user, right. And then it's  going to call a function from the audit service   class and return its result back to to the client  back to the browser. But to do so, ot controller   will have to instantiate a auth service class,  right, because in the end, it is JavaScript.   So if you want to create that instance,  for instance, it will be service is equal,   new or service, right? To avoid doing that. To  avoid having to manage where it's created, and who   manages it all, we use dependency injection, that  means that instead of our controller to actually   have to declare it, for instance, to actually  have to do something, something like that,   give me the service here, give me that, an  instance of that class. And I don't care how to   instantiate it, just give me an instance. And  this is how you do it in SCS. Private or service.   Service. And that's it. Nice, yes, we'll handle  on itself, How to instantiate the auth service,   and how to pass it to you in that old controller  file. So you don't need to really worry about and   private here, if you have never seen that  notation, it just means it just means that   and then have to do something like  this, or services equal or service.   Instead of doing that, you just write private, and  you scrap off this. That's that just a shorthand.   And if we check our code, we see that it  is being executed. So everything is okay,   everything is compiled. And now if we  want, like if we put a function into the   odd service called test, this function is not  going to return anything. If we want, we can call   this function directly like that. Right? So  that's dependency injection in a nutshell,   if you want more information, just Google it.  There's a plethora of explanations online,   how it really works. This is how Nigeria's use  it and basically it allows us to not handle   dependency management. And it's just easier to  work with when we have dependency injection.   So let's come back to the auth service and create  two functions because our auth module will manage   to functionality, login and signup. So let's go  ahead and create a function, login and sign up.   Right. And that's all is going to do for now,  the auth service will store the business logic   right now there is none. So let's come back  to the controller and create two endpoints,   an endpoint for login and an endpoint for signup.  So the way to do it again, is using decorators,   it just simplifies how you write your logic. So  we expect a post request on signup and a post   request on login. So we create a function,  let's name it sign up, right, and sign in.   And, and to make it a route, we just need to  annotate it with the post decorator that comes   from Ness GS common, and let's call it signup. And  sign in. And since we are in the odd controller,   it's usually a good practice to put a global  prefix route called odd. So when we are going   to call that route, we're going to do a post  request, have to out signup, right. And if we call   that route, it's going to be that that request.  Let's just return a string for now. I am sign up.   And here I am signed in.  Let's verify that the product   is compiling all good. And let's go ahead and  test our API with insomnia. So insomnia is a   HTTP client, similar to postman, you can also  use postman if you have if you're used to it   in some way, just a bit more minimalistic  and easier to use. So let's go ahead and   test our endpoint. And if you remember, our old  controller was on the endpoint, odds sign up, and   right. And we do the Send Request. And we see  that we have response, right, I am sign up.   And that is basically what we have written here,  right. And if we launch and free request sign in,   it's going to print us the other response. One  interesting thing, though, is that if we look   at the headers, we see that it is powered by  Express. So as I said, In the beginning, an S   Gs use Express under the hood, you can replace  this by another framework called fast Defy. But   for most use cases, you will probably use  Express, and that's going to be just fine.   That also means that everything that you know  about Express, you can access it. So this is the   nice thing about NES GS, if you like Express  Gs, and you need more structure in your app,   you can use NES Gs, and still have access to that  express ecosystem if you need. One other thing   that is very interesting is that Express has  sent us a content type of text HTML, right? So   this is a text. So NES GS will automatically  convert the data type based on the return. So   here, it's a string, if I send a object,  for instance, message, hi, or Hello.   And we send it to sign up. We now have a object  and the header is application that Jason So that's   a very handy, you don't need to worry about  sending the right data type, ness, GS will   do it for you. Let's go back to our app. And let's  create more logic. So as I said, In the beginning,   the controllers will handle the requests. So it  will fetch the body of the request if needed.   It might check some headers or any work related  to the request. Regarding the business logic, the   actual execution, we offload that to the service.  Usually the pattern is that we are going to create   the same function on the service side. So let's  go ahead and do it. We have a function now sign up   and sign in. Right? And instead  of returning something from here,   we can actually call the service and  we can put that message here. Sign up.   Hello. And that's right. I have signed up.  And here I have signed in right there things   correct and let's call those functions from the  service, these odd service that sign up and this   out service that sign in. So what it does is  that it allows to keep our controller clean,   and only busy with a logic with to the requests,  while our while our service will be busy with the   business logic like connecting to the database,  editing the fields, etc. So let's go ahead here   and do it again. And we see that it works as well.  And if we launch sign in here, it also works.   Now we know how a controller works, we know  that it is responsible for handling requests.   We know how a service works or a provider, it  is responsible for handling the business logic.   But what would be a business logic without  connecting to the database, right. So we need   to somehow set up a database and connect to it.  And by that time, I guess you have noticed it,   my style of teaching is to introduce concepts  bit by bit. So now we need the database.   Let's go ahead and set up a database.  For that we are going to use Docker,   Docker is an amazing tool that will allow us  to run our database directly on our computer,   but so we don't have to install it. So it will  run in a containerized environment I have Docker   already installed, you can go ahead and install  it. And one quick way to check if it works. You   just write docker ps and if it inputs something  that means that it's working, my version is   is version 20. With that being said, let's go  ahead and and create our database. So when I work   with databases, I prefer to use Docker Compose,  Docker compose will automatically allow me to   spawn the Docker containers and to destroy  them. So it's very handy. Let's go ahead and   create Docker hyphen, composite Yamo. So here's  the configuration of our Docker Compose, I use   version 3.8. In the services we define our Docker  container that we want to run is going to be dev   dB, this is just the name I give it to, to it. The  image I'm using is Postgres 13. So we are going   to use the relational database Postgres version 13  is going to be exported on the port 5334. So if we   connect to Postgres 5334 on our computer, we'll be  able to access it. And the environment variables   I'm going to use is the user who is going to be  Postgres, the password 123, as you have seen,   very secure, and the database name will be nest,  and it's going to be on the network Free Code Camp   that is defined here. That's about it. So to to  launch our database, we go back to our terminal,   we open a new one. And we do Docker compose up, we  choose the DB that we want to run. So it's dev dB,   the DB, and we will run it in background. So with  Duke and that's it. And we if we go to docker ps,   we see that we have a container now that is  running. And we can even access a lock if we want.   So Docker logs. And it's written that the  database system is ready to accept connection,   it has deployed, it has compiled everything is  running correctly. Cool. Let's go back to our app.   So we have the database running in Docker. But how  do we access that there are libraries like SQLite,   typo RAM mongoose, that allow you to  connect to the database. In this example,   I'm going to use a new IRM that I really love and  I have been using for over a year now. It's called   Prisma. So you can access the website on Prisma.  That IO, what Prisma is, in a nutshell, is that   it's kind of a query Query Builder, but it's so  easy to use. So basically, you define a model,   for instance, that will be a post with ID title  and all the fields that you want in a database.   And you can get them from your JavaScript code  or your TypeScript with that syntax. And we're   going to explore it straightaway. So with Prisma,  we are going to create the database connection   logic the database module in a way. So that  means that we need to create another module   since the database module will be able to use  to be used by auth module because you need to   login sign up. It should be used by bookmark  module and even by user module. So it's a new   feature of our app for Prisma. We need to have two  libraries installed. The first one is Prisma CLI,   it will allow us to create Our schema and  run migrations deploy the migrations into the   database. So it's more of a maintenance library.  And the other one is the Prisma. Client. So Prisma   has different clients, the one we're going to use  is for JavaScript. So let's install Prisma CLI   yarn add, and we're going to add it as a  development package Prisma and yarn add   Prisma client for the client. Okay, let's  clear that out. With that being installed,   we now have access to the Prisma. CLI. Let's run  it and px Prisma in it. And it's going to generate   several files for us. First of all, it generated  this dot env file for the environment variables.   And it just created a Postgres connection  string by default, that we're going to change   a bit later. And it also generated that Prisma  folder in the root directory. So what it has,   it just has its schema. And this is where we're  going to declare our models. See, when you use the   library like type or M, you will create entities  and you will place them inside your logic for   Prisma. There's only one place that you need to  handle your your models a bit like with Graph QL,   actually. So you would declare those structures  that will describe the shape of the data that   will be in your database right here, it says that  it's going to use the Prisma client GS library,   which we have installed, the provider will be  Postgres, but you can have any other library   Prisma supports my sequel, and even MongoDB.  And the URL is the URL of the connection to   the database. So it's going to grab it from  the first environment, a file that it finds.   So if you place one inside the prison folder,  it will grab this one. For that tutorial,   we're just going to leave it here in the global  root folder. And let's go ahead and create our   models. So the way to declare the models is just  to type model, and you name it was a singular   word. So if it's users, it's going to be user.  And if it's bookmark, it's going to be bookmark,   right. Model bookmark, bookmark. And what do  we have in our app, we have users and basically   bookmarks, right, so we only have two entities  in our app. So the user will have an ID field.   It's an integer, we need to  tell the Prisma that it's an ID.   And we need to set a default as auto increment.  Or that can be found in the Prisma documentation,   of course, and same goes for bookmark, we also  have to add the created Add Field. Otherwise, we   will not know when it has been created, it's going  to be a date time. And the default would be now   which means when the record is created in the  database, a default value of now means the time   at the creation is assigned to that variable. And  we also have to add updated add, I'd like to add   that as well. Date Time and prisoner has a special  command here updated. And we can copy that to the   bookmarks as well. Right. So for the user, what  we will have, well usually we store the email of   the user is going to be a string. And it's going  to store also the password, at least the hash of   the password, so we're going to put hash shrink.  By the way, if one of the fields needs to be   optional, you can just put the, so let's create  two optional fields. First name is going to be   an optional string and last name, optional string  as well, right, we also have a bookmark. So the   bookmark that we're going to save is going to  have a title is going to have a description,   which could be optional. And we are going to have  a link which will be also a string but will not   be optional, because when you set a bookmark to a  certain link, well, a link needs to be there. Here   we go. We have created our two models, we save  the file, and now you see auto formats it nicely.   Then we need to add the database connection  string to our to our database URL variable here.   So let's check it here. So the user is Postgres  password is 123. And the database name is nest. So   let's go ahead and change that. User is Postgres.  password is 123. The port is at 54345434.   The database is nest and scheme not public, we can  leave it out like that. So now when we run Prisma   commands, prisma will be able to access our local  database that is running here. docker ps. By the   way, if you have the Docker app installed, like  I have on Mac here, you can have, you can access   the dashboard for Docker and see your container in  action here, next year's API tutorial. And you can   even see the logs, right, so let's run our Prisma  command. So the way to do it is to run MPX Prisma.   And let's press help for good to get some help.  So we have several commands, all that is explained   into the Prisma documentation. Of course, it's  quite nice, by the way, you can check it out.   So we have several commands that will be useful  for us, we have the Generate, we have the migrate.   And we have the studio Studio will allow to create  a kind of a online client so we can explore our   database through the browser, we're going to see  that soon. But the one that we're interested at   that point is Prisma migrate devs, what it's going  to do is that it's going to read that schema,   and it's going to generate the migrations in that  folder. So let's go ahead and run that terminal,   clear MPX Prisma and migrate data and basically  says that we you have added tables, bookmarks   and users for those migrations to be applied,  we need to visit the database. And it's usually   common when you rise my when you run, migrate Dev  is only for development. If you need to push your   migration to production, there's another command  that will not delete the data. But for now,   we can just delete it. And we can press yes. And  it's going to ask us the name of the migration,   we can just say in it. Now we see that  it has generated a migrations folder.   And basically it just generated some  SQL. And when we run Prisma, migrate Dev,   it actually does two other things. First of  all, it pushes automatically, that schema,   that SQL to the database. So the database if we  go there, and we check the logs, here, we see that   there is some command that has been run insert  into public users created an email hash. So   Prisma has already pushed some migrations onto  the database. So the database has the tables,   the tables of users, and bookmarks. And one  other thing is that Prisma has also automatically   run the Generate command. So when you use Prisma,  migrate, Devon Prisma, also does and pm Prisma.   generator, and what generate does, and it's  actually a very good, cool thing is that it   takes your schema here. And it creates TypeScript  types for your schema. So it creates the user   interfaces or classes. And same for model, the  bookmark interfaces or classes. So you we can   directly use those fields in our code. So we  can go. And now we see that we have a user here,   the user and the bookmarks as well, that  are that are exportable as TypeScript types   from the Prisma client. So we can use those  types directly in our application, which is   awesome. They're just very awesome. We don't  need to code that by hand, we can use it   directly with Prisma. Right. So let's come back  to the schema and inspect our database with Prisma   studio. So Prisma gives us a very handy tool  called Prisma. Studio, we can execute it by typing   MPX Prisma. Studio, and it's going to connect  to the database at the URL in the end v file.   Here we go at Port 5555. We are now at the Prisma.  Client and we see that we have a user and a   bookmark models, right. And we can go here and  inspect our database, when we'll have some some   stuff there. And we can even add records if we  want. So it's totally compatible with the Prisma   schema. It's actually quite cool. Let's discard  the changes for now and come back to our code. We   can leave that running that a that Prisma studio  running, and we can come back to our code here. So   far, we have created the Prisma kinda migrations  folder, and we have created the Prisma schema.   But we don't have any way from our code to  actually connect to the database. And for that,   we're going to create a module to do it easily,  right? We're going to encapsulate all our logic   regarding the database in the module and only  export from the module, the stuff that we need to   be accessed by the application. Alright, let's go  ahead and create A module I'm going to generate,   I'm going to use the NES CLI, because I'll be  quite lazy here, module Prisma. And I'll just   call it the same name as, as this folder. But  it's, of course, two different things here,   this Prisma folder in the root, stores the schema  and migrations, while this one will be our module,   following the NES, GS modular structure,  right. So we will create an SG module Prisma.   And now it's here. And we  will also create the service,   we have created the service manually here,  let's go ahead and create the service   with the CLI. So instead of module, we have  Prisma, or sorry, we have service. And by default,   it is going to create the spec files. So the test  files, we don't want that here. So we say no spec.   And now we have the service that is  important, as provided in the module, right.   And in the service, we are going to create  our logic that connects to the database.   So the way I like to do it is that I like to have  the Prisma service extending the Prisma client.   And Prisma client is a class that allows to  connect basically to the database, right,   it has a constructor constructor, it has connect,  disconnect, and execute SQL and everything. So   what I'm what I want to do is I want to configure,  I want to instantiate it with its configuration,   so I need to constructor and I need to call super.  So super, will call the constructor of the class   I'm extending, and the constructor of Prisma  client needs to have data sources needs to have   DB and URL and the URL will point to that trink.  In the moment, we're going to see how to use   config variables, so dot n and everything in  SGS. But for now, let's just put that hard coded   into our Prisma. Service. Right. And I think that  from now, we're going to need a bit of more real   estate to run our scripts. So instead of running  every time, the terminal here, I'm going to kill   it actually prisoners to you as well. And I'm  going to run my scripts in a dedicated terminal.   Let me make it a bit bigger. So I'm going to  do yarn start demo. And I'm going to split it   and do yarn MPX Prisma. Studio. And this is item  two, of course, is nice terminal I use on Mac.   So if you have any questions regarding the  terminal, that's the that's the one. Let's go back   to our code. We have the prisoner service declared  here. And we had it imported into the modules. So   technically how it works in SGS. So let's say we  want our module to have access to the prisoner   module, because it's all modular, right? Well,  you could, you could do something like import   Prisma module, right. So let's see if  that works, or works. And normally,   you would have access to the providers that are  inside that module, right. So let's go ahead and   try it out. So in order to service that is part  of the auth module, and that has access to the   Prisma module now, because auth module imported  in auth service, we can use dependency injection,   to get reference to that service to Prisma service  from our auth service code. So constructor,   private Prisma. And we can just reference it by  Prisma. Service. Let's press save. And let's see   what we have, oh, we have an error. Well, why do  we have an error? It says that nest can resolve   dependencies of auth service, please make sure  that the argument Prisma service at index zero is   available. So what it does is that it says hey,  you're trying to import a a service here. And   I don't know what is that? I don't I don't have  access to that. And even though we have imported   the Prisma module from the in the art module, we  have not allowed the Prisma module to export it to   export the prisoner service to other providers. So  if we want to do that, we just need to do exports.   Prisma service, right. And now the error should  be resolved and we don't have we don't have any   errors. right now. So basically, that means that  if you have a module here, you will need to import   it in auth module to make it work. But that's a  bit tedious. Because we have our Prisma module   where the user will need to have access to  the database, the bookmark will need to have   access to the database. And if we add to other  modules, they will all need to have access to that   prison model. So do we need to really import  that every time like every time we need to   create an import and create a model. Now, what is  possible in in next year's is to create a global   module. So instead of importing it like that,  what we can do, we can go into Prisma module   and add another decorator called global. And  just by adding that and making sure that the   stuff that we want to be exported, it also  is also in the exports array, just by writing   that this prisoner service will be available to  all the modules in our app. And if we check our   logging, everything works correctly, just make  sure that your global module is also imported   into the app module into the root module. And in  fact, it is important here. Now we can freely go   and and do what we want. And here comes the  interesting part. Because this is where we   really start to write business logic. This is  where we really start to do programming and not   configuration. And if it was a bit tedious to set  all this up, well, if you do something like that   properly, with Express alone, it will take  you much more time. And you need to be really   good with architecture to be able to make  everything work flawlessly here we're in SGS,   we have everything working out of the box. And of  course, it takes a bit of time to get used to the   way of SGS. But in the long term is going  to save you so much time. And here we don't   actually need the object so we can delete it. The  injectable can accept other objects. But for now,   it's not important in the scope of this of this  tutorial. So without further ado, let's go ahead   and start writing our logic. So for this signup,  what do we need? The signup is the creation of   a user right, we need to create a user based  on something that we pass in the body usually,   so usually it's going to be as post route to all  sign up. We are going to save Send the body to   that route. And the body will contain the email  and the password and is going to receive something   back about something back we're going to discuss  more into details because we are going to touch to   authentication and especially DWT JSON web  tokens. We're going to talk about that a bit   later. Right now just let's focus on the process  between the request and what is happening in the   in the logic. So net GS has a lot of  decorators. So this is a decorator.   This is a decorator, right? It has a lot  of decorators that that have different   functionalities. Remember I said that under  the hood is express GS? Well, if you want,   you can access that express GS under the hood, all  you need to do is write a decorator called Rec.   And it comes from Nash yes common. And let's  call it Rec. And we give it the type of request,   which comes from Express actually, it's  going to be a bit careful about that,   where things come from. And if we now press  and if we now console log rec, we will see   that rec will have a lot of properties. And  those properties are actually coming from the   Express request object. So let's just log  it for for the loads and CO the odd sign up.   I have signed up amazing. Let's go back to our  logs here and we see that we have logged the   request object. And that request object is  basically the same as C Express request object.   And you can get stuff like Heather's like body,  etc. Right. So if we want to log the body,   it will be something like request body and then  if we want, we can pass that body to the signup   function. So let's go ahead and request body  and provide a body of course it's going to be   form URL encoded. Here we have an email and  a password let's send it over and let's log   that into the console and we see that the body  has been locked. Now usually how it will work   is that we will pass the request body inside our  function and of course here it complains because   it the sign up doesn't doesn't have any declared  parameters. But what happens if the email is not   defined if the password is too weak, or even,  there's no password? Well, this process of   validating, that is called the validation. And SGS  has a lot of tools for that to make it really easy   to do. But before even going to to that direction,  I want to point out that this method is not very   clean every time we need to get a request. And  then we don't have any, any information of what is   inside the body. And SGS uses DT O's data transfer  objects in a nutshell is just an object where you   push your data from, let's say a request. And you  can run validation on it if you want. And you can   even have the shape of those details because we  use TypeScript. So we can say that the body should   have an email, and it should have a password,  right? So let's go ahead and implement that when   working with NES GS, you should never really use  the request object of the underlying underlying   library. Because what if you switch to fast defy  what if you switch to another framework that they   might add in the future, you will use that kind  of independence that NES GS has, you will not   be able to reuse the same code pretty much. So  what we're going to do is that we're going to   use another decorators called body. And it just  allows us to get the body of the request, right,   let's call a DTO. And let's declare it as any,  because right now, we don't know the shape of it.   And let's console log that detail. And  I'm going to use the My Favorite logging   pattern. So basically, is just going to create  an object and put the DTO inside it. And that's   the shorthand for that. Let's go ahead and do  the request again. And you see that it also   works. So the advantage of using decorators like  that is that express will get the right body,   depending of the framework for you. So you don't  need to really worry where the body is express or   fast defy or any other framework. Message. Gs does  it for you, right. But here, it only brings us   half of the answer, because we don't know the  shape of it. So we need to create a interface   for that shape. Let's go ahead and create it. So  usually, I like to create a folder called DTO.   And inside the DTO, I use the Baron export  pattern. So I have an index.ts that is going   to export all the fields. So here we are going to  do what while it's going, let's call out.dto.ts.   And there's going to be interface called odd DTO,  it will have an email, which will be a string,   and it will have a password, which will  be a string, and we need to export that.   Right when to close that. And we're going to index  and we need to export that detail from the index.   And if you have never seen that  pattern, the Baron export pattern.   The main advantage is that  now I can just do odd DTO.   And it's going to import all the details from  that folder, instead of doing something like   odd detailed Ts. And if we have something else  like sign up the detail that is instead of doing   that is going to import everything from the same  folder, all the imports will basically be there   in those brackets instead of being spread out  in your in your code, right. So that's a nice   pattern that I love using it brings a bit of  more code. But honestly, it's worth it. It   makes your code much readable. And now we have  access to this parameters, email and a password   in the DTO. Right. And let's let's clean it a bit.  Delete the requests. Recall, let's try it again.   And it works again. But here, it's only  TypeScript. So what if we don't pass   the email? What if we, we forget to  pass the value to the email? Well,   if we log that, we don't have any errors, we, we  have email that is void and we have a password.   So that's a problem because now we need  to write codes like that if DTO dot email,   if not then throw error and is this is very  verbose. We can simplify that a bit by using the   class transformer and class validator libraries.  So let's go ahead and implement them. And just   before we implement them, let me introduce pipes.  What are pipes in SGS pipes are just a function   that transform your data. So if you have a string  that comes from the request, because usually apart   from if you send the JSON If you send a string  in the in the in a query something like sign up,   for instance, user ID is equal one or user one,  that one will be a string. And if in your code,   you need to use a number, that could be a  problem. So one way of doing that is to use   the built in types. So what we can do is that  we say email is going to be a string. And we   can isolate the email field directly from the  body like that. And the password would, will be,   will be created like that, right. And let's,   let's log goals email password. And for some  reason, my pitch here is not working. See   this line is a bit big. So I'm going to go into  preach here, and reduce a bit the, the print with   and you try that out. Okay, 50 works  well. And let's also look the type of type   of email, which will type of email. And same for  type of password, type of password. So again,   I go here, and we say that the email is a string,  the password is a string. So what if we want to   transform the password into a number? Well,  it could be done simply like that by using   inline pipes, parse int, type, and there are other  pipes. But usually, it's the this one that you're   going to use. And here, since it's not a number,  the password will throw an error. So it's going   to stop the execution of our code. And if you  check here, there is no console log is going to   stop the execution of our code before even we run  the business logics. So this is amazing. But if   the password is a number, well, it's going to have  is going to work right now. And we see that here,   the password has been converted by the pipe to the  number, obviously, this process is a bit verbose   because you need to create a pipe for every  data field, what we can do visit DTO is just   is just apply those transformation and  validation directly on the on the detail.   Right. So let's go ahead and continue what we're  doing with that small explanation about what are   pipes. But I think it's quite important  to understand the pipes before we move   into the detail of validation. So there's more  explanations about pipes in on the NES GS website.   And you see that we have different types, both  pipe float pipe, uu ID, which stands for unique,   unique identifier, but there's something  called Class validator. So basically,   this is what we need, we need to install  those two packages, class validator and class   transformer. So let's go ahead and add them.  Yarn Add Class validator and class transformer.   Here we go. And now what we can do is that  we can go into the DT O. And to apply the   transformation and the validations, we need  to use a class not an interface. Basically,   it is the same for us, it doesn't change anything,  it just that instead of interface, it's a class.   And we need to add something here is email,  for instance, from the class validator   package, and is not empty. And is going  to be and this is going to be a string.   And it's going to be erased, not empty. And let's  go ahead and throw the request again. And we see   that it does not work right. Why doesn't it work?  Well simply because we don't tell nest yes to use   the pipe logic to use the validation pipe globally  everywhere. So we need to go into the main Ts. And   just before the abduct, listen, write app, use  Global pipes. And here we just write validation   type. And validation pipe is a built in pipe by  NSCs for that same purpose, right? And we need   to instantiate it like that new validation pipe.  So now that we have added that validation pipe,   let's go back to the insomnia and run the request.  And here we see that we have two errors. The first   one is email should not be empty an email must be  an email, right? So that's cool. So if we provide   something like test, well, it's still going  to complain that it must be an email. So flat,   Gmail dot Come. And now everything works. This  is validation in a nutshell. Thanks to DT O's,   the validation pipe can do other stuff such as  transform automatically your data. One thing that   could be interesting for you guys is to see that  use case. So if I'm going to my controller, and   I'm going to console log, the DTO. Right. And if  I'm going to execute that logic, we log that. But   what if I try to cheat? What if I have identified  a maybe a vulnerability in your server and I want   to inject a variable, for instance, ID is equal  one. Or any other variable? Well, if I console   log, that ID will be passed to our DTO. And maybe  that's not something that we want, right? One of   the things that the pipe validator can do is that  it can strip out the fields that you don't need,   what we can do is just set whiteleys to true, and  it's going to do, right, we send the same request.   And now we see that the ID is not here, what it  is doing is that it's stripping out the elements   that are not defined into our DTO. So now we can  be sure that rd to has an email and a password,   and know all the fields that we  have defined. So this is amazing.   Let's go back to our controller now. And  write the rest of our logic. Now we know   that the DTO is validated, and it has an email and  a password. Let's pass it to the signup function.   To make it all clear. Clean that and let's open  the audit service. And in the audit service, here,   the signup function will receive a detail of the  deal, right. And now we can run our business logic   with self assurance that the data that we  receive from the client from the browser is   actually correct. So the first thing that we're  going to do is that we need to generate a hash   based on the password, I like to use Arcanum. So  a lot of people use B crypt for password hashing.   And that's a fine solution. But I also had the  refresh token in my in my application. And there's   a problem with B crypt because its verification  algorithm is only limited to the first 72 bytes   are going is considered to be a better solution  overall. So I'm going to go ahead and use argon.   For that we need to install argon, two.  And we can import it into our oath service.   So all as argon from argon two. And the first  thing is that we need to generate the password.   Then save the new user in the DB, right. And we  need to return the user, the saved user. We're   going to do those three things first. So let's  generate the password hash is SQL Argan. Hash. The   first will come the plain text that we want our  hash. So it's going to be detailed or password.   And that's it. Then we're going to say the user  in the database. So const user is equal await. And   it will be in a sync function, of course, because  it's called Prisma. A synchronously this prisoner   user. And since we have defined  user in our prisoner model, create   data. And this is the data word that we're  going to use to create the the user with.   And what we have here we have email, which can be  detailed email, and we have hash, which will be   that hash. Right, we can save it. And it's  not happy because it says promise string is   not assignable to type string, and of course, are  going to hash is in a sync function. So our wait   and the user is created. And then the user is  created. We just returned to the user. Let's go   ahead and, and create our user. So we can go back  to insomnia and delete that ID and create a user.   And our user has been created. Obviously,  we see that we have returned a hash,   which you should not return because that's  basically the hash password of the user.   Not very secure. And let's let's try it  out again. So we go to Prisma studio.   We gonna reload, and we see that the user has  appeared here, we can delete it, delete record,   here we go. And go back to our code and just say  that, listen, I don't want to return the hash.   Well, how do I do it with Prisma? Prisma has a lot  of possibilities. Either you, you create a select,   and you select only the fields that you want.  For instance, if we want only the ID, we say   Id true email true. And, for instance, created  add to true. So it will only return those fields   like that. And let's go ahead and delete that. But  obviously, it's not very handy, because there's a   lot of logic to, to write, right. So what I prefer  to do is to write transformers. So we're going to   cover that topic a bit later. But for now, an easy  and dirty solution will be to do delete user hash,   there is going to just strip out the hash  out of that user object and return that.   So let's go ahead and create one. And we have the  user object without the hash. Amazing, right? So   one other thing that will be interesting, what  happens if that I, if I send the user again, well,   if I do it, again, it's going to be created again,  and another user and another user. That's because   email field is not set as unique in the prisoner.  So let's go ahead and run the migrations to   set it unique. And we can delete that. Otherwise,  we'll have some problems. And let's go ahead   and get back to the Prisma model. And this is how  migrations of Prisma works. So those migrations   have created, the bookmark and the user. Now  we're going to modify our model. And to make   it all compatible with our database. So we can  simply include the new updates to our database,   well we need to do is we need to modify our  schema. So for instance, email should be unique.   We might want to rename the the table user  to users, because right now it is great user   is good for Prisma, because Prisma  Prisma loves those kinds of things.   But we're going to just map these names  to another name. So map users, and map.   book marks, everything seems to be correct.  Amazing. One thing that we might add as well   is the relation between bookmarks and user. So  bookmarks will belong to the user. The way to   do it with Prisma is to create a link to the user  in the bookmark because many to one connection, so   many Bookmarks can belong to one to the same user.  In other words, this user can have many bookmarks,   but any given bookmark at any given time belongs  only to one user and not to several users, so many   to one, let's create a user ID variable is shall  be an int. And user, it shall refer to the user   model, we need to tell it it's a relationship is  going to use fields. So we use fields to indicate   a prisoner which fields are used for primary  keys. And we use reference to indicate to Prisma   to which variable this primary key references  to so it's going to be to the ID, which is an   integer, or fuser. So we just name ID, right.  Amazing, right. So we have made some changes, and   Prisma automatically included an array bookmark  here, we just need to change it book marks.   And is going to be an array of bookmark module.  All good. So now we have made our changes,   we need to run the migrations, how to do it,  we come back to the terminal. And we do NPM   Prisma. Migrate, Deb is going to connect to the  database, enter the name for the new migrations.   Let's just name update models. It has run  the generate. So it has generates the new   variables in TypeScript for bookmarks and for user  ID. And it has made the email unique and it also   has pushed the new migrations here into the  database. And we might need to restart studio.   Sometimes it's a bit buggy  when you run the migrations,   and it works correctly. So now we have the user  and with the new fields, email should be I believe   it should be unique somewhere it should be ready  Unique. But anyway, we have bookmarks here. And   the bookmark has been updated with user ID and the  user object. So which is, which is really nice. So   go back to our code and write continue writing  our logic. So we go back to the audit service,   let's see if our logic against the duplicate  user works. So we create one user ID one,   because we have visited database. And if we  create the same user with the same email, again,   what we have is a five or not very cool, right?  Because 500 errors don't tell us anything about   what happened. It's better that we provide to the  user a kind of phase specified error saying, Look,   in that case, it is a forbidden exception, because  credentials is already taken, right? So we need to   create that error in SGS, it's actually quite  easy to do. And if you see here in in the logs,   we see that the there's an error with the  unique constraint failed on fields email.   So prismas tells us that email is unique,  and we cannot really use it. So what we can   do is that we can say, we can add try catch,  block. So we put all that into the try catch   error. Here, we can just isolate if the error  comes from Prisma or not. So if error instance   of prison Prisma known client request  error, and all that is detailed in the docs,   right? The only time where you would  write those detailed error exceptions,   is basically when you create a unique field with  unique properties. Basically, you don't need to   cache all the possible Prisma errors here, I  just want to make sure that if I'm catching the   Prisma, duplicate, unique duplicate error, so if  the error is is Prisma error, and not something   else is that happens if error dot code is  equal to p 202. Which stands for duplicate   field like Prisma has error codes defined and this  specific code stands for you try to create a new   record with the unique fields that has been  violated. So if that happens, we throw a naseous   exception, throw new, forbidden exception.  Credentials taken, right. And that new forbidden   exception actually comes from from SGS. It is well  documented in the docs, and is the error is not   does not come from the Prisma what we do is that  we just throw the error, right. And let's go back   to our insomnia send request. And here we see  that the status code is for free. And we have   a descriptive message error message telling  to the client, hey, the credentials are taken,   you cannot use that. Amazing, right. So we  have created the signup service function.   So let's go ahead and create the sign in. So  what happens when we sign in while the user   will provide the password and the email? The first  thing is that we need to find the user by email.   If user does not exist, throw exception,  then compare passwords. And if password   incorrect, we throw an exception. And if  everything goes well, we just send back the user.   Okay, so the sign in function will also receive  the same DTO as signup, we don't really have a   difference between the signing and signup process  in some application, they do in some application,   the signup object, the signup detail will be more  complex, but in our case, it's going to be the   same. So the first thing is to find the user. So  we go and find the user const user is equal await   this prisoner user find. So the way you can find  elements in Prisma either you find them by find   unique or find first. So if you want to find a  single element from the database using Prisma   you can either find it with unique or first  find first will allow you to get the element by   any field and find unique will allow you to get  the element by unique fields. So in our case,   either a ID or a fields with unique  property. So let's, let's use find unique.   Where email is DTO that email, right? So the first  thing that can happen is that someone tries to log   in with an email that does not exist in our  database. So to handle that use case, we're   going to create what's called a guard conditions.  So if not user, we're going to stop the code at   that point and throw an exception, throw new,  forbidden exception, credentials incorrect.   And if the user has been found, we can just  continue our logic and compare the passwords.   For the password comparison, we're going to use  the compare function of the argument. So for the   compare password, P W, mattress, physical await  Argan. Verify the first argument will be the   hash. So the hash password, it is in the user, of  course, so user dot hash. And the second argument   is the password in plain text, and it comes from  the detail DTO dot password here. And again,   we put a guard condition if not PW matches, if  password does not match, we fire an exception,   the same exception as above, here we go. And if  everything goes according to plan, we can send   back the user. And before sending back the user,  we can delete the hash field on the user object.   That looks good. Now before we go ahead and try  it out, let's create some handy scripts for us.   So first of all, let's just write a script that  will allow us to respond our database instead of   typing it manually here in the terminal. Let's  create a script in the package Jason. So we can   just run it and it will rebuild our container  for us. So our Postgres database. And the second   thing is that, let's also write a script that will  allow to apply those migrations to the database.   So let's start by the database. So let's, let's  call, let's call this clip D dB. Dev restarts.   So that means restart the database with Dev  development environment. So by definition,   we only are in development. But if you have a  project, and that has several environments, such   as testing environment, maybe staging or something  else, well, you can create several scripts with   that syntax. So for now, let's go ahead and first  try it out our script here. So Docker Compose.   So to remove a container, and here in our Docker  compose our container or service is called dev dB.   To remove it, we use RM. And let's go ahead  and see what what functionalities we have here.   So we have forced to, to remove them without  asking us for confirmation, we also have stopped   to try to stop the containers before  removing them, it could be nice,   it's a nicer way of stopping them instead of  just killing them. And we also had this v dash   v to remove the volumes attached to that  containers. And that's a good thing to do. So to   for our cleaning script is going to  be Docker Compose, remove dev DB as   f v. So let's go ahead and put that into  our maybe let's do something like that,   let's put our logic into several sub scripts.  So it's just easier to manage them the B dev RM,   right. And the same would be dB dev up.  But instead of removing is going to,   to push it to create it and with is going  to be done in background. And for the DB   dev restart script is going to do  yarn dB, the RM and yarn DB Dev.   Up. Let's try our our newly created script in our  terminal and see if everything works correctly.   Yarn DB dev restart. So we see that it runs  the first one and then it runs the second one.   So we had the Remove thing here. And we have  the creation of a new Docker container here.   And if we do docker ps, we see that we have  one created here for us The problem, though,   is that even though we have created the  database, it doesn't have migrations applied   to it. So it does not have tables of users and  bookmarks. So we also need to create a script   to automatically apply the migrations. So  remember, in the beginning, we have run the   command Prisma, migrate Dev, what is going to  do is that is going to generate a new migration   based on the current migrations. And we don't  really want to do that, what we want to do is that   we want to apply those existing migrations to to  the database. So that process is much more safer   than regenerating the whole migrations every time.  Additionally, when you do prism, migrate Dev,   it asks you for confirmation. And it asks you  for name of that migration, for instance, we have   in it here, and we have update models. So it's  very hard to automate. However, the other script   that Prisma has is called MPX, prisma. Actually,  let's go ahead and check the Migrate Doc's help.   And we have Maghreb data, that's the one that we  have used in the beginning to generate the initial   schema and to run the migrations. But if we  just need to apply the migrations to a database,   we can just run Prisma migrate, deploy. So let's  go ahead and create that script. So Prisma,   Devil deploy. So this is going  to deploy the migration to our   dev dB, which is here at that, at that at  that link. So in so Prisma, migrate, deploy,   right. So and what we're going to do is that  as soon as the database is up, we're going   to run that script as well. So it's going to also  deploy our current migrations to the database that   we're working with. And yarn Prisma dev dB, what  might happen as well is that if you have a slow   computer, the database might take a bit of time  to start. So it's usually nice to put this bit of   sleep here, I'll put sleep one second. So we are  sure that before trying to apply those migrations,   our database is running, and everything is  set up correctly. So we don't try to apply   the migrations on a database that is in Bootstrap  mode. So let's go ahead and try that out. Again,   yarn DB restart, is killing the database. It's  restarting it is waiting a bit, and it applies the   migrations here. And we we see that it's written  that we have, we have found two migrations, and   the following migrations have been applied here.  Amazing. Now we can go ahead and start our server.   And thanks to TypeScript, we  now know that we have an error   amazing, we don't need to run the script  at runtime to notice that we have an error,   we have it here even before starting the server.  So we have what we have in the OD controller,   you have not given a DTO while in the service,  you require the to, let's change that.   So in the surface, the sign in function, it  requires the DTO while in the controller, you   don't pass it. So let's copy the body here, the  body logic and pass it to to the sign in function.   That should resolve the issue. Amazing. Now we can  come back to insomnia. By the way, I noticed how   to make the font bigger. And I just didn't think  about it. But yeah, basically, there's an option   in the in the in the journal options where you can  resize the font. So sorry, for the smaller fonts   in the beginning, I'm learning as well. Let's go  ahead then and do the signup requests. So there's   Senate and we had the user, if we try it again, we  receive an error. And if we do sign in and provide   the same credentials, we have the user again, if  we do a mistake with a password, we have an error,   which is nice. And if we do a mistake with  the email, we have an error as well. Amazing.   We basically have implemented the sign in function  and everything works correctly. One thing though,   in the real applications, when you sign  in, of course, this information can be sent   to the browser. So it can it can, for instance,  render information about the user. But it is not   enough to help the API to help the server to  actually identify the user connecting to it,   we see that in our case, we send the email and the  password. And it's called Basic Authentication.   But we cannot do that every time. Right? So there  are some API's where you need to send the email   and the password. And basically anything required  by the basic authentication at every API request,   encoded, maybe in the base 64 format. That might  be a bit technical, but that exists. But in our   case, for the user experience, we want the  user to login only once in a while, right.   So to allow the server to track the user to  know who the user is, there are two techniques.   The first is sessions, you probably have heard  about them already. And the second one is G wt,   Jason Web Tokens. And that's another way of, of  tracking the user on the website. So know who   the user is and allow or forbid, requests based  on user identity. Because if the user sends that   back, it's not enough, of course, anyone can fake  that. This whole process is called authentication,   and authorization, right? So we identify the  user. So the user provides some credentials.   We know who that is, we identify then the user,  but then we need to give something to the user.   So we can authorize that user through subsequent  requests, for instance, login, signup,   everyone can call that route, right. But there  might be something private, for instance, user,   slash me, and that only attentive FIDE users can  call it. So let's go ahead and implement that   functionality. I said before, we are going to use  DWT, for that we have already prepared modules for   NES GS. Now. So far, we only have seen custom  made modules. So it's module that we have made   ourselves. But Ness, GS also has modules that  you can use in your app, like any NPM library,   so let's go ahead and implement some of them.  The first module that we're going to implement is   the Config Module. So for now, we have used hard  coded environment variables. So this database URL,   we have actually hard coded in Prisma, right. So  instead of doing something like that, which is   not secure at all, because that will be available  in your GitHub repository. And also, it is error   prone, because what happens if you do an error  here, right, it's very hard to notice. And it can   be only detected at runtime efficiently. So that's  something that we're going to fix with the Config   Module. So let's go ahead and install it,  we can kill the server and install yarn, add   nest GS config. And we can start the server  back again. And let's go ahead and implement   that Config Module. So the Config Module is  usually implemented on the root module. So here,   or you can put it in a in a custom module and  implemented there, if you need to use something   like validation on that. So for instance, you can  check that, oh, this variable should be a string,   this variable should be a number, this can  also be checked. But it's out of the scope   of this project. So let's just leave it out. But  know that you can actually put the Config Module   inside a custom module called config if you want.  But for now, we're going to just import it here.   We have just installed the Config Module, let's  go ahead and implement that Config Module. And,   and you see it comes from Nash TS config, I  actually like to move all the node modules   packages on top. Now Config Module requires some  configuration. And if we add it requires a four   route option. And that's all we need to do  to load that dot n file into our application.   Under the hood. The Config Module uses dot and for  library, I actually have a nice video about dot n   on my channel. So if you are curious how it works,  check it out. Like any module that we have here,   it also have a service and also uses dependency  injection. So we can import that Config   Service inside any of our modules of our  app. So where do we need it? Well, at first,   we're going to need it in Prisma. So let's go  ahead and use it in prisoner to use dependency   injection. Don't forget to annotate a class with  the injectable decorator. So if it has injectable   that would be able to use dependency injection.  You don't need to put inject inject trouble if you   don't have any dependency injection requirements.  So if you don't use something like Prisma Prisma   service, for instance, if you use that Ness, GS  will complain somewhere, for instance, prisma.   User, find many, if we do that it should complain,  because it's going to try to get that object and   that will be undefined. So it will not know what  the user is. And in fact, it says Cannot read   property of undefined, right. So for any class  in net, she has to use dependency injection.   And that class, of course, needs to be inside the  module, we need to annotate it with injectable.   decorator. So now it will work.   But of course, we don't want to use Prisma. That  was an example. What we want to use, however,   is the Config Module. So let's go ahead and name  it config Config Service. Config Service is a   service declared in the Config Module that we have  imported here, I'm just repeating it so you guys   can absorb the new, the new concept easier, right?  Repetition is key. And what I'm going to do here   is that this string, now, I'm not going to  hardcore it, I'm going to import it from the dot   and file. And the way the Config Module  exposes that dot and file contents, is by   having getters in on the config object. So  this has a config object, we can do config.   dot get. And we just named the the name of the  variable and database URL, let's put it in quotes,   clean that and fire it up. And now we have an  error saying basically that, okay, we know what   a Config Module is, but the Config Service is not  exposed. Well, that happens, because, by default,   all the modules are kinda contained. So this  Config Module would be only available in the app   module, but will not be available into the Prisma  module. So it's very similar to what we have here.   With a global, you can expose our Prisma  module to the whole app. Well, any NES GS   compatible module also have this functionality.  Of course, we cannot use the decorator   here. But inside this object, there's an option  called is global. So we can just enable it,   and that basically does the same thing. Let's  come back in now, it should work to make sure that   our prisoner Service is working correctly. With  config, we can go ahead and print the config.   And we see that we get the right   URL. So everything is working. And let's  test it out. Let's create a new user   have led to amazing the new user has been  created. And that proves that our logic works.   Now let's come back to the GW T, the subject of  authentication seems to be quite easy, right? Like   how hard can it be just login and sign up? Come  on, every website has that. But in fact, under   the hood, it's very, very complex. And there are  companies, multi million multi billion companies,   if I'm not mistaken, making hundreds of millions  of revenues per year, providing that service   to corporate and, and and companies. So that's a  quite edgy subject to get right is also very hard.   So in this example, I'm going to  provide a very simplified functionality,   very simplified authentication. If you need to  get more information about that. I have a two   hours video on that subject alone on my YouTube  channel. It's about net CFG WT authentication.   If you're interested, check it out. But without  further ado, let's get started and dive in and   try to add authentication to our CRUD app. Now SGS  has some decent documentation on authentication   and authorization. And behind the hood, it uses  passport passport is a authentication framework   for Express GS with a lot of strategies. So you  can log in with Facebook login with Google auth   zero Twitter govt and has a lot of functionality  that you can use in our app. In our example we are   just going to use G wt. So basically the user will  give the email password pair, and it will receive   a G wt, what is it readable T, I have a video on  that on my channel, but basically is just a string   with a signature, some data and some description  about the kind of string it is and which algorithm   it is using. And basically inside it to say,  Jason that is encoded in base 64. And this is   the information that the server could pass to  to the client. So for instance, in our case,   we could pass that the sub which refers to the  ID will be a an ID or the user. The name could be   Vladimir, in my case, and the email could be  Vlad G Gmail. com, and you can add as many   claims as you want, though, all those fields  are called claims. There see expiration,   you can put an expiration we can put a creation  date. Basically, you can put any data you want.   And you pass that the server creates that  when the user logs in or signs up, and it   passes it back to the browser. So every time  the browser goes somewhere on the application,   it sends it over to the server and the server says  okay, yes or no you have access to that or not.   This behavior is quite similar to sessions, except  that sessions are being passed automatically,   with each request while govt needs to be passed,  basically with code, but apart from that,   they solve pretty much the same problems,  or at least people use them to solve the   same problems. Of course, some might argue  that G diabetes are bad for authentication,   but I don't necessarily subscribe to that point of  view. If people are using DWT for authentication,   we should at least show them how to do it  correctly. So let's go ahead and install   the needed packages, we need to install quite  some packages if you have any problems with   following the steps. Of course, all the code  will be uploaded on GitHub in the description   below this video. But without further ado, let's  let's proceed and install all the needed packages.   So what we need to have we need to have  Ness GS passport module, we need to have   passport and passport to local we don't need  passport local is a library to handle local   authentication. So we don't need passport local  nor do we need the types we only need passport and   NES GS passport. This is basically the passport  library. And this is the porting to net GS kind   of a, a module for Nash Yes, for passport. So we  need to install those two. Let's kill it and yarn   add those. We also need to install g WT specific  libraries. So here NES GS govt model, and pass for   govt package of passport. So it's a bit a lot of  libraries to install. But don't worry, just follow   the steps everything is going to be okay. And we  also need to install the types for those paths for   G WT thing because no library and they don't have  TypeScript inside the repository, it's in another   repository. And we are going to save it as a  development dependency. Here we go yarn, add D   for development dependency in types password TWG.  Now we will have all those added here somewhere.   Right. And let's see how we can use them in  our application. First of all, everything   regarding authentication, of course goes  into authentication module. And that's   nice thing because everything will be organized  and clean in our project. The first thing   that we need to import is the G WT module. So  remember what we have installed. This NES GSG   WT is basically used to sign in the code tokens.  This under the hood uses JSON Web Tokens library   so it just kind of a niche yes modularization  of that library, while the other one in the   beginning that uses passport. This is a true kind  of module that pours passport to to the next GS.   So the reason why I'm saying that is that this we  are going to use it in our service while the other   library, we are going to kind of put it in  another folder called strategy because the   first time you see that kind of pattern, it's  a bit weird. So we're going to import it here,   G WT module. So this is to sign in decode the the  JSON Web Token and we just need To register it.   And there are several ways to do it, you can  provide some the secret because the DWT needs   to sign with a secret, you can provide it here,  an expiration date and stuff like that. I usually   like to leave it blank, because in most of  the use cases, here, we're not going to use   a refresh token. But most of the time when  you deal with Govt, you also need to use a   refresh token. And the refresh token will have  a different secret and expiration date from the   from the access token, and more about those  in a minute. But that's why I kind of like to   declare the module here and customize it further  into the auth service provider. Right. So we   this is to sign in decode JSON web tokens. So  let's, let's do it. Now let's do it. First,   we go here. And since it's a module, because  everything in Nigeria are kind of modules. It   also has a what a service of course, well, we need  to import it again with dependency injection. And   this DWT models is registered inside this module.  So it will be accessible here. We don't need to   make it accessible there. And the use case of that  module is just to sign some tokens. So let's go   ahead and do it. We need to import it here as  the dependency injections of private govt G WT   service. Right. And this is imported from DWT  from the same package. And if you have any doubt,   you can also just check the package and see what's  what's there. There's a god service God module   and some interfaces. And I think it's actually a  good practice to always kind of inspect a bit the   the libraries that you use, it will allow  you to get a better understanding of what   what is inside instead of just blindly following  documentations and see things just appearing there   out of nowhere. So we have signup and sign in?  Well, we said that we don't need to return a user,   we actually need to return tokens. But to return  that we need to sign that information, though,   like this user information and transform  it into the token, obviously, like here,   so we need to generate something like that,  right? Based on for instance, data like email   and ID. So let's go ahead and create a function  for that. This is going to be signed token.   And I like to put it in a sink as well. And this  sign token will take the fields that we need to   sign, it's going to be user ID, which is going  to be a number and a email, which is going to   be a string, so we're going to send the user ID  and an email. So later on, when he passes back,   something like that, we can get those two  information out to that token, and run validations   or assume that all this is the user ID one. So  whatever action that he does on our platform check   first is that he has authorization to pass  that specific action and then perform that   action. So this is the kind of information  that we're going to extract from the govt   and kind of trust what's inside. So we're going  to construct an object that we're going to sign,   let's call it data user. Let's code  sub user ID sub is just a standard of   of the GW T's kind of convention that that  you need to use a unique identifier for   a sub field. And let's add any field that we  want for in our case is going to be an email.   And what we're going to do is that we're going  to return this G WT sign and all those functions   come from Jason Web Token library that you  can find on NPM if you need sign a sync.   And the first thing is going  to be a payload and the second,   the second argument is going to be a options for  the signature. And this is where we can set our   secret secret information that we're going to sign  the data with. So only us know that information.   So if a user comes back with a token ad with  token, we know that it comes from us because   we have signed it with our secret password. And  actually, we can name it payload because it's   going to be more descriptive payload. And the  second option will be an object. First of all we   want to set when the token will be expiring.  So let's set it at fixed 15 minutes. 15 m   So that means that once we give that token to the  user, the user can do some actions on our platform   for 15 minutes after that, the token will be  rejected and the user needs to sign in again. And   we also want to add the secret, of course, secret  is mandatory. Otherwise, we can't really sign   up for the secret. Since it's a secret, we should  definitely not commit it to GitHub, let's put it   into the MV file as well, as called GBTC. Correct.  And let's name it whatever like super secret.   And let's copy that and use the same  process that we have using to Prisma   Prisma service, let's import the  Config Module, private config,   sorry, Config Service. And let's get that the  GW t here. Cons secretly SQL these config get   govt secret. Here we go. And since we're  using TypeScript, we can actually provide some   interesting function descriptions, like the  return type is going to return a string.   Right. And here. And for signing, for  instance, instead of returning the user,   what we do is that we return this sign  token user.id and user dot email. Perfect.   Since we return in a synchronous function, we  don't need to put a sink here. This is only useful   if we do some asynchronous operations, when with  await here, since we're returning the promise,   we don't need to put it here. The code will know  that it's a promise. And same thing happens here.   And we don't even need to do it, the user here,  we can clean that out. And let's also return   the user here. Awesome. Let's get back to our  insomnia, and pass the URL request. So now if   we do sign in, is going to return us. Of  course, we forgot to start the server.   Silly me. The server is running no  errors, let's do the request again.   And now we have a text, which is not  very nice, though I didn't really want   a text. But it gets us the the JSON web  token. And by the way, if we copy that,   and paste it here into govt.io website, we see  that we have the sub, which has the user ID   and our email. So this information that we have  signed is correctly included into the body. Now   into the next part, one thing that we might want  to add is that instead of returning a string,   because here is going to return a string. And of  course, next js is going to convert the headers to   text HTML, I'd like to return a object. So instead  of doing that, we can just change the logic a bit.   Here in our sign token, we can  return an object with access token,   I have noticed that usually, the  convention for access token is to   have this snake case convention. And we can just  return the access token here. Like that. And of   course, is going to complain because our type now  is incorrect. Our type is promise string. So it   should be promise of object access token, which  is a string. Now everything is working correctly,   and we execute the sign in again, we get a object  with the access token key. Amazing. Now on to the   next part, the strategy part, we have generated a  access token. And basically token a user can use   to pass requests, protected requests to our  application, the next step is to actually write   the logic that will be able to intercept that  token. So that token that we the user passes to us   validated, make sure that it didn't expire and  make sure that the signature was which we created,   the token is correct. And then only allow  the actions that the user wants to do   on our platform. So to summarize, we have written  the logic that allows us to create a token, right?   It returns a access token to the user.  Then what would happen? Well, the user   will call another route, for instance,  users slash me to get information about   the current user and He would provide in the  headers authorization token, something like   that bearer space. And that would be the access  token. So the logic that will verify that this   bearer token is correct is called a strategy.  And this is what we're going to implement now.   For that we create a folder in our module  called strategy. We'll create a baron expert.   And we'll create the strategy which is  basically just a class strategy, the Ts, the   strategy, the G, the Ts, export class, G  devotee strategy. We have an example in the NES   she has documentations. Let's check it out. Here.  The strategy should extend the passport strategy,   which comes from the NES GS passport module. And  it implements the G WT strategy, which comes from   this passport, DWT library. And what it does  is that it configures it in the constructor   calling super. So it calls this module this  service. It says that the govt should be extracted   from the headers as a bearer token. So it just  means that it should be it should have this kind   of format bearer space token, which is a standard  for a bearer token. This property is set to false   by default. So we don't need to set it to false.  It just allows us to ignore the expiration date   of the access token which can be useful when  you were testing but we don't need it at that   point. And it takes the secret key as a as  a parameter. And the secret is basically   this thing that we have defined here, we  have signed our token with a specific secret.   Well, we need to allow the strategy to decode that  same token with that kind of secret, not really to   the code, but more to verify that the signature of  the token has been really signed by that secret.   So we know that the token comes from this server  from our API. So let's go ahead and implement it.   The jeido which is strategy should extend passport  strategy that comes from Ness GS module passport,   and it should take the strategy that  come from passper jadibooti. Right.   And it has a constructor because we are extending  a class we need to call its its constructor,   the constructor of the parent class like that.  And we need to provide the configuration of   that of that password strategy class. So we  can just go ahead and copy what is there.   And delete that. Because it's false by default,  and import extract g, oo, t and x. And this is   basically the secret, right? So this class is  also a provider like the auth service class,   right, so it can use injectable. The reason  why we separate it in a different folder is   just to make sure that we don't we know  that this class has a specific use case.   And it's for validating the D token, the access  token. So that's why it's inside a folder. But   it can also use dependency injection under the  hood. So that means that it can inject Prisma   inject Djibouti and inject the config and this  is what we need because we need to get that   that secret from the environment variable  so let's go ahead and do it injectable   and here is going to be config Config  Service. config dot get and it's going to be   I think we call the govt secret everytime I forget  how we call things. G WT secret. Amazing. Now, now   everything's okay. The only thing that we need to  do is that we need to export that class from our   Baron export, which is a good pattern. And we  then need to import that strategy as a provider.   So NES GS is aware of that of the strategy being  part of our application. So G to bootstrap the G.   And that's all we need. Let's go ahead and start  the server. Nice. Everything seems to be correctly   instantiated, and we now have the DWT  strategy configured. Now we can protect   some of our routes with that strategy. That means  that you can access a route only if you have the   valid strategy here we are using CWT but if you  want you can also have strategies like login with   Facebook login with Google. And they have their  own configuration options and stuff like that.   So again, we generate the token with the auth  service. And then we have a strategy that we can   decorate other routes with. So only  people with a valid token can access   it. But we don't have any other routes, any other  controllers are part of the odd controllers. So   let's go ahead and create one in the user module,  I'm going to use the CLI nest G controller user.   I would name my controller users based on  the REST API format. And let's go ahead and   implement a simple get endpoint is going to be get  me if you leave get decorator blank, it will, it   will catch any any requests. So it will catch any  requests like that. If you put something there,   it will actually catch it with that pattern.  So if you leave it blank, it will just use   the pattern of the controller to catch it.  Obviously, if the controller has nothing,   it will try to catch it at root, which is not  a very good idea because it can have conflicts   and undesired behavior. But in this case,  we are going to use me. So we are going to   call that endpoint with users slash me. And in me,  we are going to return something return user info.   It's just a drink, right? Right now we are not  doing anything. And if we go back to insomnia,   and CO users me, and let's actually delete that,  and it's not the post request, it's a get request   is going to return us user info because we have  just mapped that route on to our application,   but we haven't protected it right. So there  see. So to protect a endpoint to kind of have a   condition that will say, Okay, if you meet certain  conditions, we are going to execute that, that   logic, else, we are not going to execute that. To  do that in Ness. Yes, we use what we call guards.   And again, you can use the nest GS documentation  to read about guards. A guard is basically   a function that will stand in front of a route  handler. So in front of a endpoint, and to allow   or not allow the execution of that endpoint. In  our case, our guard will check for the strategy.   And if the strategy digital which strategy is  correct, is going to allow the execution of the   route if not, is going to block it, you can of  course, create custom guards. But in our case,   we can use something that has already been  pre made. And that comes from the NES GS   passport module. And it's not called. So to use  guards on a given route or on a given controller,   you can use pretty much everything at a global  level at the controller level, or you can use   it at the route level. So in our case, we want to  block the GET ME route if you don't have a valid   token. So let's go ahead and create that we  need to use a decorator called Youth guards.   And in the youth guards, we can  provide the guard that we want to use.   And Neji has passport, the module that  we have here somewhere, actually here.   NES GS passport, it already has a guard  for to work with that strategy, right? So   if we inspect the code here, we see that will  do what does it have? It has a note card,   it has some interfaces. It has passport  module, but this is what we are interested in.   It's not guard and basically. So it's  basically a guard that is compatible with   Nash's that we can use. And that works very  well with the strategy. So let's come back.   Let's go back to the user controller and import  it here into the youth guard. decorator. So old   guard. And here in the parenthesis we provide what  kind of guard it is what kind of strategy it is   guarding for. So it's G W team. And when we create  our strategy with with that was that strategy with   that strategy object that comes from passport,  Govt it by default assigns DG WT kind of key to   it so so you can assign any key that you want. For  us, for instance, GT 32 But by default, it just   leaves it like that. So it will be identified  by the odd guy with that keyword. So if you   have a refresh token, you can do something like  that. You can name it really the way you want,   you can give it any name that you want. But by  default is G wt, you can leave it blank, or you   can leave it here Djibouti, I will prefer to leave  it like that, because it's going to be clear, is   going to be a bit less of magic, because the first  time I encountered the old guard, I was wondering,   how does it know that this job jadibooti is  linked to that strategy. And that's how, so   we are going to say that, Oh, this route should  be protected by that strategy. Now, let's go into   insomnia and try to use the same request again.  And see we have a 401 status unauthorized? Well,   it's because the strategy is being executed. And  it does not receive the bearer token. So it throws   an error. So let's recreate a bit the flow, I  cleaned up the database, I have now three routes,   get me route, a signup and sign in route. So let's  go ahead and sign up and create the body email if   lad@gmail.com passport, sorry, password 123. And  this create the account, we have an access token,   that access token, we can use it in our bearer  tokens. So if we, if we throw the request in   right now if we use a request, right now,  we're going to get a 401. Because we haven't   required any we haven't given any bearer token.  Let's go ahead and implemented authorization.   Bearer. And then we paste the token. And now  we have another error, which was interesting.   Let's see what is going on. This validate is  not a function, okay, we forgot one function   in the in the GW strategy, and it's validly  date. So let's go ahead and write it.   And it's going to take a payload  of any, let's log that payload.   Cool. One important thing that we forgot  to implement is that we forgot to have   valid function. So the token is going to be  transformed into that object and put into payload.   And then we need to return it. So here we can  perform any validation that we want. And then   we can return the user. In our case, we're just  returning the Jason. So what it's going to do   by returning the payload is going to append the  payload to the user object of the request object.   It sounds a bit confusing, but under the hood  of Nigeria's, we use Express, right? And we can   get the request and the response of express with  the right decorators, which I have shown in the   in the beginning of the course, right? What the  WG strategy does, is going to attend that a user   object to the request object, so we can use it  in our route. So the user is going to be that   payload. So it's going to be that object with  the sub email expiration date, etc. But let's   get back to the strategy and just run it again.  It is passing correctly, right? So we have the   the console log the payload here, as I said,  it's an object with a sub of the user ID email,   our email and other information that was contained  in the token, right. So let's clean that.   And let's see, why is it useful for us?  Well, if we go back to the controller,   I said that the strategy will put that decoded  payload or whatever value we pass here, whatever   value we pass in, the validate function is going  to append it to the user object on the request   object of the request of the or the or  the API. So we can get that object here.   Request. Actually the Ric Rec. And Rec object  is from nest GS and request interface is from   Express. And we can do console log user is equal  to rich dot user. Record user. And you see that   even expressed now that a user is possible because  because when you validate the identity of a user,   its identity can be appended to the  request object. So here we are going to   log that is going to log the payload.  So the object that we have returned from   here. So if we run the requests, again, we'll come  back to the thing. And we see that we now log,   the same payload, but from the controller, because  we have written user here. So if we pass any other   value here, let's say hi,  Well, hi is going to be logged.   Here, because we basically attach whatever we  export from the validate function to the request   user object, right? Does that make sense? If that  doesn't make sense, don't worry about that, we are   going to build upon that concept. And I'm going to  come back to it a couple of times. So basically,   that means that we can get the information of  the GW T from the token and do something with   it. Since we have an ID, we can get a user by the  letter Z, since we have an email, we can maybe   get the user by that email, everything is  possible, we just know who that user is,   that requests the users me endpoint, let's  clean the strategy and return the payload,   we can close the strategy file and come back to  the user controller file. So what we're going to   do now is that we need to get the information of  the current user based on the access token, right.   So now we need to get information of the user and  return it back. So that can be done in several   ways. In that example, we are going to get the  user object from the database directly in the   validate function. So on top of having  config, we also need to inject Prisma   Prisma service and here we can get the the object  so it's not going to be any it's going to be,   it's going to have a subfield which  will be a number, and it's going to   have an email field, which will be a string,   validate will be in a sync function can get the  user const user is equal await the prisoner.   And I forgot to put private. The reason why  I don't put private in front of the context   is because if we do something  like that, I can't really   use this because super must be called before  anything. And since I'm not using config in my,   in the rest of my application, there's no point  to use private and remember when we use private is   just means that we declare the  variable here automatically, right?   So we don't need to do that I can leave it  without private and of course, it's going to be   config dot get. But here we can use private  because we use it elsewhere. So this prisoner   user, find a unique ID is going to be  where ID is equal payload dot sub. Also,   very important thing to notice is we if we  return Nope, it's going to throw an error.   Right? So the user will be now if the user  will be not found. And a 401 error will be   returned. And if the user will be found, that user  object is going to be appended to the user request   object on the request. And the thing that we  can do before doing so is to delete the hash. So   we don't inadvertently export some sensitive  information, and then we return the user. And   in our user controller, what we can do  is that we can return a rack dot user.   Now if we run the requests user, slash me,  we're going to get back the user based on the   access token. And now we have our application  working, we can sign in, sign up and get the   information of the user. So that's quite cool. But  there are a couple of things that we can enhance,   before I told you should not use the request  object immediately because it is error prone.   And this is correct. So we can fix that.  And we also can make that a bit more   clean. So this is easier to do. So let's start  with that. Every time that you need to put   a string somewhere. It's called the magic drink.  It can create errors, and we can make that cleaner   by abstracting it in its own class. So let's  go ahead and do that. This functionality will   be part of the odd. So let's go ahead  and create a guard, a custom guard. So   new father guard, and again, the Baron export  here, and we are going to create the duty   guard.ts. And what is going to do is going to   just be a class jadibooti guard. And all we  need to do is to extend the old guard. And   we are extending a guard with GE WT strategy. And  that's pretty much it, we might just run the super   and, and we need to export that class so we  can use it in our application. So instead of   writing out guard, like that, with those strings,  we can just write that class. And let's export it   and import it in our user controller.   jadibooti guard. And if we run, if we check  the runtime it is executing correctly. And we   can even get the information correctly. Oh 401.  Unauthorized and we can we can. So so this is   similar to what will happen in our application, we  get a access token for a specific amount of time.   And once it is expired, you cannot use the  protected route anymore. So we need to get a   new one. So let's go ahead and create a request  email flat ARCHIE MILLER comm and pass word   123 We get the new access token. And then we come  back to the to the header here and replace it with   a new one. And if we send the request, it works  correctly. So now we have fixed that. And let's   go ahead and fix this. This is a decorator.  So you know, all those things are decorators,   we have made a custom guard that extends the  auth guard provided by naturally as passport.   But we can also make a custom decorator that will  go in the request object and get that user object   and return it back to us. So now we can go in the  old folder because it's kind of part of the OT,   ot functionality, right, we can create  another folder called decorator.   And again, export the burn with a burn export.  And let's create a custom what we call a   puram decorator. And I don't remember the syntax  by heart. And obviously that's why as programmers,   we have documentation, so use it when you can  you're not supposed to know everything by heart.   And in the custom decorators documentation, we  have params decorators, and that basically mean   that you can put them in the parameters of your  endpoints. And there are a lot of them already   defined, you see that you have the request,  we have already seen their session as well.   You have IP headers query body that we have  used, right. And they say that you can create   a custom decorator, for instance, to get the user  object on the request object. And the way to do   it is like that. So they just copy it. And I'll  explain in a minute what it does. So let's go and   create our decorator, let's call it get user.  decorator, the Ts, and let's call it get user.   And that's it. It is creating the params  decorator that we can use like that.   Get User right, and it in fact, it only knows it.   And what it does is it can take a data that you  pass to it, for instance, that would be data.   But by default, it's unknown. So you don't you  don't need to pass it. And the second argument   it's actually gets, it actually gets the execution  context of the request. So it's important to   understand that NES GS is an abstraction right?  It uses something under the hood. It can use   Express it can use any other protocols. Here,  we say that the this execution context switch   to HTTP because we're using HTTP, but sometimes  you might use for instance WebSockets, right.   Or you can use RPC for something like like micro  services. In our case, we use HTTP And then we say   get requests, there are other things that you can  do, you can get the response as well. But here,   we want to get the request. So it's going  to get the request object of the Express   Library, right. And then we can do something with  it. So this request will actually be the same as   Express request. If that makes sense,  right, this request is going to be that,   and then it's going to return whatever we want  from it. So the decorator will put in a variable   here, whatever we return to it, and is  going to be a user. And in our case,   since we have used the strategy, in our case, the  user object will be the user object from Prisma.   Right, that's all we need to do for the custom  decorator, let's export it from the Baron export.   File, and in the user, we want to use the Baron  export pattern is going to export it from the   decorator file. And here, we don't need to put  any data for now we're going to leave it blank.   And here user is going to be of type user. And  that will come from the Prisma client. So in   the beginning of the video, I said that Prisma  generates TypeScript typings for us, so which is   very cool. So now, we can say that this variable  is of type user that was defined in our prisoner   schema. And now we can just return the user and  it makes it all clean, and that decorator, you   can reuse it pretty much everywhere. Now, we can  also optimize that logic a bit by moving the guard   on the controllers level. So that just means  that everything that is in the user controller,   while it will require you to be to have a token,  it will require you to provide an identity of who   you are, which makes sense. That way. We if we  have another endpoint here, for instance, patch.   Edit User, well, we want me to copy the guard here  as well, we can just put it on the global level.   So let's go ahead and run our requests again, and  everything is working. So let's say that in that   in this case, you don't really want to pass the  whole user object, you just want to pass the ID.   So you can say I just want the ID and then it's  going to be user ID and it's going to be a number.   So you can say something like that. And then  in your logic, you can get the ID of the user,   if you want to do something like that, it's quite  easy. You come back to the Get User decorator.   And you say, well, if if data if there's something  in the data, then you return request user. data,   and data will be a string. And it could be  optional. So we if we don't provide it is going to   return the whole user object, if  we provided it's going to return   the the a field from the from the user objects.  So we can we can actually try that out here.   And here, we say we want to  get the email of the user   is going to be a string. And we can before  returning the user console log that email.   Let's run the request. And if we come back here,  or there's something that's not working a required   parameter cannot follow an optional parameter. Let  me go back to the get user. And here, okay, I see.   So instead of doing like that, and this is true,  a optional parameter can only be put at the end   here, the old order kind of metrics. So we  will say String or undefined. So that way,   the data could be potentially undefined. Let's  go back and throw the request. And we have   a log of our email and the same time we get our  users so everything is working correctly. Let's   clean that up. And we don't need to get the email  anymore. So thanks to those tools, decorators and   guards. We have created quite a clean logic  for our application. You see everything is   quite organized, and everything has its place.  There are a lot of decorators that nest GS has   and it allows basically you to save Have some code  and have something? Well, I would say economic   from a from a visual point of view. For instance,  there's another decorator that I use quite a lot.   And that I haven't showed yet. It's HTTP code. So  usually, when you create a resource on the server,   you send back a 201 HTTP code. So if we go ahead  here and create a new user, Vlad to the status   code will be 201. Right? So that just means that  the server has created something in a database,   that's kind of a standard, you can of course,  make it return to Oh, so for that is going to be   HTTP code. That's the decorator. And inside the  decorator, we're going to return a status. So   for instance, it could be 200. Gnaeus, also  has enums. So instead of returning numbers,   which is error prone, you can return  enums, HTTP code, HTTP status. And you have   accepted found and it basically means  different codes. So code 200 means okay.   So and if we put the mouse here, we see that  200 is equal, okay. And there's a lot of other   code that is that are used in the development.  So you see, here's a whole list here not found,   for instance, that is very known for or for 401,  authorize that is thrown by the strategy when the   bearer token is not correct and forbidden, for  instance, for free, when we throw a forbidden   exception. So we can do that. Obviously,  when we create a user, now it's going to be   two Oh, but by default, a post request will  return to r1. So we don't really need to   change that. However, when we sign in, we don't  really create a new resource. So I like to return   the code 200. So we can use it 200 Here.  So instead of like signing in with a 201,   it can be used to sign in and get it to oh, that's  quite cool. So post requests return usually 201,   GET request will return 200. So we don't need  to specify a because decorator here, we have   implemented quite some features already. And you  see that our application starts to grow, will   soon implement the user routes. For instance, the  patch user route will also have bookmark routes,   and application will start to grow, it's going to  be very tedious to actually go in insomnia, and   run all those kind of tests manually. Imagine you  have something like 100 endpoints, and you need to   test several use cases, for instance, like, Oh,  I've signed up with a profile of admin and the   admin should be on boarded. And then it should  do that. And then I need to sign up with you,   oh, my God, it's pretty much impossible to test  manually. So that's why we use automated testing.   There are three kind of main levels of testing  you have unit testing that you probably have   heard about, unit testing will usually take any  any functions, for instance, is going to take   the sign up function is going to mock any  dependency that the signup function is using,   for instance, argument or connection to  the database. And it's going to try to   make sure that this function is executing and  calls the right the right things and everything   is working correctly on that unit level. However,  that takes a lot of time. And to make it right,   you need to actually practice a lot. There's a  lot of methodologies, how to do unit testing. And   it can be really nice when you have a project  where a lot of people work on and a product   that will respond through years and years of  development. Unit tests are a good investment   in terms of your time. However, in most of the  cases, what we want to have really is end to end   testing and integration testing. So we have unit  testing just above, we have integration testing,   integration testing, will kind of take several  modules. And that's why NES GS is so cool,   because, by default, it separates our application  into modules. So for instance, I want to check the   odd functionality on it. Well, I can load the odd  module and the Prisma module, and maybe the Config   Module. And I can test only all those three  together. And when I'm happy with the result,   I can just test something else user user well  for the user will need to have a user. So   it needs to use the auth module. So we're going  to use the auth module user model prisoner module,   but not the bookmark module. And we can can  test all those together, integration testing,   you define some segments of your app and you  test them together. I like to test it with the   test database, so on of having a dev DB that I  use for like manual testing and manual feedback,   I will also have a test DB here in our Docker  compose that I'm going to spawn and destroy   every time I do my tests. So you have integration  testing, and then you have end to end testing and   end to end testing kind of verifies a very high  level user journey of your app. So okay, a user   signs up signs in, he requests his profile, he  does that. So it mainly verifies how the user will   interact with your app. While integration testing,  we can really test a lot of things, for instance,   well, is the same token working correctly, is it  the same token with signing is working correctly   are the exception throw correctly. So this is more  for integration testing. Since testing takes a lot   of time, usually, it's estimated that testing  takes at least the same amount of time that you   have spent on creating your app. So if you have  spent something like two weeks building your app,   you'll probably spend at least two weeks testing  it. There are various methodologies for testing,   there's test driven development where you  write your app as you test. Obviously,   we have not done that here. And it can solve  some problems as well. But in our example, here,   in our small CRUD application, what we can do  is that we can use end to end testing. So end to   end testing will allow us to kind of showcase the  use of our app, and prove that it kind of works,   we don't need to go into details and  make sure that everything works together.   If you're interested by that, you'll probably be  using integration testing, I have a video about   that on my channel. So if you are interested about  that, specifically, and how to do it with Prisma,   well be my guest, there's a one hour video on the  subject. But in our example, we are going to use   end to end testing. And I'm going to use a library  that has been suggested to me by one of the core   developer of NES GS. And I have to say, it's quite  cool. It allows you to save a lot of time. And   it's called Pakhtun. By default, NES GS uses super  test for the end to end test. But In that example,   we are going to use Pakhtun je s. So without  further ado, let's get started and create our end   to end tests. So we don't have to jump between our  code and insomnia over and over again. Okay, so   let's start with that amazing endeavor. And first  of all, let's install package on yarn, add pack.   So pack to me is an amazing library for testing  your API's. It is really nice to work with.   And it works very well with Graph QL. And  it has a lot of features that we're going to   use straight away. And to install  it, all we need to do is to use   AES to install it with factum.   So before we start, our test will need to consider  a couple of things. First of all, we will have to   set up a test database for our end to end tests.  Because we want to keep the dev DB actually   separate from the test dB, so we don't delete  our database every time. So that's one thing.   And the second thing is that we'll have to set  up the database set up the Prisma service to be   cleaned up every time we run our tests. But before  doing that, let's clean up our app. And to inspect   file. We can just go here and delete everything.  So how NES GS works is that it's going to compile   a module. And we're going to take the whole global  module, the app module is going to compile that   and we can create a test module out of it. And on  that test module, we can call requests like we do   with insomnia. So let's go ahead and first,  create a describe blocks. So it's going to be   app content.   And inside that app, and when we  will just run a test, a to do test   should pass just to see that if our script is  running, and we are going to kill our server   because we don't need the server anymore. We are  going to kind of use what we call test driven   development. We are going to write tests and write  logic and make sure that our tests are passing.   So The way to run that file is through tests end  to end here, there's a script already created   for us by nursery's. So yarn test end to end. And  let's see if that at least works. And we see that   we have a past test, nothing really happened. But  that's fine, because we haven't defined our tests   yet. So let's go back to our test and create  the Prisma module. So before all the tests,   what we're going to do, and it's  going to be in a sync function,   it's kind of a hook that is provided by jest,  we're using jest as our main testing framework,   both describes come from jest. And we're  going to use Pakhtun for for the requests   to send the request to our server and to analyze  the the answers to responses from the requests.   So before doing that, we need to create a module  module ref await test, the test is going to   come from from NES testing. NES GS  test think there will be a test.   Test create testing module. And here we import.  And that's basically a, a, a module as we have   here in the app module. So we create a module  that will import that app module inside it.   That's the easiest way to do it. app module for  the app module come from the from from here.   And we are going to say compile. And  that's pretty much it for end to end test,   we just import everything because everything  needs to work together. And what we need to do,   then is to well, let's see  that passes to begin with.   Right? Amazing. Now, what we can do is to avoid  everytime that every time that we want to run   the test. To avoid that we have to go here and  do yarn test and 20, we can set the test to be   kind of automated. So the run automatically  as soon as they detected change in our code.   So we go back to package json and say just watch.  One important thing that we need to say as well is   to disallow the cache of the test in case we  don't run into problems where some resources   might be cached. So that's fixed as well, let's  go ahead and run it and see if that works. So   now it should be running continuously. And if  we save, nothing would happen. But if we run a   new test, it should automatically recompile it.  So it will detect if we have any new tests in our   application. And if I press A is going to run all  the tests again, that's pretty much just usual,   just I would say flow, you press W to get more  options. But for now, that's all we need to do.   And let's delete that test and, and see if we  can connect to our test database right now. And   let's add a couple of things. Basically, what  we are doing here is that we are simulating the   the server. So anything that we have defined  in the main Ts, we also need to define here.   In our testing module here we use Global pipes.  If we don't include those, the detail validation   in our tests will not work. So we need to also  include those just before here. So now that we   have the module compiled, we need to run a win to  create a NES GS application testing application.   So we can say app is equal module, dot ref. Create  module ref, create nest application, right, so   he's going to try to emulate an app. Here, it just  compiles a module that can be useful when you run   integration testing. But since we really want  to run an end to end testing, with that, also   app we can abstract it in name in the describe  here, I nest application and app will be this.   And now we can include the pipes. Otherwise,  the validation pipe will not work. It needs to   be as close as possible to our real server. And at  the end we say await up in it. So this is where we   kind of start the server and when We are done.  When all the tests are done, what we do is that   we do app close. So we close the app. And we see  that now it is still working, everything is good.   This is our starting logic. This is our teardown  logic, we can close that. And now let's think   about the database. Well, by default, NES GS,  in our case, will connect to our dev database,   we need to have a dedicated test database for our  test and a dedicated database for everything else.   So how are we going to do it? First of all, let's  create the dev DB in our in our Docker Compose.   So just copy here and called sorry, test  dB. Test DB is going to run on port five,   and 5435. So it should not be running on the  same ports or otherwise you will have a problem.   And the rest can pretty much stay the same. We can  now go back to the package that Jason and we see   that we have a we have the scripts for the dev dB,  right? Well, we need to have the same scripts for   test dB. So let's copy that and write  it here test to be your third. So   and and just copy all the scripts here. And  those will be for test for is not test deploy   dB. Test, remove and DB test up. So for the  test DVD, it's going to be just test a B   test, the B prisoner deploy. And here  in the to start is going to be test,   remove yarn DB test up, and er prisoner test,  deploy. Okay. One important thing though,   is that Prisma does not manage the the environment  variables by default. So here is going to just   load the environment, the database URL from the  environment file that it detects. So I need to   be a bit more specific here. This means that  prisoner will try to find that variable from   the environment variables. And if it doesn't find  it, it will try to get it from the NV file. So   one thing to work with Prisma with  different environment variables,   because you can just create another.in the  development that indata testing, that would not   work. Well with that the cleanest way I found to  manage environment variables with Prisma is to use   a NPM package called dough 10. CLI, so let's go  ahead and implement it. Yarn add the 10th. CLI.   So what is going to allow us to do is  to inject the dot env file of our choice   in our kind of scripts. So by default, if we just  stay on the environment variables is going to get   this environment variable. So if we don't do  anything, everything is going to be loaded   immediately from this one, right. However, if we,  if we want to use another environment variable,   such as in the the test, it's a bit more tricky  to force or all our code to use this one,   because Prisma will automatically only get the  dot ends, it doesn't know about the end the test,   and it cannot know about it. The Config Module  from the API tutorial can load that specific one.   For instance, it has a variable called end file  path, and you can specify where the environment   variable ease, but we will have to create a lot  of filler code and it's going to be quite ugly. So   it's better to use the 10. CLI. It keeps our code  clean. And we don't need to change anything here,   we just need to include that library here. So  let's go ahead and do that. So if we are using   the dot env development, we don't need to use  the 10th CLI because by default is going to be   using this one and this one will override any  any other environment variables file. However,   if we use the test ones, we need to inject  this one first. So it's very easy to be honest,   you do you just do the n the E and you just  provide the path to the end file environment file   and dot txt And then you just execute the rest.  This is this is specific to Docker. So Docker   does need to be aware of the environment  variables. However, when we run our test,   we also need to make sure that the NESs GS is  loading the right, the right environment variable,   not this one, but this one. And for that we also  need to include here. So we include that end,   hyphen, e dot and the test on the test end to  end. And on the deployment of our migrations,   right, and let's come back to a dot and  if the test and just they just clean that   here, and implement that new string, but instead  of the Port 5434, we're going to have the Port   5435, which is the right port. Now to test it all,  and this is the moment of truth. Let's go ahead   and kill it and do yarn test, end to end. Also, an  important thing is that we need to create a hook   for test and twin. So when we run the end to  end test, it needs to run the DB test, restart.   So it's going to clean the database, the test  database, and it's going to push the migrations   on that test database. And it's indicated in  the dot n dot test. And to define a hook in   package that Jason scripts, so we just say  pre. And we put the name of the script here. So   if we execute that, this is the hook that's  going to be executed before. And we do yarn,   DB test, restart. And just to make  sure that everything is correct, the B   test restart. Okay, let's try  that out and see if that works.   So we see that the hook is working. And everything  seems to be correctly working now to make sure   that the migrations have been pushed into our  test dB. So let me just open a new terminal   session, and I just do docker ps. And we have  now two databases, one that has been created   just just now. And it is the database  on port 5435. It is our test database.   And this is the old database on port 5434.  So what we want to do is to make sure that   this database has the migration, all we need to do  is to use Prisma. To do but remember that Prisma   is also using this the 10th file. So what we  can just do is to force Prisma studio to use   this one with the same technique that we have  used here. So that N E F test, let's copy that.   And it's MDX because we are running it  from the terminal. And we do Prisma studio.   And that should automatically connect us to  to the right database. Now we see that the   studio is blank. However, if we connect  to the to the other one with dot length,   will be connecting to the dev database. And here  we have some fields that we have been testing with   insomnia. So everything is working correctly,  we can clean Prisma studio, we won't need it   for our tests. And let's come back to our testing  logic. If you have any questions regarding that   process, feel free to drop them in the comment  section below. I will try to answer as soon as   possible. But all the code here will be available  in the GitHub repository in the description of   this video. So if you are stuck somewhere, just  check there. And I'm going to clean here because   everything works correctly. And yeah, let's start  our testing process. So now we're connected to the   test DB via this environment file. Everything  is okay. Let's go back in our in our testing   module. So what do we need to do? First of  all, first of all, before running our tests,   we need to make sure that the database has been  cleaned. And of course, every time we run our   end to end tests, the whole database is actually  restarted, so cleaned and restarted. But when we   run our tests in the same kinda just session, we  also need to clean the database. We don't need   to restart the Docker container because that  takes time that takes like three, four or five   seconds. And we don't want to wait all that time.  Right? So what we want to do is that we want to   tell Prisma to clean everything that is in our  database every time we run the tests, right?   So because we have a just end to session that is  watching. So that is keep going, it doesn't stop.   We need to do it manually. So it's  quite easy to be honest to do it.   But let's first examine our schema to make  sure that we are doing the things right.   So what should happen here? Well, every time we  do we run our tests, we need to delete the users,   and the bookmarks. And sometimes there could be  a problem where for instance, of the bookmark   is linked to a user, right? But what happens if  you delete the user first? Well, if you delete   the user, first, the bookmarks suddenly might  be without a user. And that could be that could   be problematic, because that can create errors,  to make sure that we don't have any errors. And   that elements are deleted in the right order, we  can either tell Prisma to delete first bookmarks,   and then the users. But that can be a bit  daunting, because imagine you have something like   20 models, so your teardown logic of your  database can be quite long. Or you can do   something like that you can say, on Delete. And we  just say cascade, that means when the element that   is it is the kind of the parent of that when  the parent model or that bookmark is deleted,   the bookmark should be deleted as well. To  implement that we need to run migrations,   I'm not going to do that, I'm going to go with  the other option, where I'm going to make sure   that the bookmark is deleted before the user,  but know that it is possible. And in some cases,   it is really good to have a on delete cascade,  and it's unless you really want to conserve   the data in your database. So for instance, you  can in an app have categories and posts. Let's   say that the user decides to delete a category,  well, you can say what happens with the posts   in that category? Are they kind of  set to are they just do we keep them?   Or do we delete them as well, in our case, if a  user has been deleted, the bookmarks should kind   of be deleted as well, I don't see why would we  keep the bookmark so undelete is set on cascade.   But in some application, you might want to keep  the user data, you know, you never know. But know   that it is possible to have those kind of hooks  on prisoner, but I'm not going to go with it.   Because I don't want to run the migrations,  I'm going to just show the other way.   The other way is to go into Prisma. Service. And  we need to implement a new function that's called   Clean dB. And what does clean dB? Well, we need  to tell it what it does. And we need to delete   the bookmarks and the users. So we can do return  this prisoner. Sorry, actually, user, it works   like that, because this is actually prisoner. So  this is the Prisma, client, user, delete many.   So what do we need to have here, we need to  delete all the users. And we need to delete all   the bookmarks. And of course, since we need to do  it in order, it needs to be first bookmarking. And   you're right, except that Prisma kind of optimizes  our, our request and could delete the user before   the bookmark. So to avoid that we can use  transaction a transaction is when we tell Prisma,   to make sure that the things are  done in the specific order. So this   transaction, and we just provide an array and  elements will be executed one by one. So we first   need to delete the bookmarks, and then we delete  the user. So we don't have a case where a bookmark   can be without a user. And we just need to return  that. And that's it. That's all we need to do.   This is our teardown logic that we need to run  before our end to end test. And let's come back   to the end to end test in before all hook,  we need to make sure that in that logic, the   database is reset. So how do we get the database?  Well, it's actually quite simple in Nash, yes,   because it uses dependency injection. So you  can do app prisoner. Let's just declare our   Prisma service here. And now we can say,  we can say prisoner is equal to app get,   and we can get any provider that we want. It's  called Prisma. Service. And it's going to just get   that Prisma service and we can put that into the  variable and we can call that variable like that   await Prisma clean dB. So it's quite cool to do  tests with Nest Yes, because yeah, it's just a   nice experience. And we can come back here. And we  see that property, clean DB does not exist on type   prisoner service. That can happen sometimes  when you write code, and you didn't allow   Nigeria to recompile the files. So in  our case, we, I think we need to just   restart the server. And that should work.   So if you are doing major changes to  the underlying logic to the services,   you might actually need to restart the end to end  test because it needs to compile the files into   into JavaScript, right. And that's it. And let's  go ahead and now create our end to end logic,   we can close that collapse this, we don't need to  touch it anymore. And we don't need to touch it   either. Because as soon as we close the app, the  prisoner connection to the database is also close.   So we are quite happy. Now let's create our tests  of describe what do we need else we will have user   and we will have bookmarks.   So you notice that I actually write the tests  first, before we even have a for instance,   bookmark logic is because that will allow us to  kind of have a structure already and think about   our application before we even build our code.  So what should be in the oath? Well, it should be   sign up. And there should be signing   and that's pretty much all the race, then we  should be able to get the user get current user   or more like get me then we should be able to edit  user. And for the bookmarks, we should be able to   get bookmarks create bookmark we  should be able to get bookmarks.   We should be able to get bookmark by ID maybe  edit bookmark and delete bookmark because that way   we will have our CRUD application now next year's  complaints because we haven't created a single   test. Let's go ahead and just create a  to do I think it will be happy with that   should sign up. Let's see that  works. Okay, that works. So   we have should sign up we  also have should sign in.   And let's start by that. So this is kind of  our testing structure. Now we're going to   run our tests right our tests actually  and for that we are going to use Pakhtun   so to run the tests was packed on we first need to  import it with import all as Pakhtun from factum.   So after that we have imported Pakhtun. We can  now use it in our application. But factum is   a request making library, it needs an API, it  needs the server to make requests. And so far,   our servers, our NSGs app, it just has initiated  the nest application context, we also need to   start a server by providing a weight dot listen.  And we can provide the port at which we want the   app to listen. And now we can do the request  so we can go into our first route a to do and   we can provide a callback function to that test.  And what do we call we call return Pakhtun spec.   And then we provide the the request type is a post  request to OD two to HTTP localhost 3333 Odd sign   up and then we need to provide the body as well  with body and the body will be the to the odd DTO   and it will take an email which will be  flat@gmail.com and the password which will   be one To free. And we will provide that  email here. And we shall expect a status   of 201 Because we're creating a resources. So  let's get back and see, okay, perfect. That test   took 42 milliseconds. And that has succeeded. If  we want to see what's inside the request body,   we can just call inspect, at the end of the  promise chain. And the body here has been   locked, along with the code and the  headers. So you see that we have the   headers that is powered by Express, the status  code is 201. And we get our access token. Now,   this is a bit verbose because every time we're  going to call the the API, we need to write that   this is called also the base URL. So what we can  do is that we can abstract that away from this   post request. So we don't need to repeat it in a  subsequent request. So we can do Pakhtoon request,   said base URL, and we can just provide that base  URL. And instead of writing the localhost here,   we can just write out, sign up, that is much  cleaner, much shorter. And that does the same   effect. Let's get rid of the inspect to see if  our test is passing. And everything is nice.   So it just took a bit more time, but it  just independent of our of our logic.   Okay, now, it's amazing DTO, we are going to  reuse it in our whole Old application, kind of odd   flow. So we can just move it above. And let's  also test if the sign in route is working. So   we are going to delete it to do here, provide a  callback to be to test and return out sign in.   Since it's a end to end test, it will first  execute this code. So we will have a user   and then it's going to execute that code. And  obviously it should be too low. And let's see   how it works. Amazing, everything works together.  So we have tested that we can create a user   and that we can sign in usually when you write a  test, you also need to test the use cases where   your test will will fail. Alright. So for  instance, before writing should sign up,   we should actually write it should throw, throw  throw an exception, if email empty. So we can   also write all that to test if that logic will,  will flow. So we can just copy that. Put it here   and say that we expect a a code of 400. So  we're going to write 400 status code to be   expected because we expect the error to be thrown  by the validation pipe, which returns a 400 error,   bad user input. And we also need to provide a  DTO without the email. So what we're going to   do is that we're just going to provide just the  password 123 Actually detail that password. So we   reuse that, that detail. And let's see if our test  is passing and we see that the test is passing   next we can also check the other way around.  So should throw if password password tempting.   So instead of having the password here,  it's going to be email and the to that email   and should also throw 400. Right. And we  can also test both just in case, throw   should throw if not that you nobody provided.  And I'm just going to do it without the body.   And we can do pretty much the same with  the with the sign in. So we can copy that   and test it with a sign in here. Except  that it's going to be signing everywhere.   Let's go ahead and check our tests. And everything  is passing. And that's pretty much the process   of kind of end to end testing. It doesn't really  test how our modules how our functions interact   with. So we might return the right status, but  maybe some something in the database is not   is not saved in the correct format and that we  are not going to be able to verify that with end   to end testing. end to end testing is not the is  not designed for that end to end testing is just   there to make sure if the app is working end  to end. So if kind of all the functionalities   are working more or less as expected, if you  need to go in more details, you're going to   actually create integration testing. And  that's out of the scope of this tutorial.   Now, a very interesting part is that we need to  check the user information, right. But for that,   we need to send the bearer token. So Pakhtun  provides a very neat functionality that allows   us to store a variable in the packet and  execution context. So we don't need to   create a variable somewhere, for instance,  we don't need to do something like that   access token, and then assign it somewhere  else based on the of what our API returns,   what we can do is that we can use the store  API of pakhtuns. So here in should sign in,   let's inspect the body response that's going to  be returned. So we have the body and we have the   access token. So we can actually save that value  in the memory of Pakistan. So let's go ahead   and use that functionality. And it's basically a  stores function stores back request and response   data. And we can choose where what we want to  store. So for instance, is going to be user at   user access token is kind of like assigning a  variable. And the path to that variable will be   access token. So it's going to get the access  token from the body, the access token variable   from the body, which is in the Jason and is going  to put that into that variable. And later on,   we can reuse that variable in our requests.  So let's, let's do it here. Get me it should   get current user   return packet on the just copy that  here. And we are going to put users   need and it should not have a  body. However, it should have a   a an authentication headers. And if we check  the code, right now, let's run that. We see that   get current user, we have a status of 404. less  interesting. Why is it? What is going on with it?   So users? Has that controller and me, users me,  so why is it not working? That's very interesting.   404 cannot post it's a post request, of  course, it expects a get request. So get.   And now it says that it's it's 401  unauthorized because we don't have the   access token. Right. So let's get go ahead  and pass the access token. In the same way we   have passed them in insomnia. Remember here  in headers we have. We have authorization   bearer space and the access token. Let's go  ahead and do that here. Headers, with headers,   and we can provide the object key value. So the  key is authorization. And the value is bearer. And   to inject that variable that we have saved here,  there's a special syntax in Pakistan. And it is   this thing a bit like what we have in in template  strings with JavaScript, except that you have an S   here for store. And you can put the name of the  variable here. And normally, we should get a   a correct answer. And we can even inspect  that to make sure that we get the correct one.   And you see that we got the user object that was  expected. In a nutshell, that's all integration   testing is most of the time you will just test  if the status code is correct. And at that point,   we have tested all our routes. And what is left  is to actually write the logic for edit user   and the write the logic for create bookmarks, get  bookmarks, get bookmarks by ID, edit bookmark,   actually by ID, and delete bookmark by  ID. So this is what we're going to do   in the next part. In the next section, we  are almost there, we have almost finished   our CRUD application. So what we need to  do now is to create the logic for the patch   request, and the crud requests in the bookmark  module. Let's first start with the patch request.   And we are going to need the service here, we  can leave our end to end in the background.   And we can go ahead and create our, our service.  So nest G service, user know spec, it's going to   create a service for us that we can now use, let's  put there and we need to create a function here   Edit User in the same fashion that we have done  with the auth service. So edit user is going to be   probably in a sync function is going to take  several fields is going to take a user ID.   And that's pretty much it. And it  also needs to inject prisoner praise   Max service. And that's yeah, that's  about it. So once it receives the user ID,   it also needs to receive a DTO. And it's going  to be Edit User DTO. Let's create that DTO.   So Edit User DTO, the Ts. And it's a class, Edit  User DTO. And what can we edit? Well, we could   edit the email, we could edit the first name  and the last name, so email, drink, first name,   string, and last name, think and all those  fields can be optional, because we can just   edit the email without editing the first name,  or the first name without the email, etc. Right.   So we can also provide the class validator  with email. This is going to be a string,   string is string. And all those  are going to be is optional.   It's optional is optional and mean to export that,  Edit User DTO and exported here through the parent   export pattern from Edit User DTO, let's clean  those files and come back to user controller.   The patch request, edit user will receive  a body of type edit user detail. And it's   going to also get the user and just the user ID.  So Id, user ID and it's going to be a number.   And he's going to call the function in the  User Service edit user. And it also needs to   have video edit user DTO. And let's just call  that so on that side on the controller side,   this is done return this. We have of course  not imported the the user service here,   we also need to import it through dependency  injection, private user service, user service.   And now we can use that user service here return  this user service added user user ID and detail on   on the control side, it is now done. Let's go back  to the user that service and write our logic here.   So what we need to do is to update the user with  the DTO. We know that the DTO will either have   an email first name or last name. So we can trust  the DTO. Because remember, we have this function,   we have this pipe with a widely that's true. So  we are sure that we are going to receive at least   something at least something in in in our in  our API request. And we can say user is equal   await this Prisma user update where ID is user ID  and the data that we're going to update, we just   can just destructure the DTO. So if the video  has something is going to be structured here,   and before returning the user, we can delete the  user dot hash and return the user. That's our edit   logic. And before continuing any further, let's go  back to our tests and run the test for that edit,   edit functionality. So we come back to our tests.  We have one Is that we have user get me. And we   have edit user, right? So we go here and just  copy the test here and right should edit user   is going to be users. And it's  going to be a patch request.   And the headers are correct. And we need also  the body, the body will have it to the to edit   user DTO. And let's just edit the  first name of Lada mirror, and   just the email. Lat at code with blood, that  and let's push that detail to the body with   embody the T O and let's see if we can  get something interesting. So first,   let's see this test executes. So here it goes.  should edit user, it is executed. Interesting. And   let's maybe inspect that. Where's the answer here  is this. This is the response. So we get the user   with the updated email and with the updated  first name, which is quite cool. So that works,   we can also make our tests a bit more defined.  For instance, we can say that, Oh, we expect that   the body contains a field where we expected  the body contains the first name Vladimir,   and an email of that, well, we can just say expect  body contains. And we can provide a value. So it's   going to be detailed that first name. And  we can do the same with the to that email.   And let's see if our code executes. Cool. Our code  is now working obviously, you can test it out,   you can say expect body contains let's say I  know false value. And that should throw an error   because false value is not part of the body  value false value not found in response body.   So that's a handy way of checking if some fields  are there, without going too much into details.   Okay, now let's go ahead and create the routes for  the bookmark. So for the bookmark, we haven't done   anything yet. We will need to have a controller  and a service. Let's go ahead and create those.   So nest G controller, bookmark,  no spec. And same for the service.   Miracle we can clean that out. And here what  do we need? We need to have a couple of routes.   Okay, bookmarks, maybe put it here as bookmarks.  We also need to use some guards. So govt guards   need to have an access token in order to use those  routes. So that is done at all missing imports.   Have we forgotten something else? No, I think  we have adult we can close user controller and   just work with bookmarks controller right  now. So we have a route to get all all the   all the bookmarks, so it's going to be get   get bookmarks. We also have get bookmark  by ID. We have edit bookmark by ID.   And maybe delete bookmark by ID. Let's check  our test. If we haven't forgotten something,   create all create bookmarks as well. So we get  bookmarks. Get bookmark by ID, edit bookmark   by ID and delete bookmark by it and we also need  to have a route for creation. So create bookmark   that's it we need to have a positive decorator  for create bookmark, we need to have a   get decorator for get bookmark by ID by ID.  Let's move it above so gets are in one place.   We also have added bookmark  by ID so it's going to be   patch and delete is going to be  deleted. So we have the whole crud   crud thing. Let's also import the service because  all our business logic will be in the service.   Private book mark So bookmark service, book mark,  service. And let's copy all those functions in,   in the bookmark service. And  just clean the decorators here   here we go very well, now all of them will  have to use get user decorator, get user.   And it will have to use user ID. Number.  Sorry, it's actually goes into here.   And we need to fetch the ID. Same goes for here.   Same goes for here. And same goes for there. And  the reason why I have to have these ready is that   I can check if a bookmark belong belongs to a  certain user or not. So when we are deleting a   bookmark, we need to make sure that we are  not deleting the bookmark of someone else.   And when we get the bookmarks, we need to make  sure that we are getting the bookmark of that   user. That's why we in that, so the Git bookmark  will not need to have a DTO. This will not need   to have a DTO, either, but it will have to have a  parameter. So if we want to get a bookmarks or get   book marks by ID forces, two, or five, well,  this ID is called the params, we can get it with   another decorator. Here around that also comes  from less common, and it's going to get the ID   and the Name of that variable will be equal to  the variable that we defined here. And we need   to put two dots like that. And similar to what  Express does express also have those parameters.   And there's going to be book mark  ID is going to be a number. And   by default, this is going to be a string,  but we can convert it to a number with parse,   and pipe, the Create bookmark will have to have  a detail. So let's go ahead and create that DTO.   Index Ts and create book mark that detail  the TS export class create a book mark DTO.   And what will the Create bookmarklet to have?  Well, let's check out our schema. So the bookmark   has a title description, which can be empty, no  link, okay, title, description and link. Let's   go ahead. And let's add that title is a string  description is a string and it can be optional.   And link a string as well. And  we can use this drink validation   is drink is drink. And this can be is  optional. And this is is not empty.   Here we go. And we can export  that create video from the folder.   Now we can close it all open the  bookmarks and add the DTO here as body   the DTO will map to create bookmark   DTO and edit bookmark DTO will also have something  similar. And I'm going to show you a cool,   neat way to reuse our code. And here we have  made an error it should be capital. And it   should be capitalized here because it's a class.  And that should be fixed. Above. That's nice.   And the next thing we said that we want to have  edit bookmark by ID by ID Okay, edit bookmark.   Detail the Ts. So what we can do is to just  copy what we have here added bookmark the deal.   And everything could be optional. That's  the only difference here and here.   This is this is for TypeScript. No this is for  the validation to know so you don't get confused.   We can change title description and link and  we also need to export that detail from our   DTO folder. And then go back to here and the patch  request will be edit. Bookmark DT Oh, nice. And we   just need to have the one last route, delete  bookmark by ID. Well, it also will take the,   the ID here. And we can just reuse the same  logic that we have in get bookmark by ID. Here.   Here we go, we have everything that we need  on the controller side. Now let's jump into   the service side. Let's jump into bookmark  service. So what do we need to get to bookmark,   we need to have user ID, which is a number and  that's about it, right? We don't need to have   anything else yet just to user ID, then  we need to get the bookmark by ID, well,   we still need to get the user ID. But we also  need to have a bookmark, it should be a number   and create bookmark, we need to have the user ID.  But we need to have a DTO of create bookmark DTO,   since it's going to be an object,  same for edit, bookmark DTO dot   edit, bookmark DTO. And delete bookmark by ID  is going to be user ID as well. And bookmark it.   Like, like here, and that's pretty much  all our parameters. Now we can pass   our R values here to the service, return this  bookmark service, get bookmarks, user ID,   we also need to do the same here,  get bookmark by ID, so just need to   change it here. And you also have the bookmark  ID that goes there. And for create bookmark,   purchase similar except that the  second argument will be d t Oh.   And here as well, it's going to be  the same DTO but it's going to be   create bookmark edit bookmark by ID. And  here we we actually have forgotten something.   Since it's added a bookmark by ID, you say  the idea of the bookmark at which you want   to be edited and you provide the body so  we have forgotten also to put a ID here.   And let's just copy it here and  provide the bookmark, bookmark ID   and then the DTO. And of course, we need to  go and modify the signature of that function.   And delete the bookmark by ID is going to  be your turn this bookmark service delete   bookmark by that by ID user ID and bookmark it.  Whew, that's, that was a bit tedious. But we have   all the logic pretty much programmed from the from  the controller's point of view. Now let's go ahead   and jump into the service to to see how we  can make that work. And we're going to do it   one by one. So when you write code, it's  also nice to actually test it straightaway.   So you get an immediate feedback on how your code  performs here is going to be very wide because we   are running entwine tests. But usually you would  first go with integration tests. But in our case,   since the application is quite simple,  that's going to do it. We rerun the test   database to make sure that everything is  updated correctly, all the files are generated   as they should be. We have our first tests that  are being run. And let's go ahead and add the   logic for the second one. So the first thing  is to create bookmarks. Okay, maybe we can,   we can first get the bookmarks, get empty  bookmarks first, get empty bookmarks. So because   we want to kind of simulate the user experience  on our app, if we imagine what the user would be   with end to end tests, let's actually close  that. Close this To make it a bit more readable.   So we have the signup functionality, the user  signs up, then he signs in, then the user will   get himself. And then he can edit himself. So we  can simulate what the user can do on the platform,   then the user will go on a dashboard or something,  and he will get empty bookmarks. Because he   haven't created. He hasn't created any bookmarks  yet. So let's go ahead and simulate that.   Let's copy this code and simulate  it here. It should get bookmarks.   Return Pakhtoon is going to be  bookmarks, it's going to be get requests,   the headers can stay the body, we don't need  any, the status should be 200. And let's inspect   the result. And we see that the body is actually  empty, nothing is there. And this is normal,   because we haven't written any any logic yet.  So we can come back to our bookmark service   and write our logic. So let's import  Prisma. Because it's not important yet.   Prisma Prisma service. So get bookmarks. We need  to return this Krisna. Sorry, I forgot private,   this. This Prisma. Bookmark, return file,  find many where, where what where user ID   is equal to user ID, we can just leave it like  that. So it's going to return all bookmarks   that are linked to us to the user that is doing  the request. Let's see what it does return.   And here, now we have an empty array. And because  by default, when Prisma will run, find many, if   it's not going to find anything is going to return  an array, because you are expecting to find a lot   of elements, right? So what we could say is that  inspect status, expect body. And here we can say   what the body will expect. And it should be an  array, an empty array. Let's see if that works.   Then we can go ahead and continue with our logic.   And we can write the code for create a bookmark.  So same thing return, it should create a bookmark   return Pakhtoon spec post bookmarks with headers  correct. And then we need to provide a DTO.   So let's go ahead and provide  a DTO here at that level.   Create bookmark the deal. Okay,  the tie the title should be   it should be first bookmark. And the link will be  Let's actually put a link to one of the videos of   Free Code Camp. I personally liked the  video, that guy who teaches keep your   needs are really well done, man. And I'm  going to save this URL in my bookmarks.   Here we go. And we put the DTO into our with body.   It should expect the status or two or one because  it's a post request. And let's see what it does.   Well, obviously it will do nothing, because  because we have not programmed the logic yet.   So let's go ahead and program the logic here this  create bookmark. So in the same fashion, we can   make it a sink and create our bookmark  const bookmark is equal await this prisoner   bookmark create data. And what do we put  here? First of all, the bookmark is created by   a user. So we can say user ID is equal user ID.  And then we can just destructor the detail. And   then we can return the bookmark to see what it  does. And let's see if our code executes. I'm   going to check here and inspect the, the,  the response, let's inspect the response.   And we see that we have, we have created the  first bookmark, it is linked to user ID nine,   which is the current ID and that is the  second bookmark. So if we do it again,   we see that the ID is three is because  while we're cleaning the database,   we're not cleaning everything, we just clean  the users table and the bookmarks table,   there's another table that keeps track of the  indexes. And that is not clean. And this is   normal, that is going to be incremented. But  that's okay. It's not a problem in our case.   And anyway, you should not in your test relate  to hard coded IDs, like here. So now we have   created a bookmark. And we can go here into  get bookmark and re execute the same code. So   let's go ahead here should get  bookmarks. And we can just copy it here.   And let's see that code executes. Okay, cool.   We had to get bookmarks and wish we  had that. And we can inspect that.   And we'll probably see that we have an array.  And in that array, there is our newly created   bookmark. So now we should have the get bookmarks  and expect the status 200. Yes. But now we know   that the body should be an array, and it should  be one element inside it. So what we can do   to make a very simple test is that expect Jason  length to be one. So we can expect the array of   bookmarks should have at least one element. So  that's that we can then proceed and write the   logic for getting the bookmark by ID. So the way  to do it is to simply should get bookmark by ID,   which will copy the tests that we have already.  So if we want to get a specific bookmark by ID,   we can write it like that. But we don't know  the it right? We weren't sure about it. Because   as I've just said, we don't reset the ID is the  that has been sequentially generated by Postgres,   for elements. So we need to keep track of the  bookmark ID that we have created somewhere.   So let's go ahead and where do we create it  should create bookmark, this is where we need   to use the stores API, like we have used for  user access token. So stores is going to be   book mark ID is going to put the ID field of  the bookmark inside it. So to use parameters   with Pakhtun, when to use their own kind  of way of doing so we need to the ad here   and with params with path params. And it's going  to be the key is going to be ID and the value is   going to be the value that we have saved in  our in our store. So let's see if that works.   Very well. But now let's write the logic.  Because we haven't written the logic yet. And   we have the function here, get bookmark by ID  is going to be pretty much the same. Apart from   we are going to use Find first. And we need to  get the bookmarklet that belongs to a certain ID.   And which ID is also a a bookmark ID provided  here. And let's go ahead here. Let's execute our,   our logic. And we see that  now we have the right answer.   And we can go back here and do some  basic assertions we can say expect   body contains and it's going to be what is it  going to be the value, the value is going to be   this number which will which is  which is going to be the bookmark ID.   Okay, let's see that works. Perfect. Let's now  finish it with edit bookmark by ID and delete   bookmark by it. Before we go any further.  Let's just examine if everything is correct,   get bookmarks. By user ID, that's fine. Get  bookmark by ID. Yes, that's okay. Create bookmark.   We pass the user ID and the DTO that's fine. And  edit bookmark by ID and this is where we need to   do a bit more work. So first of all, we need to be  get the bookmark by ID and then we need to check   if user owns the bookmark. And then only we  are going to do the modifications. So the   first part is quite simple bookmark is equal  await this prisoner bookmark, find unique,   where ID is called bookmark  it. And then if not bookmark,   or so the bookmark add specific ID does  not exist or if the user ID at the bookmark   is not equal to the user ID. That means  that is a bookmark that we try to edit   does not own to the current user, then we throw  an exception, throw a new, forbidden exception,   access to resource denied. That's it, and  the function should be an async function.   And we can clean that out, we don't need those  parentheses here, because we only have one   throw exception. And again, it's a god condition.  So it's going to stop the execution of our code   below. So if the bookmark belongs to the user,  then only we can modify the the user, then only   we can modify the bookmarks. So we will return  the modified bookmark this Prisma bookmark update,   where ID is called bookmark ID. And the data will  be DT Oh, okay, just destructure the DTO here,   and we can come back to our tests and just copy  our test here. should edit bookmark by ID should.   Edit bookmark is going to be a patch bookmarks  by ID year. And we need to take a detail.   So the detail is going to be here and the  to edit bookmark to and we're just going to   add the description. And the description was  actually the we're going to add the title and   and the description. So let's just copy this   and we pass that DTO to the body with body.   Here, we expect the status of 200. And let's  first execute it and inspect that to make sure   that we had the right things. Awesome, we had  right things and we can just expect the title   and description to the to build those values.  Let's I see that we have a whitespace here.   Let's expect body contains DTO dot  title. And same for detailed description.   Let's see our test. Awesome. That works.   And now let's run our last test. So usually when  you delete a resource status that is return is a   two or four. Let's see if we can we can actually  do that. So first of all should should delete   delete book, delete bookmark. So it's going to  bed delete with path params IDs with headers,   correct. We don't need any body. We  don't. And let's see if that works.   Okay, one thing that I like to use when I delete  resources, I like to have the code to have four.   So we're going to modify a bit HTTP code, like  we have seen before HTTP status, no content   which is which stands for code to have four. And  if we go back to the test and run them again,   we now have an error. We can  of course go ahead and just   modify that and we can return back to  our bookmark service and feel the last   logic here. And we don't want to return anything.  So it's going to be a sync function. While here,   we also need to check if the user owns the  bookmark. So we can just copy, copy it here.   And if the user owns a bookmark, then  we can go ahead and delete it. So await   this prisoner bookmark delete,  where ID is equal bookmark ID.   And that's pretty much it that will  delete our bookmark. Let's come back here.   And just after the Delete, let's make another  API request should get empty bookmark.   And what we can do is that we can just  copy the should get bookmarks here.   And and expect the Jason length to be to  be zero. Let's come back and run our tests.   And yeah, amazing. We now have a entwine tested  crud API with authentication. So I hope that you   enjoyed this tutorial that you have  learned something out of it. Of course,   there's a lot of stuff that we can still do. We  can work on security. When we deploy our API,   we can run it in the cluster mode through pm  two. And we can do a lot of amazing things   with that library called Ness GS. Furthermore, to  improve the code coverage of this app, we can add   integration testing and unit testing. But so  far, my mission here is accomplished. I have   taught you how to use NES Yes, and how to make  a solid use of its architecture. My name is   Vladimir, I hope you liked this tutorial,  and see you for more ad code with flutter
Info
Channel: freeCodeCamp.org
Views: 371,079
Rating: undefined out of 5
Keywords: nestjs, nestjs tutorial, nestjs crash course, nestjs api, nestjs rest api, nestjs jwt, nestjs authentication, nestjs access token, nestjs jwt guard, nestjs passport, nestjs passport jwt, nestjs prisma, nestjs e2e
Id: GHTA143_b-s
Channel Id: undefined
Length: 222min 9sec (13329 seconds)
Published: Tue Feb 22 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.