Introduction to Sequelize ORM (w/ Express.js + Postgres + Docker + Jest) | David Armendáriz | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Introduction to Sequelize ORM (w/ Express.js + Postgres + Docker + Jest)

teacher avatar David Armendáriz, #NeverStopLearning

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

58 Lessons (5h 22m)
    • 1. Introduction

      1:40
    • 2. Advise for Windows users

      5:20
    • 3. Installing Node with NVM

      4:14
    • 4. Installing Docker and Docker Compose

      4:22
    • 5. Installing Postman and DBeaver

      2:18
    • 6. Installing VSCode

      2:39
    • 7. The repo for this course

      1:34
    • 8. Initial setup

      6:29
    • 9. Adding all the dependencies

      5:07
    • 10. Configuring Babel, Jest and Nodemon and adding scripts

      5:43
    • 11. Creating and connecting to the database

      10:42
    • 12. Understanding JWT

      13:28
    • 13. Understanding Bcrypt

      9:10
    • 14. Adding Environment Variables

      9:05
    • 15. Adding JWT utils and tests for them

      10:55
    • 16. Creating the Database Class

      12:51
    • 17. Registering the models

      7:49
    • 18. Adding the server

      4:36
    • 19. Adding Tests Helpers

      4:11
    • 20. Models overview

      2:25
    • 21. Creating the User model (Part 1)

      9:22
    • 22. Creating the User model (Part 2)

      9:13
    • 23. Creating the User model (Part 3)

      5:52
    • 24. Creating the Role model

      2:18
    • 25. Adding Refresh Token model

      1:11
    • 26. Inspecting the new tables with DBeaver

      3:28
    • 27. Configuring the Sequelize CLI

      3:15
    • 28. Adding User Migration

      10:33
    • 29. Adding Role Migration

      7:59
    • 30. Adding Refresh Token Migration

      4:10
    • 31. Applying Migrations

      1:53
    • 32. Small improvement to the User model

      3:06
    • 33. Adding User model tests (Part 1)

      9:33
    • 34. Adding User model tests (Part 2)

      11:59
    • 35. Adding User model tests (Part 3)

      6:35
    • 36. Adding User model tests (Part 4)

      3:37
    • 37. Adding User model tests (Part 5)

      2:55
    • 38. Adding Role model tests

      6:56
    • 39. Creating the Express app

      5:25
    • 40. Creating the errors middleware

      2:28
    • 41. Creating an Async Wrapper for catching errors

      2:54
    • 42. Creating the Auth middleware

      5:52
    • 43. Structuring the controllers

      3:12
    • 44. Creating the register controller

      4:58
    • 45. Tests for the register controller

      11:27
    • 46. Adding the login controller

      6:56
    • 47. Adding a new test helper

      2:02
    • 48. Tests for the login controller

      9:22
    • 49. Adding the token controller

      4:15
    • 50. Token Controller Tests (Part 1)

      10:30
    • 51. Token Controller Tests (Part 2)

      4:03
    • 52. Adding the logout controller

      2:36
    • 53. Adding logout controller tests

      3:58
    • 54. Inspecting our coverage

      3:34
    • 55. Listening for connections

      1:18
    • 56. Testing our app manually with Postman

      4:02
    • 57. Using the debugger

      2:43
    • 58. Conclusion

      1:34
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

45

Students

--

Projects

About This Class

Hi and welcome to this course! In this course, you will learn A LOT about how to build a simple backend with production-level code. We are going to learn how to set up a local database with Docker, how to use Express.js with Sequelize as the ORM and manipulate the database, how to test our code and more importantly, how to structure our code to test it easily. We will also learn:

  • Sequelize best practices
  • JWT and Bcrypt
  • Testing with Jest
  • Express middlewares
  • Docker and Docker Compose

This course is different as I am looking for you to learn how production-level code looks like.

Meet Your Teacher

Teacher Profile Image

David Armendáriz

#NeverStopLearning

Teacher

Hi! I am David Armendáriz and I am an ecuadorian mathematician. I like everything related to Data Science and also I like to apply my knowledge in this topic to software.

See full profile

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hi, and welcome to the scores, building a simple authentication back in with NodeJS and SQL like, who am I? I am Debbie determine that is a software engineer and mathematician. I am from Ecuador. I have several courses in different platforms. I am AWS solutions architect certified. I love to teach into program in my spare time and I have a YouTube channel called Math as a second language way may discourse. If you haven't worked with relational databases. And I want to introduce you to them. In a job you're most likely to work with an Orion or object relational mapper to handle things like queries, insertions. If you have worked with relational databases and work with a Orem like Active Record for Ruby on Rails. Then this is to show you how easy life can be. I want to show you a pattern I use for my projects. Especially, I want to show you how my pattern allows for easy testing. And this brings us to the next point. I want to show you how to test and NodeJS app with just and super test. Remember that untested code is broken code. What are we going to build? A simple authentication backend, which is going to have login, logout, refresh tokens, access tokens register. And this sounds simple, but we have to do lots of things. What are we going to learn? Well, lots of things. Json, Web Tokens, cyclize, testing, expressed yes, Docker and best practices in general. So I hope you like this course as much as I enjoyed building it. See you in the next lecture. Bye bye. 2. Advise for Windows users: Hi and welcome back. So before we start coding, we need some tools, right? Well, here I have a list of tools. The first is actually not a tool, that piece of advice. And it's avoid windows when possible. So you will be telling me, Hey, why are you telling me DCT you are using Windows right now? Yeah, that's true. But I don't use windows of time. I use Linux all of the time, but I have problems with audio and video recording in Linux. So I have to admit that that is a big, big disadvantage. So I have decided to record this course in Windows. And that has been a challenge for me because I haven't used windows in a long time, and I have tried to customize it so that it feels more like Linux specifically to 12. And yeah, I have had luck with that. So first of all, Linux or MacOS are better in most of the cases for software development in general. And you totally need to be familiarized with Linux at some point in your career. The alternatives you have to install Windows Subsystem for Linux, which is the thing I have done and it's great. It feels like wounds or Linux. Any other Linux distro in general. And the other option is to install a Linux distro alongside Windows. It's pretty easy and you're not going to regret it. So let me show you very quickly what is Windows Subsystem for Linux. So if you go to Google and click on the first link, here you have all of the steps necessary to install Windows Subsystem for Linux and make sure to have Windows Subsystem for Linux 2 because it's the more up-to-date version of Windows Subsystem for Linux. And it's the one that works better, especially with Docker. Okay? And the second thing I have is this pretty look terminal. And basically this is the Windows Terminal, I think it's called, well, the thing is that you tie Windows Terminal on Google. And here you have these GitHub repo where you have all of the instructions to install it. I think I install it using the Microsoft App Store, so I think it's available there. And yeah, you have to only read this documentation. And here it says install of Windows Terminal from the Microsoft Store. So yeah, I was correct. You only have to install it there and there. There you have it. Okay. And as you can see, I have well, if you install this terminal, you're not going to have the same look and feel. And that is because as I said, I tried to customize it as much as I can to feel like my Ubuntu operating system. And I have all my zs H. And basically z is h is like bash, bash terminal, but it's for Mac OS. And there's this open source project, which is basically the SH, but open-source. So you can install it, you can install it in a Linux distro. And it's pretty, pretty simple and solid. This is totally optional. You just have to do this and you will have the SH up and running. So I think first you have to pseudo installed the as age and then run this command. And there you have. So as you can see here, it says, omens is H works best and MacOS or Linux, well, everything works best. Macos or Linux except for certain software like Adobe Photoshop. And these software I'm using contrast in order to record things. Yeah, that's some problem with Linux and macOS. You have better support for those kind of things, but for everything else related to software development, believe me, macOS or Linux is better. Okay? So yeah, this is totally optional. But you can do it, it's pretty, pretty cool. These omens TSH. But the important thing here, the key takeaway here is to install Windows Subsystem for Linux. Even docker works better if you install Windows Subsystem for Linux. And remember, it's even better to have Windows Subsystem for Linux 2. I want to be able to help you if you are not using Windows Subsystem for Linux 2, unfortunately, if you are using macOS, probably not be able also to help you because I don't have a Mac OS. If you're using Linux, that's totally fine. I will be able to help you. And if you're using Windows Subsystem for Linux 2, again, I'll be able to help you. Okay, so that's it for this video. Hope you like it. See you in the next lecture. Bye bye. 3. Installing Node with NVM: Hi and welcome back. So now that you have all the advantages and disadvantages of using windows, Let's go to the next point, which is node version manager. So obviously this is a NodeJS course, so we need node. And there are two ways of installing node. The first one is going to know G as an org. And here clicking on these long-term support version, or you want to use the latest, latest version with the latest features. You can click on here. Okay? And that will install Node.js on your machine. But I don't recommend this because if you are working on multiple projects, maybe you're taking another NodeJS. And NodeJS course has an older or newer version, I don't know. And you want to switch between these two classes, then you won't be able to do that because you have a stick with just one version of those. So in order to have multiple versions of nodes, there comes nvm, which is not personal manager. And in the about page it says, as you can see, and VM is Version Manager for Nadia, be installed per user and in both PowerShell, and then works in any POSIX compliant shell. In particular on these platforms, Unix, Mac OS, and Windows Subsystem for Linux. So it doesn't say Windows, it says Windows Subsystem for Linux. That's why I insist so much. You install Windows Subsystem for Linux. Again, if you don't do that, I won't be able to help you with the installation. Although there exists this NBN Windows, think. But again, this is complicated. Your self unnecessarily just install Windows Subsystem for Linux. Then you have to run this command. Again. You are using the ASH or OMICS age instead of bash. Then just replace this with TSH and then you are good to go. Okay, so if I open my terminal here and I type nvm, as you can see, I already copied and pasted this command. That's why I can use the npm command right here. So if I type nvm, this is going to show me all of the options I have available. And it's very, very easy to install versions of node, as you can see here. Just type npm install and the Persian, and that's it. And here, if you want to installed the latest, Well, not, not the latest, but a long-term support version. Just type npm install dash, dash LDS, and that's it. This is 14.17.4. I already installed it. That's why it says that this is already installed. And it's saying now using this version of nodes is you want to see all of the Persians available or the versions that you haven't sold type npm list. And here you can see I have this 14.17.114.17.4. And this arrow tells me that, hey, I am using this version 14.17% for right now. If you just want to display the version without one of these things, then just type npm current and it's going to show you the version. Okay? What else can I tell you if you want to use the other version, just type npm use and the other version. And there you have it. Okay, so it's very, very easy to NPM. There's no rocket science on this. Okay? And that's it. That's it for this video. Just one more thing. Executing this command is just going to put this script inside. In my case, it's going to be that CS HRC. Your case probably is going to be badger, see, if you are using Bash and so on. So that's it for this video. I hope you like it. See you in the next lecture. Bye bye. 4. Installing Docker and Docker Compose: Hi and welcome back, so we know how to use and BAM right now. Now the next tool we need and very important, docker and docker compose. So as you go and search on Google install Docker, the first link is going to get you through the documentation. And there are three ways in sold occur. Well for Mac, for Windows and Linux. And for Windows, it's very, very easy. You just go to Docker Desktop for Windows and click on this button and it will give you the installer, the EXE file to install Docker Desktop windows. And good news. If you install Docker desktop, if you're on a Mac or Windows, you're going to have Docker Compose automatically. So that's why it's very, very good. This Docker Desktop, I have to admit it. And here in the system requirements, again, you need Windows Subsystem for Linux to backend or this hyper be back-end and Windows containers. So I really don't know how to install it with these hyper, hyperboloid thing. I just install Windows Subsystem for Linux. And that's it. That's my solution. I don't want to complicate myself more with this hyperboloid thing. Okay? So as I said, these Docker Desktop includes docker-compose. And if you go and open here you can see the containers. And the apps wouldn't have any containers running yet. We have the images, the volumes that their environments, etc, etc. So yeah, I have here these images, for example, postgres, Kubernetes. And the thing here that I suppose are also related to Kubernetes volumes, volumes that I created about an hour ago. And I haven't used this Dev environments. It looks like this and new feature and I don't know what it is right now. So yeah. If you installed Docker desktop, then you are good to go. Now if you are a Linux user like me, then it's a little more complicated. For example, here you have to see which destroy you are using. For example, um, you see in Ubuntu. So for Ubuntu, you have to basically run all of these commands here. Okay, So run all of these things. And very important to go to the Linux post install. Okay? And again, run all of these commands. And here you didn't, you didn't have Docker Compose installed automatically. So you can go here to the left, it says Docker Compose, and here it says Installed compose. And if you go to these makin, so it says that this is already installed. Docker Desktop with Windows. It's the same story. And with Linux, you basically again need to run all of these commands. Okay? So although I have that Docker Desktop, think I'm still more accustomed to using the terminal. For example, to use Docker image alas and having all of the images docker ps to see that the containers that are running Docker volume allows us to see all of my volume. So again, this is like going into Docker desktop here. And volumes, these two volumes are going to be the same two bones here. But this isn't our command line. So image or less going to give me all of these things. And those are the same things I have Here. Okay, So that's it. It's very important that you have Docker and Docker Compose because we're going to create our databases using Docker compose. Okay, so that's it. See you in the next lecture. Bye bye. 5. Installing Postman and DBeaver: Hi and welcome back. So less than tools are postmen and dbVar. So they are very, very easy to install. Basically just go to Bozeman.com and here download the desktop app, Windows, Mac, or Linux. And if you're on, sorry, for dbVar, it's the same thing, dbVar dot io. And you can click here on Download. So basically postmen is at here an API platform for building and using APIs. Both man and simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs. So maybe it's an overkill that we are using postmen scores because we're only going to test manually. Our application was Bozeman by making some post requests. Obviously, we're also going to make tests, so we're not going to rely on 100% on, on postman. And yeah, so that's basically the only US that we're going to Postman and dbVar. Well, it's more interesting because this is GUI or graphical user interface too. Managed things in our database. So we can, for example, delete records in the database. We can connect obviously to database tables be the properties, et cetera, et cetera. And it supports these databases, MySQL, postgres, which is what we're going to use, and all of these other things. Okay, so basically again, just download it. And there you have, so here I have dbVar. So if I click here it's dbVar, and here I have footmen. And yeah, this is the graphical user interface. We need the steel to connect to the database. We haven't done that yet. And this is again, the graphical user interface for postman. Okay? So probably a viewer installed in Bozeman for the first time. You're going to be prompted to create an account. So just create an account with Google, whatever. And yeah. So yeah, that's it for this lesson. I hope you like it. See you in the next lecture that I. 6. Installing VSCode: Hi and welcome back. So there is one additional tool that I forgot to include here, but I haven't edited right now. And that is the code editor. Obviously, you can use whatever code editor you feel comfortable with. However, if you are on Windows and you are using a Windows Subsystem for Linux, then I strongly suggest use VS Code. And why is that? Well, VS Code is the best code editor with the, I mean, in terms of integration with Windows Subsystem for Linux. So if you go to code that Visual Studio.com, again, extremely easy to download installed. So download for Windows you also have MacOS, Linux, okay? And once you install the code editor, then you can go to this tutorial code that Visual Studio.com slash docs slash remote slash WSL dash tutorial. And you're going to see remote development in Windows Subsystem for Linux. And basically it's just installing this extension here. Okay, so if you click on this button, you're going to install it in VS Code. Okay? So if I open Visual Studio Code, open in my second monitor, so it's here and go to Extensions. You type WSL or remote dash. And WSL, you're going to need to solve this thing here. And then here you will have these icon which is open a remote window. You can click on this and here you will see that you are, You are now connected to the Windows Subsystem for Linux. And that means that it's like this code editor is inside, was opened inside your terminal. In fact, in the next video, we're going to see that if we open our wrapper from the terminal, from the Linux terminal, then you are going to be automatically connected to Windows Subsystem for Linux. So, yeah, that's why I like this a lot, because it's really simple to connect to Windows Subsystem for Linux again. And if you are on Linux or Mac OS, you don't have to worry too much about this. Just code in whatever code editor you feel more comfortable with. So that was this lesson. I hope you like it. See you in the next lecture. Bye bye. 7. The repo for this course: Hi and welcome back. So you have reached the end of this course. Congratulations. What have we learned here? Well, a lot. And probably the most important skill that I want you to have from now on is testing untested code is broken code. We also learned how to use the ORM. But it's not only SQL ice. If you go and use something like Active Record or type ORM, which is also a very famous hour and four note or any other or RAM in general, then you're going to see that there are things that are exactly similar. But with other syntax. We learned how to do migrations, how to configure models and configure the app in general, express we have learned, we have also learned the basics of JSON Web Tokens and how to use them. And in general, best practices. So we can still improve our code even more. But this is only an introductory course. And that's why we're going to end the courts here. I hope you have learned a lot here. I hope you like this course. See you in my next course. Bye bye. 8. Initial setup: Hi and welcome back. Now it's time to make the initial setup or four projects. So I am in the Linux terminal and I have repo where I save all of my rebels. So it's called rebels. And inside here I'm just going to create a new directory called SQL ice cores or something like that. And yeah, I already installed it. Some just going I already created it. Sorry. So I'm just going to delete it first. Ungraded again. Okay? So this is the command RM minus RF cyclized course to delete a folder and all of its contents. And this is the command to create a new folder. So if I type ls, then you're going to see that I have this folder called SQL ice cores. So let's cd into that and type COS an adult. So that means open Visual Studio code inside this directory. And as you can see here, this is what I was telling you. I'm already connected to Windows Subsystem for Linux. Okay, I can open a new terminal here. I have a shortcut for that. But if you didn't have that, then just go to terminal and type new terminal. And now I have these integrated terminal. So first thing I want to do is to initialize an empty Git repo in order to have source control. And the second thing I want to do is to create this file called and v MRC dot NVM RC. So here I'm just going to put the version of node that I want to use in this project. So remember I have distributions and these 14.17.4 was long-term support version. So I'm just going to put that. Okay. Now, if you type nvm use without any arguments, it has found these dot nvm RC file with this version. Then we're going to use this version here. So this command nvm use, you have to run it every time you open this folder. Okay? So actually if you are using ASH, there is a hook you can use in order to run these nvm. Use command automatically. If it finds this nvm RC. Let me show you like really quickly. Say char seem. So where it said here. As you can see, this is the hook, okay? But this only works with COSH, if you're using bash, probably you need to make your own investigation on how to do it. Again. So that's only an interesting fact. Now, let's create our package.json files. I'm just going to say npm dash y. Okay, so I have my package, that JSON file. And let's also add a README file. So it's always a good thing to have arrhythmia. And we're going to say cyclize course. And we're going to say here, pre requisites, requisites I have. That's spelled correctly. And we're going to say, Hey, I want MBM and Docker. So any other developer that is going to read this is going to say, Hey, I need an VM and Docker in order to use or work on this project. Okay, so that's it for our initial setup. Well, I think we need to still do some things here. So what I really like to do is to use a prettier in order to format my code. So here you can install, you can search prettier on the extensions and install it. I already have it, installed it. And also enabled Windows Subsystem for Linux. And once you install that, we can create a configuration file which is called prettier, our scene. Okay, so dark prettier. Actually, let me make this terminal a little bigger so you can see better. Okay? And inside this preacher RC, you can define whatever you want. I'm just going to say trailing comma that ES 5 is. I'm going to say I want semicolons, I want single quotes. So it is true. I want good prompts to be consistent. And I want to print width. I'm going to set it to 80. I want the tablet to be too. That's right. And those are the options that I'm going to set right now. Also, we need the gitignore file. So remember we're using nodes, so probably we're going to ignore the node modules folder because that's a very, very heavy folder. And within one that also we are going to have a coverage for tests. So we're going to build this coverage folder later in the course. So we're going to ignore that as well. And also we're going to ignore this dist folder, which is the build for our node project. And also I'm going to ignore this dot M file, which is environment variables File. We never want to put this into our source control. And that's why I'm just going to put it here. So don't worry, you're going to see all of these things being created later in the future. And for now, just put them here. You're going to thank me later. Okay. So that's it for this video. I'll be like it. See you in the next lecture. Bye bye. 9. Adding all the dependencies: Hi and welcome back. So now in this video we're going to install all the dependencies and deaf dependencies that we're going to need in our project. And I'm going to explain you very briefly why they are useful in our project. Okay? So first of all, let's start with the deaf dependencies. Again. I'm going to install npm install dash capital D. And first of all, we want to use modules, yes, ES6 modules. So for that, we already have support, native support. No, no GS 13, I think, already supports this. So from 13 onwards, ES6 modules are supported natively. But I have been experiments in these and they still have some problems. So I prefer to stick with the old way of using bubble and it's not that difficult anyway. So I'm just going to install for dev dependencies, which is the Babele CLI, the bubble core of Babel nose, and above all percentile. Okay? So we only need these four things in order to use ES6 modules again. And then we also need Jest, which is who our testing framework and types. Just don't forget about that. We also need super tests in order to make fake requests to our Express app. And finally, we need Norman so we can restart our app automatically when we are developing. Okay, So let's install this thing. And a quick note when he taps just because sometimes when we are developing, we didn't have, like, for example, we want to use an assertion, expect love of law to equal. And that to equal may not be available if we didn't have these types. Just library. Okay? So in the meantime here, these other terminal, I hope I'm just going to maximize it as much as I can. I'm going to install the dependencies. Not the death penalty is the real depends. So npm install and first of all, we're going to need decrypt be crypt. So decrypt actually is an algorithm. And this algorithm is going to help us to hash unsolved our passwords. So if you didn't know what that means, that worry, I'm going to explain it later. But basically this is for securing our password. Okay? Then we are going to need cyclize obviously. And that's what we're learning here. And SQL IC line, which is the CLI for life. And we also need JSON web token, which is a library to generate and refine these tokens. Again, remember we're going to use access tokens, um, first tokens, and both of them are going to be JSON Web Tokens. We also need pg, which is the driver for Postgres. We also need Express. Obviously, that's our framework. And we're going to use in order to use environment variables. Remember that in the gitignore, we added this dot m. Dot m is going to load all of those parallels in our application. And we also need Morgan. So this is optional if you want on the solid. This is for login our requests. So it's very useful on production. We also are going to need the CLS, which is going to help us to manage automatic, automatically transactions. So in relational databases, we have this concept of transactions. Basically, for example, if we're inserting multiple tables, inserting data into multiple tables, and one of these insertions fails, then we want the whole operation to fail. Okay? So that's when we roll back the transaction. If everything goes well, we commit the transaction. And if something goes wrong, we roll back the transaction. And we have consistency throughout, throughout our database because if something fails, everything fails. Okay, so those are the libraries that we're going to need. In the next lecture. We're going to configure Babele, note bon, and also just a hobby like it. See you in the next lecture. Bye bye. 10. Configuring Babel, Jest and Nodemon and adding scripts: Hi and welcome back. So now we're going to do two things here. The first one is to configure but L and just, and then build or write our script here. Okay, so first of all, let's create a file called Babele dot config. And another one called just that conflict. That's okay. So let's open these two things and it's very, very easy to configure this thing. So for Ravel, we're just going to type module.exports. And this is going to be an object and sets key, which is going to be an array of arrays. So tourists. And the first element is going to be this, add a bell, dash m. And the second is going to be an object saying with targets property. And this is going to be an object with a known property and we just say current. So yeah, that's the way to configure this year. And for just even easier, we just say module.exports, jazz environment. And that's it. For example, if we were building a UI like something with reacts rubbing, we need to put here browser, but we're using nodes, so we're going to say test environment. Okay, So that's all the configuration that we need to do to use ES modules and to start testing our code. Now we need to write our script. So let's start with this test here. So for the test we're going to execute just with these run in band command. And this desk watch is going to be the same. So npm test dash, dash, dash, dash watch. So if you don't know what this means, it basically means, after all, everything that comes to the right of these two dashes is going to be appended to the original command. So basically, this is equivalent to doing this just run band, dash, dash watch. So it's equivalent, but we are repeating code. We already have this just less than string bands, so let's reuse it. And the other test script that we want to write is coverage test column courage. So again, it's going to be the same thing, but we're going to pass this coverage flag here. Okay, so those are the scripts related to tests. Now related to starting the app developers debugging building. Okay, let's start doing that. So first for below, we're going to say, Hey, take everything from the source folder, which by the way, we haven't created yet, we can do it now if you want, make their source. So here's where our code is going to live. So take everything from there and compile it inside a folder called this. So remember that the gitignore, we put that folder in the gitignore. Yeah. So that's basically where the compiled code is going to live. When we want to start her. Okay, we want to run this slash server.js. So again, the savage or NodeJS doesn't exist yet, but it will exist. After somebody. For developing. We're going to say no, then we're going to set these environment, but will no doubt development, development. And we're going to execute node one, dash, dash x and that'll node. So that's why we installed this dev dependency. But note, and we're going to say server dot js source slash server.js. So obviously inside server, inside sorcery, we're going to create a file called server.js. That's going to be our entry file. And yeah, so that's what node 1 and Babylon is going to compile when we are developing our app. And there's one additional commands that we want to use, and that is the debug command. And basically we're going here to run npm, run dev. So this command here, dash, dash, dash, dash, inspect. Okay. So yeah, this is going to allow us to use, for example, Chrome developer tools in order to debug our code with all of the power of the Chrome Developer Tools or well, any other chromium based browser. Okay, so that's it. Those are all of the scripts that we are going to use in this course. So I hope you like it. See you in the next lecture. Bye bye. 11. Creating and connecting to the database: Hi and welcome back. So here comes the fun part. You seen Docker to create our database, our main database, and our test database. So actually, first, before green, these two databases, I wanted to show you this information here. So we have several testing strategies. The first one is to use a real database. With Docker, for example. You can also set it manually, but with occur it's much more easier. So women have all of those complications with auger. So what are the pros of doing this? Well, we're testing against a real database, so our tests are more reliable. And the cons is that it's more difficult to set up both locally and CI environments and also it may be a slower. The other alternative, which is in-memory databases. And the pros, is that it's easier to set up. It can be an NPM package. And the cons is that they simulate the real database, but they aren't database. So that's why they are called in-memory databases because everything is stored in memory. And the third option is SQL lite, which is a lightweight database. But it can also act as an in-memory database. And it's probably installed in most operating systems. For example, if you're using Linux, Ubuntu, and it's probably already, it comes with that. Also if you're, if you installed Python, I guess it also Python comes with its own version of SQL. And so it's very universal thing. And the pros, as I've said, it's very lightweight. The cons is that it's an prosperous and sometimes you can phase very challenging problems. Like for example, you are defining and schema here, but that's gamma is not compatible with your Postgres gamma and you have to do very nasty things in order to make them compatible. So in this course we're going to stick with the first approach, which is to use a real database in order to use with our tests. Okay, So that's the only information that you should be where you should be aware of. Okay, Um, so now that you are aware of that, we're going to create these Docker compose YAML file. Okay, so here I'm just going to say, Hey, use version three of the thing. And in the services, we're going to start defining our two databases. So the first service is going to be Postgres. You can name, you can name this whatever you want. And I'm going to say that the image is going to be postgres column 13. So this is the image and this is the tag. And the tag in this context means the version of Postgres that we're going to use. Okay? You can pathname to this for the container. So you can say container name, cyclize, dash, dash to me. This is optional if you want to have or not a container, a container name is up to you. And here comes the interesting part. So we are going to get all of the information from these dot M file, which we haven't created. In fact, let's create it right now. Okay? So now it's created and it's great because it's under gitignore. Remember, we don't want to put environment variables into our source control. So in the impairment, we're going to say Postgres password. We're going to say, Hey, take this from the db password environment variable. And if this is not set, well, just default to Postgres. So this colon dash means everything that goes to the right is going to be the default value. So here for example, I don't have any DB passwords environment variable. So it's going to take this as the default password. Then for the ports, I'm going to say, Hey, take the port specified in the DVI port. And if this is that specify in this dot M file, then just use 5432 and map it to 5432. So very important. This part here before the column here is the host ports. So basically the port of our machine. And this is a port of the container. Okay? So for the container it's always going to be 54324 here. This can be an important, obviously you're not going to use port 80 or port 22 because those are very important ports that you can use, something like 45, three. If you want, but I'm going to stick with 542. Okay, so this is going to be our first service, so our first database. And for the second database, and I'm just going to copy and paste. So this is going to be the database for our tests. I'm going to call it postgres dash test. And again it's going to be postgres 13 and SQL ice cores. Dash desktop. We have to change the name for the container name. And it's going to get everything from that EMF again. But instead of putting here, we're going to put here dv test that work to make it flexible. So if we have something here like DV tests backward, then it's going to take for example, tests or some like that. Then it's going to take that as a password. And if this American Bible is not set, then we're just going to say that the default password for this test database is going to be parsers. And for the port, this is going to be the same, but let's put this David test or to make it different. If this is not set, then we're going to say 54, 33 because this has to be different from this one. Because we're going to, we're going to have these two databases at the same time so they can't have the same port. Okay, So that's everything for our Docker. Compose YAML files. So as you can see, extremely easy to set up a database locally with Docker. Now we can simply run this command, Docker Compose up minus d. And the first time for you it's going to take awhile because probably didn't have these images. Download it. I already did have this downloaded. And then I can type docker ps. And here I have my two containers running. Also if you're using a Windows or Mac, or you will probably have Docker desktop. And here you will have this thing here. And here are your database, your sword or two containers. And those match this one. Okay, so now we have two databases. Now we can connect to these two databases. In fact, let's open dbVar here and here in these new database connection, select Postgres. And again, the first time probably for you, it's going to download some drivers or something like that. So just click on Accept and download the drivers. And here I have the host localhost port 5, 4, 3, 2. That's correct. The database Postgres, that's correct. Authentication, database name, username, and a password. Well, it's going to be Postgres because we haven't said anything here in these dot M file. So it's going to be the default password, which is Postgres. Okay? And I think that's it. We can test a connection and yet connected in 236 milliseconds. So we're going to finish and, but before doing that, let me see if there is an option here to change the name, I guess trace. And here, connection. Here where it says connection details, click on this button. And here I can put main database, main underscore database, or cyclize. Underscore core's main DV, whatever you want, really, I just want to have a pretty name here. Let's make another connection, again to Postgres, but this time to port 54, 33. And the password, again, it's going to be Postgres in the connection details. I'm going to say cyclize underscore corps, underscore test db or whatever you want. Okay, so now we have these two databases. So we have this database postgres with this schema. Public women have any tables yet. And the same thing applies for this test database. Okay, So that's it. We want to be doing too much with this database, are going to focus more on the main database. But we're going to still have both of these connections here. So you can disconnect if you one from both of them. And that's it. That's how you use dbVar to connect to a database. And if we were you seen, I don't know anything else. It will be more difficult. But with Docker, this is very, very simple. So the third, hope you liked this video. See you in the next lecture. Bye bye. 12. Understanding JWT: Hi and welcome back. So before we start coding, we need to understand two important concepts. Because remember this, some authentication backends. So we need to understand what security measures are we going to use here. So the first concept is JSON Web Tokens. Remember in the intro of these curves I said we're going to have access tokens and refresh tokens. And those are going to be basically JSON Web Tokens. And JSON web token is an open standard that defines a compact and self-contained way for securely transmitting information between parties. As it takes an object. In our case, the parties are going to be the front end, back-end, or the client and the backend. In our case, the client is just going to be postman or something like that. We're not going to build a UI for this. And this information can be verified and trusted because it is digitally signed. And JWTs can be scientists in a secret with the bank algorithm or a public-private key pair using RSA or ECDSA. Although JWTs can be encrypted to also provide secrecy between parties. We will focus on sign tokens, and that's also our case. We are not going to encrypt any token here. Sign tokens can verify the integrity of the claims contained within it. Well, encrypted tokens hide those planes from other parties. And with tokens are scientists in public-private key pair as the signature also certifies that only the party holding the private key is the one that signed. So as you can see, there's a lot of complexity behind how JSON Web Tokens work. So fortunately, we have this JSON Web Token package that is going to hide all of that complexity for us. And we're just going to generate images, what tokens and verify them. That's why I said in the beginning of the course that is not going to be our main focus. And here are some scenarios where JSON Web Tokens are useful authorization. This is the most common scenario for using JWT. Once the user is logged in, subsequent requests will include the JWT, allowing the user to access routes, services, and resources that are permitted with that Tokyo. We're going to actually in this course build a middleware that is going to make the verification of this JSON Web Tokens just as described here. And single sign-on is a feature that widely uses JWT nowadays because of its small overhead and its ability to be easily used across different domains. So again, that's very important. Json Web Tokens are very easy to use. They are stateless. On normal, not like cookies, they are stateful. So that's why JSON Web Tokens are very used nowadays. And the other scenario where this JSON Web Tokens are a good way. A good use case is for information exchange. So this Web Tokens are a good way of securely transmitting information between parties because JWTs can be signed, for example, using public, private key pairs. And you can be sure the centers are who they say they are. And additionally, at the signature is calculated this in the header and the payload you can also provided a content hasn't been tampered with. So this is also very useful, for example, for a contract. Suppose you have digital contract and you want to make sure that this contract, contract hasn't been tampered. So yes, No web tokens are the way to go for this. Okay, So what is the JSON Web Token structure? This is what is the most important thing here. Json Web Token consists of three parts separated by dots, the header, payload, and signature. So this is the format XXXX. X is going to be the header, YY, PYY is going to be the payload, and it's going to be the signature. The header is just going to consist of two parts. Typically, the type of the token, which is this CYP property, and the signing algorithm being used, such as HMac, SHA 256 or ISA. So here it's using it or HMac SHA 256. And then this object here is encoded in base 64. And that is going to be this part. X x, x, x x, that is going to be the base-64. It's going to be this base-64. The payload is the second part of the token that is very important for us because we're going to build payloads in this course. This contains the claims. And claims are statements about an entity, typically the user, and additional data. There are three types of planes, registered, public and private. Register. These are the set of predefined claims which are not mandatory but recommended to provide a set of useful inter operable claims. Some of them are the issuer, the expiration time to JSON Web Token at the subject and the audience and others that you can click here and basically see all of them. Well, looks like the link is not working right now. Probably tomorrow's working. Now it's working right now. So here there are issues. The issuer, the subject, the audience expression time. For example, not before issued at the JSON Web Token ID, etc, etc. So these are very useful. One for the access token, the expiration time, the public lanes. This can be defined as will be seen by those using JWTs, but avoid collisions. They shall be defined in the JSON Web Token registry or be defined as a URI that contains a collision resistant namespace. The namespace, Sorry. So basically those are these ones. For example, we're going to use the email and the email is going to be unique. So this going to be collision resistant if that's the term. And if it can, for example, be somehow duplicate it, then we just defined a URI that contains our collision resistant namespace. So that means prefixing these with some, something that is not going to be that is going to be very unique. Okay. So and then we have the private claims, and these are the custom claims cred to share information between parties that agreement is in them and are neither register our public claims. So basically, private claims can be whatever. Again, and this is an example of a payload. The subject name, the admin, which is a role. And then the payload again is encoded in basic civil war. And that will be the why, why, why, why part of the diesel Web Token. And the third part is the signature. And that is very easy to calculate. You just have to pass to your algorithm. For example here or using HMac SHA 256, you pass a header encoded in basic four plus dot plus the base-64 version of the payload. And the secret as the third arguments. And now that's it. That's going to be part of the decimal episode. And the signature, as we already saw, is used to verify the message, that the message wasn't changed along the way. And in the case of tokens signed with a private key, it can also verify that the center of the JWT is who it's acidic. So if we put everything together, put everything the XX XYY ends at, at, at, pardon, this is going to be that JSON Web Token. And this JWT page has a very cool feature. So for example, this JSON Web Token, and this is the decoded version of the JSON Web Token. And this the algorithm used. Here, it's specified also in the header. So you seen HMac SHA 256. Okay, so that's how the JSON, JSON Web Tokens work. This is also important for us. So let's review it. Authentication, when the user successfully logs using their credentials, a JSON web token will be returned. So very, very important because this is how we're going to design our controllers. Since tokens are credentials, great care must be taken to prevent security issues. In general, you should not keep tokens longer than required. That's why we are going to expire our JSON web token. You also shall not store sensitisation data browser storage due to lack of security. So what does this mean? We're going to keep this access token number first token in the client, in something like local storage for example. So anything and the client is basically unsecure. So we don't have to store sensitive data in this JSON Web Tokens because they're going to be stored in the client and the client is unsecured. And whenever the user wants to access a protected route or resource, the user agent should send the JWT, typically in the authorization header using the beaver schema, basically the various commands saying bidder and a space and the token JSON web token. So this is the content of the header. The header should look like the following. Okay? And this can be in certain key says a stateless authorization mechanism. So some minutes ago I said that JSON Web Token is stateless, but we can still put this on web tokens and cookies, making, making them stateful. So in certain cases, stateless of irritation, authorization mechanism can be made. And by the way, we're going to use, but we're going to make our backend stateless. We're not going to use any kind of cookies or anything like that. So the servers protected route would check for valid JWT in the authorization header. And if it's present, the user will be allowed to access protected resource resources. And if the JWT contains the necessary data, the need to create a database for certain operations may be reduced, though this may not always be the case. So in our case, we are going to steer and make a curated database using the email field that is going to be present in the JSON web token. Okay? And if the token is sent in the authorization header, course won't be an issue as it doesn't use cookies. Cookies are more complex. In my opinion. These are the reasons of why analgesia. Oh, why should we use yes-no Web Tokens? Let's read something here. So let's talk about the benefits when compared to simple web tokens or UN Security Assertion Markup Language. So can some are short, as Jason is less verbose and xml, when it is encoded, it sizes smaller, making Jay Della team or compact that somehow. And this makes JWT a good choice to be passed in HTML and HTTP environments. Security wise, as w t can only be symmetrically signed by shared secret is in the HMac algorithm. And you can read more about this more ten, more technical decent parsers. This important decent partners, sorry, are common in most programming languages because they mapped directly to object. Conversely, XML doesn't have a natural document to object mapping. And these make it easier to work with JWT than, than SAML assertions. So remember some of our uses XML. So that's why didn't the team uses JSON? And it We're sorry. So yeah, that's it. That's a brief summary of jsonwebtoken, sir. People that dedicate their lives to security and things like that. But this is a very good summary of it. So hope you liked this lecture. If you have doubts, then don't hesitate to ask questions and see you in the next lecture. Bye bye. 13. Understanding Bcrypt: Hi and welcome back. So now that we understand the basics of JSON Web Tokens, Let's understand decrypt. So first of all, here I am in these blog posts from these TWO was also a page or a website grilled by 00 is a great company. It from Argentina, but they managed to be unicorns. So they are valued at more than $1 billion and they are great at security. So here in this blog post they say in previous balls, we learned that password in plain, plain text never be an option. And that's totally true. You never, never, in your mind have to think, Hey, what happens if I save this password as plain text password, that that should never be an option. And I emphasize this because I know senior developers that have saved passwords in plain text and for financial institutions. So if you don't believe me, yeah, I have seen that. So instead we want to provide the one-way road security by hashing passwords. Okay, So hashing basically means to encrypt the password somehow. However, we also explore that hashing alone is not sufficient to mitigate more tags such as rainbow tables. So what our rainbow tables? Well, basically, let's first understand what happens if we only hashed password and that's it. So suppose my password is tests wanted three exclamation mark. And then if we hash the password, then this is going to be a random string. Sounds like this, okay, with numbers, things like that. Okay? So if a user uses this password, is going to have this hashed password. But suppose that username, so user, this user one and user two uses the same password. It can happen, and they will have the same hash, okay? So a hacker is going to have all of these hashes are stored and mapped to these passwords. So basically they're going to have like an object, unlike something like this. And this is going to be this way. So this value is going to correspond to this. So if a hacker goes and reaches your database and sees that the password is this, then they're going to see, Hey, these user has this password so they can login to your account and make bad things with them. Okay, so that's a rainbow table basically. So a better way to store password is to add salt to the hashing process. So I close that, but let's do it again. So this is a one. It's going to have this password here. Again, a random string. And user 2 is going to have the same password. But if we add assault, so for example, assault can be timestamp. And that timestamp can be encoded and like that. So this is this out and this also another salt which is going to be different. Now, these two things are totally different. So the, sorry, the hacker can, can tell if lead that is dissolved because probably the, the hashes this and made it solves this. So in short, more complicated for the hacker to know your password. However, it's still not sufficient to have salt. So it says here that the ideal authentication platform will integrate these two processes, hashing and salting seamlessly. And there are plenty of cryptographic functions to choose from, such as the shard to find me, and the shattering family. However, one the sign problem with the Schar families is that they were the scientific computationally fast. So the SHA 256 algorithm is part of these sharp feminists. So they are fast to compute. And how fast the cryptographic function can calculate. The hash has an immediate and significant bearing on how safe the puzzle is. Faster calculations means. Brute force attacks, for example, modern hardware in the form of CPUs and GPUs called cool compute, millions, or even millions, billions of shot 256 hashes per second against a stolen database. Instead of a fast function, we need a function that is lowered hashing passwords to bring a taggers almost to a halt. We also want this function to be adaptive so that we can compensate, compensate for future faster hard work by being able to make the function or slower and slower over time. So here at Global Law, we do things well. Well, the motivation behind is a technology changes faster. In some years, we probably are going to have quantum computers. So increasing the speed and power of computers can benefit both the engineers trying to build software systems and also the attackers trying to exploit them. And some cryptographic software is not a scientist scale with computing power, as explained earlier. And the safety of a buzzword depends on how fast this leg cryptographic hashing function and calculate the password hash function called World execute faster when running. Much more powerful. And if you don't believe me, just look at Crypto, Crypto mining with pulse. That's insane, the computational power they have. And when I say insane, It's insane really. And to mitigate this attack vector, we call create a cryptographic hash function that can be 10 to run slower in newly available. That is, the function scales with the computing power. And this is particularly important in through this attack vector, people tend to get the length of the password constants. So that's here in 10 years you're going to have your same my dog on your birthday as your password. Passwords length are constant. Hence, the design of a cryptographic solution for this problem, we must account for rapidly evolving our own custom password length. And that is where decrypt comes in. So Big Rip was assigned, but this guy, Neil's promise, he actually thinks he has a tutor. Tutor. So this guy, thank you. And bead measures. Again. This guy has he has only 2 thousand and forwards. That's very little for how much he has achieved. And again, 400 thousand forward, very, very little. But these two guys are gods because they designed this big red thing based on the Blowfish. Cipher. B for bold Blowfish and script for the name of the hashing function is by the Unix password system. So again, we go to unix. And yeah, so you can read more about this. It's a long article, but again, the key takeaway from this is that these decrypt algorithm is intended to be low and it can be slower if we say so. And that will be beneficial because the years are going to pass and Harvard's going to be more and more fast. So we need a way to avoid, avoid that these fast cryptographic functions. So yeah, that's the key takeaway from this. I hope you liked this video. See you in the next lecture. Bye bye. 14. Adding Environment Variables: Hi and welcome back. Well now we have the notions of snow up to the enzyme to start. Well, first of all, we need to make some configurations, right? So instead folder, I'm just going to create a config file. Sorry, a config folder. Inside the config file, sorry, coffee folder. We're going to have three files. The first one is going to be index that ds. And this is going to be very easy. We're just going to import data from these data. And I were going to say dot. Okay, so we're going to import this file here inside our server, but that is going to be in the future. We're not going to do it right now. So yeah, this is going to be the entry file for this config directory. This second file we're going to create is the database database study. Yes. And here we're going to use module.exports. And we're basically not easy in here. Yes, six exports. So like something like this. However, this in this because this file's going to be used by RC file. And that file also uses all JavaScript syntax. So it's very anatomists too much with that. So I'm just going to use it like this. Also. It's no harm in doing that, doing it like this. And this needs that development and test. Also, if you plan to deploy the production unit, production key here. But for now we're just going to have development and test properties and the subject. And we need the username. And we're going to get it from processes that TV username. And if this is not pass, well, let's just use phosphorus. We need also a password. Again process of passwords. And again, if this is not passed, just use Postgres has the password host. It's going to be processed that ends that TV host. And again, if this is not provided, use local host. For the port, we're going to parse int, process the EMF that TV parts. And if this isn't an ASD, again, 5, 4, 3, 2, for the database and processes that have that DB database. And if this is not passed is Postgres. And for the dialect, we're going to use phosphorus. Okay, so that's great. Now here for tests for just copy and paste. Here we're just going to say David tests the tests. Test, test and the test. Just as we did in docker Composer. Remember, here we're using new test password. Here we're using the equivalent of this but with the test. Okay. And here we changed it to 54, 33. And a tip, that's the config object, which we're going to use for the database. And also, I'm going to create a third file here, which is going to be called an environment ab.js. And this is going to contain all of our environmental variables. So Let's export default, this object here. So the port, which is going to be the port for our express application, again, bars in process that after ports. And if this is not provided, we're going to use 8080. Now know them. This is going to be processed that F, that no EMF. Remember in our package.json we said that Noemi, environment Bible also this node have environmental parable for just a test. But we're going to use ILO production here if this is not passed. So for example, if we make a deploy to production and for some reason is not passed, and then use these by default. Then we're going to provide also the South around, which is an integer, salt rounds. And if this is not provided, then put these two value that is suitable for production can be 10, 14. Those are common values for production. Again, if we make a deployed to production and we forget. To put these sub rounds and defaulted to a reasonable body. Maybe we want to modify this in the file for development because this salt rounds is for the big crypto algorithm. And it basically is, basically tells that the difficulty of the hashing function. So if this number is higher than it's going to be more and more slow the operation. And if this is lower than it's going to be faster to hash the password. Okay? And we also need the team access token secret. So remember the access token is going to be a JSON Web Token. And for that we need Secret. Remember that HMac SHA 256 algorithm that needed a secret? Well, we're going to provide a secret here as an environment variable, JWT, token, secret. And if this is not passed, for example, in development, are maybe in production as well. Well, we can use a random string and for that I'm just going to type here in the terminal nodes. And I'm going to say require crypto. So crypto is a library that comes with node. Okay? And we can say crypto that run them by 32 random BY, and convert this string by using this hexadecimal. Yeah, we have a random string there. So let's copy this and paste it here. Then we have a random string and we need also an axis, sorry, as a secret for the refresh token. So we're going to say JWT refresh token secret and process of m, that JWT refresh token secret. And again, we can generate another random string, provide any in the dot M file. So there you have it. We have now these Environment Object, which we're going to use in our controllers. Maybe not in our controllers, not a best practice, things like that, but maybe in other parts of our app again. So this is a best practice. Why? Because we are defaulting things here inside this, inside this file. So for example, if environment variable needs further processing, here it's a simple processing. We're just parsing the string to an integer. But if this needs more complex processing, then everything can be done in this file again. And then we don't have to check for undefined or four known when we're using these environment variables. So that's why this is a best practice. If you are using TypeScript, then believe me, it is going to be very, very useful. So the Fed hope you like this video and see you in the next lecture. Bye bye. 15. Adding JWT utils and tests for them: Hi and welcome back. Now that we have our environment parables in place, Let's start by adding some decent Web Token utils. So we're going to generate four methods. Generate access token and refresh token, verify access token and verify refresh token. Okay, so let's start doing that inside source and create a new folder called utils. Utils, I'm going to create a file called JWT dash QTLs that. So here I'm just going to import JWT from the JSON Web Token package. I'm also going to import environment from config environments. And I'm going to export default or default a class called data. So that's my way of generating utility functions. You can also do it by simply exporting functions, but I'd like to do it like this. So I'm going to say static generate access token. And it's going to receive a payload and some options which we're going to default to an empty object. So disruptions is going to have these expires, expires in property. And if this is not passed, then we're going to say, Hey, make this JSON Web Token, this access token experiment in one day. This is really up to you and your application. And we're just going to return a JWT, that sign. Okay? And as you can see here in the signature of the function, we need a payload, which can be string or an object, or a buffer object. So let's pass the payload, which is going to be an object. The second argument needs to be the secret or private. So in our case we have a secret and that's an environment that JWT access token secret. And the third option is this JWT dot sine absence. So we control-click here or Command click, I think it's a Mac. It's going to redirect us to the index dot js file, which is basically the types of these JSON Web Token library and hearing options. You can see that first of all, it's optional. And here is the interface for this sign options. So here we have the algorithm to use the KD, the Expressen, which is what we're going to pass. And that can be string in number or undefined. And you can see we have lots of options here, like the JSON Web Token ID, subject Aryans that before mutate payload, things like that. But we're just going to pass here. The expires. Okay? So now we have these generate access token method. And then we're going to generate, we're going to write a refresh token method, which again is going to make payload. And again, we're just going to return JWT, sign payload and environments that JWT refers to consecrate. So here we're not going to make this expire because the refresh token, by definition is a token that we need in order to create another access token. Obviously, obviously we can make these expired or refresh tokens well, OK, and there are certain strategies. For example, make it experiment one month or in two weeks, a long period of time. So, yeah, but we're not going to add more complexity because our application is already break complex as you will see. Okay, so you might be saying, Hey, why are you not merging these two things in a single method? And my reasoning behind this is a, maybe the generate access token has more logic that is independent from the degenerate refresh token. And that's why I'm going to keep them separated. Again. And the same logic applies these two methods that I'm just about to write. And those are the verify access token, which is the axis, which is going to receive the access token. And it's going to return JWT, verify access token. And we need the secret as the second argument. So that will be the JWT access token. We'll just copy and paste this thing here and replace this for peripheral refresh token. And this is going to be environment that data, the t refresh token. Okay, so I think this is everything we need to do for our JWT utils. Now let's add some tests for this. So we'll start making our test for this. So first of all, I'm going to keep all of the tests in another folder called task. So some people like to put the test just in the same folder where we define the uterus or whatever file it is. But I like to do it in a separate folder that follows the same structure as the source folder. So for example, here I'm going to have again uterus folder. And here I'm going to have JWT UT Austin test.js. Ok. So here we're just going to import again from JSON Web Token. So we're still going to use this library here, basically for having some errors. You're going to see why what we're going to use this in a moment. And we're also going to obviously import data from whatever path it is. So yeah, this path. So let's start by putting a describe block here. And in the describe block we're going to see JWT. Okay? Okay, So, okay, so I have this thing here. Now, let's say it should return an access token. And this should be something like this, like this. And here I'm just going to have a payload, which is going to have an email, for example, desktop example that come. And the assertion will be expect DWT new tools that generate access token. We put the payload and this needs to equal. You can expect any string here. So that will be a test, not very useful test, but it still does. And these, it should return a refresh token. The refresh token. And let's start seeing if this test passes by running npm run test watch. Okay, so our two tests are passing. Now let's make some more interesting task. Let's say it should verify that the access token is valid. So for that, we're going to again generate the payload. Let's copy and paste. And let's generate the JSON web token with generate access token. And we pass the payload and let expect JWT UTS, the verify access token as a decimal. And this needs to equal an object. So we're going to expect an object containing the payload. Okay? So this test is passing. Let's do the same but for the refresh token. So let's replace everything here with refreshToken. Verify. First again. Again, our four tests are passing, so that's great. Now let's make another two tests. And they are going to be these ones. It should error if the axis can ease imbalance. So we're going to expect, and here we need to pass a callback with JWT utils. Utils that verify access token. And here we can pass any random strings, I'm going to say but token. And we need to verify that this is going to throw JWT dot JSON Web Token error. So basically, that's why we imported this JSON Web Token here. And just marijuana, it show error if the refresh token is valid. Here, prefer first token, and there you have it. Now we have six tests that are passing. So that's it for our JWT utils. Hope you liked this video. See you in the next lecture. Bye bye. 16. Creating the Database Class: Hi and welcome back. So now we have utils that we're losing sales, environment Bibles, and it's time to set up our database connection. So for that, again, we're going to use a class in order to create the database class that handles these collection. So here inside source, let's create the database folder. And here let's create an index.js file again. So I'm going to export default this database class. And this database class is going to have a constructor, are going to see what's it but what to put in this chapter. So our export default class, it's going to have a sink connect method is going to handle the connection. It's also going to have a disconnect methods. And it's also going to have an sink method. Okay, so that's everything that our class is going to have. So first of all, in the constructor, we're going to pass the environments. So these can be Test, Production, development, whatever, and the DB config. Okay? So basically it is dv Caltech is going to be where it said these database objects. Okay, but we're going to inject it here. It's a good practice to do that. And we're going to say these are the environment is going to be environment and this is going to be what to become. Again. And we're going to create an additional instance variable, which is going to be called East test environment. So we're just going to say this, that environment SQL tests. So this is a Boolean saying that if this death environment and is going to be true, otherwise it's going to be false. We're creating this variable because it's going to be useful for, for example, for logging. Okay, So for the connect method, which is the most complex one, we're going to first of all, set up the namespace for transaction. For transactions. So remember that we are using this where I said, yeah, CLS hooked a package. So we need to use it right here. So for that, I'm just going to import CLS from sellers who also lets us import. Now that we're here from SQL, eyes are going to import this SQL ice. These are glass. And also, yeah, these are the things that we're going to import right now. And we're going to say const namespace that read namespace transactions. So you can put whatever here. Now we're going to say SQL eyes that use CLS and namespace. So by the way, why are we doing this? Well, basically, if we go to the documentation, so let me open here sql ice. Whereas it cyclized transactions. Search for that in Google. Then you're going to go to the documentation. And it says here that SQL does not use transactions by default. However, for production ready is that cyclized issue definitely configure PSI-BLAST sections. And there are two types, the unmanaged transactions and basically committing and rolling back manually and managed transactions. So SQL eyes will automatically roll back the transaction if any error is thrown or committed transaction otherwise. Also, if CLS, which is what we're using and it's continuation, local storage is enable. All queries within the transaction. Kohlberg will automatically receive that transaction object. So that's what we want. And basically it's this part here, automatically past transactions to all parties. So basically we need to do this, create a namespace and then use this, use CLS methods from civilized and pass that method. And that's it. Now we have transactions, we have past transactions to occur is automatically. So that's great. And that's what we are doing here. Okay? So after we do that, we need to actually create the collection to create connection. And here we're going to get from that deme config. We're going to access these that environment. So remember, if environment is Whereas it, so remember that this David config, sorry, this, that David config is going to be the subjects and these data environments can be, can be tested. So this, that direct conflict. In square brackets, this data environments going to have all of this information here. Okay, So we can deconstruct and the username, the password, hosts, the port and database. And then we're going to say is that connection is equal to new SQL ice. And here we pass all of the options, username, password, host, port, database, also dialect. Dialect. Yeah, So we can pass all of these options as well as these Login option. So basically this login action either receive false or it receives a function that is going to be used for logging queries. So you're going to see that in the future. So this is des environments. So it doesn't environment. We don't want to log queries because it's going to pollute our tests. So if we're interested, environment login is false, otherwise these cancel out. In order to log the queries, which are very useful. Okay? So now that we have created a connection, we need to check if we connected successfully. Okay? And for that we're going to say away, is that connection that offended? And for this it makes a simple query like select one plus one or some like that. We don't want to see that we're in. So we're going to see, we're going to say login false. And if we are not in the test environment. So if this is tes environment is true. We're not in a test environment. We're going to say Cancel. Connection to the database has been established successfully. And yeah, so we connected to the database and successfully. Then we need to register the models. And right now, we're not going to do this in this video. Okay? I'm just going to say that here we need to call a function called register models with the connection as the argument. Okay? And this register models needs to be in another folder. And in an R5 can be a mess here. And you're going to see why later. And finally, we need to sync the models. And for that we're going to call this dots. So remember this is this method here that we haven't implemented yet. So first of all, let's implement this disconnect method. I'm just going to say this, that connection close. And for the sync method, we're going, this more interesting. We're going to wait. Is that connection, that thing? Okay? And again, this makes some queries. We don't want to see those queries. And these assets, this force attributes. And we're going to set this to East test environment. So we're only going to force, if this is us, this is test environments equals true. And I'm going to explain this in a moment. And here, if we're not in a test environment, we're just going to say models, synchronized, or connections in production saying whatever message you want to put here is valid. Okay, so let's go again to the documentation here and search for the sync. Let's, let's just go to Google and say sync. And here we have what I was looking for. And let's read this. When you define a model, you're telling cyclized a few things about if stable independent bass have a, however, what if the table actually doesn't even exist in the database? What if it exists, but it has different columns, less columns, or any other difference is where models synchronization comes in. A model can be synchronized with the database by calling this model dancing and asynchronous function that returns a promise. And with this call, cyclize will automatically perform SQL query to the database and know that these changes on the table in the database, not the model into JavaScript side. Okay? So it says here, for example, that you recall think without any arguments is going to create the table if it doesn't exist and does nothing if it already exists. If we pass forced through, this, greets the table, dropping it first, if it already existed. And if we pad with alter equals to true, this checks what is the current state of the table in the database, which columns it has? What are the data types, and then performs the necessary changes in the table to make it match the model. So in production, we don't want the RAM to determine the table should be created and things like that. That's why we're going to create migrations for our tables. Again. But we still want is forced through four more, four tests. Because for each test we want a clean database. Again, we wouldn't want pollution between tests of the database. So that's why this force is good for tests and obviously not good for, not good for, for production. Okay? That's it. That's what we're going to code right now. Now in the next video, we're going to code this register models function. And yeah, that's it. I hope you liked this video. See you in the next lecture. Bye bye. 17. Registering the models: Hi and welcome back. So we have created these database class that is going to handle our connection to the database. And we are missing these register models function that we need to grade. Okay, but first, what is this register models function? What is, what is it going to do? Well, it's going to do two things. Basically. The first thing, it's going to put all of the models inside an object, which we're going to call the models object. Okay? So the keys of these objects are going to be the name of the models and the values are going to be that class representing the mothers. Okay, so that's the first thing that these register models is going to do. And the second thing is it's going to call the associate static method from each of these classes representing the models. And this associate method is going to say, hey, for example, this model has a relationship, I want to one relationship with these other model. And this model belongs to this model, or this model has a one-to-many relationship with this other model. So those are the associations that we are going to register in these static method called Associates. Okay, So without further ado, let's start doing this. Let's create a folder called models. So here in this folder we're going to have an entry file. So it's going to be index.js. And then we're going to have the other files are going to represent the models that represent each of our tables in the database. Okay, so we are going to import fs from fs, which is filesystem, a library that comes with node i. We're going to also import from path. Then we're going to create these models objects. And this is the, this is the object that we are going to populate with classes that represent our models. Then we're going to call export function. We're going to write sport function register models. Okay? And remember this needs a SQL connection. So that's the first parameter of this function. And then we're going to save this file is going to be path that base name, filename. So finally means that the path of this file. So if I go here and say Copy path and file name is going to be equal to this thing here. And pass that by base name. Filename is going to be only this part here, so only index.js. And then we're going to read all of the files inside this folder. So we're going to use fs, red deer sync. And we're going to pass journey. So dear name is going to be again, the path of these models folder and read your sink is a function to read all of the files inside that folder. Then we're going to filter all of the model files or going to see filtered model files. And it is going to equal to muddle files, that filter file. And here we're going to return a condition if file is different from these file and file, that is lies, Sorry, file slice minus 3 is equal to dot js. So let me see. Oh, I'm missing here, this thing here. Okay. So what basically I'm saying here is read all of the files that are not this file. So all of the files that are not index.js and all of the files that end with the dot js extension. So all of the JavaScript files answer is enough of putting anything that is JavaScript here, but just in case we have this condition, okay, so now we have an array of files. Then we have to iterate through this array. So let's use a for const file of field model files. And here I'm going to import or require the file. So I'm going to say require. And again, I'm going to use path, join your name. And we're going to join the dirname with the name of the file. And we're going to import that default export. And to the default export we're going to pass the SQL instance. So I know this sounds very weird, but this is going to have sense once we write our first model. So then we have the model that, that the class represented on Model. And we're going to say models, model.py name is going to be equal to the model. So as I said, is going to be an object representing with the keys as the name of the model and the value is going to be the class representing that model. Okay, so now we have populated our models object. Now it's time to actually call the associate method for each of these models. So we're going to again do FOR loop with, with like this. We're going to say object. The key is that model of keys, of models. For each model name. Remember, the keys are the names of the model. And we're going to say, Sorry, if models of model name that associate, then call that method associated models. Okay, So important thing here is that these associate method, we're going to pass all of the models. Again. That's why first, we need to populate. All of these models are objects. And then we need to call this associate method on each of the models. Okay? And last but not least, we're going to also set an additional key apart from the models. And that is going to be the SQL licenses. So apart from the models, these models object is going to have the SQL Instance as well. Okay, so that's it. And the export default will be the model object. And that's it. That's everything we need to register a model. Okay, so now that we have this function, let's uncomment this and import it. So it got automatic important, That's great. And that's it. We have created our data base class. We have registered the models, although we don't have any models yet. But that's what we're going to do next. So I hope you like this video. See you in the next lecture. Bye bye. 18. Adding the server: Hi and welcome back. So now we are going to add the server. And the server is going to be responsible of connecting to the database, creating express up, and listening the port that we specify. Okay, so remember here in our scripts, we said that we're going to execute this server.js file. So we need to create that file. Okay, now that we have created this file, Let's first import conflict. Okay? So config, if you remember, if we go to index.js, it's only going to import this data package. And it's going to say that m dot config. And that means that it's going to import all of the environment variables here. Again. So after doing that, we're going to import database. We're going to import the environment variables. So that's why we put these import config at the top of the file. Because this is going to execute first. And then we need to execute or important environment variables after we have loaded all of our environment variables. And we also need from conflict database. And now we are going to create a, an immediately invoked function expression, or short for i. I means immediately invoked function expression. And that basically means a function that executes after it has been defined. Okay? So this is how we do it. A sink, the function definition, and then parenthesis to execute it. So that's what I have for these are going to run all of our code in a try catch block. So we're going to say constant new database. And we're going to pass the environment. So the environment is determined by this node variable. And we're going to need also to pass. And then we can say await DVI connector. Perfect. Now if something goes wrong, then we're just going to say console error. Something went wrong when initializing the server. And we're going to put a new line here. And we're going to print the error stack. Okay? So that's everything we need for the server. In fact, we can now run the server. So first of all, first of all, let's try to run it without the database, because right now I don't have any containers up and running. So if I run npm, run dev, you're going to see that we have an error here. And the error is that SQL connection refused cannot connect to these local host on port 54321. That's because we don't have any database. Now, if we run docker-compose up minus d and wait for the database to be created or for the container to be created. We can run again. And this time we get a successful message saying connection to the database has been established successfully and connection sync successfully. So that's it for this video. Hope you like it. See you in the next lecture. 19. Adding Tests Helpers: Hi and welcome back. So the next step is to create our models. Okay? But before doing that, we need some tests, helpers that are going to allow us to make our testing easier. Okay, so for that, I'm just going to create a new file. I'm going to name it test helpers, helpers. But JS. And inside this file, I'm going to first import the conflict, but from source. So source config. So again, this is to import the necessary environment variables. Okay? Then we're going to import the database or from source database. And we're going to import DB config from again source and database. Okay? Now we're going to create this DB variable. And again, I'm going to put all of the utility functions inside a class. And I'm going to export default is glass. And the first is going to be in a static method called the Start dB. And this is start the beam. We're going to say dv is going to be equal to new database and environments where it's going to be test. You can also import environment that node m. Because when you run tests with just, just is going to automatically set that node m variable to test. Or you can just hard code the string here like I am doing. Then you need to pass a default config because remember that contains these hours. It contains this object here which contains the information of the test database. Okay, then we need to await to connect. And we're going to return the DB in case some of our tests access to this instance of the database. Okay? So that's the first thing. The second thing is that we need a method to stop that database. Okay, So after we run the test suite, we need to stop the database. So we're going to say await, await db dot disconnect. And last but not least, we are going to create a method to reset the database or the database. And we are going to say db dot. Okay? So if we remember correctly, Let's go to database index.js. Remember that if we run this method when we are in the test environment, then force is going to be true. That means that each time that we run a test, we're going to drop all the tables and have a test with a clean database. So we're going to run this sync db command before each test. Okay? So that I think those are all of the tests helpers that we are going to create right now. In the future, we're going to need two more tests, helpers, but that's in the future. So that's it for this video. Hope you like it. See you in the next video. Bye-bye. 20. Models overview: Now that we have our test helpers, we're going to start writing our models, which I think is the most complex part of every app basically. Okay, So here we are going to have three models. The user, the refresh token, and the roles. So let me explain briefly each of these models properties. So the user is going to be by far the most complex model that we're going to build. The user will have many roles, so it's a one to many relationship. The user will have one refreshToken, a one-to-one relationship, relationship. And the properties are going to be an e-mail password, username, FirstName, LastName. Obviously you can add whatever you want. But I'm going to stick with only these five properties. And we're going to see how to validate like the length and things like this. The roles model. So the role will belong to a user, roles will belong to a user. And the only property that it is going to have right now, It's the role which is going to be a string. So there's going to be like admin, customer or whatever. And the last model is a refreshToken model. And these will belong to a user as well. And the properties just going to be a token, which is going to be string. So all of these relationships and the, has many relationships that has one relationship that belongs to a relationship and the lungs to relationship. Those are abstracted with SQL eyes and it's pretty, pretty easy to do. And if you remember, if we go to our code here, index.js, we have these models, not associate method models, model name dot associate method. And that is basically going to register all of these associations that I am explaining you right here. So without further ado, let us start with the user model in the next video. Bye bye. 21. Creating the User model (Part 1): Hi and welcome back. So we're going to start defining our most complex model, which is going to be the user model. So let's create the user file here, users.js. And here I'm going to export default, a function that is going to receive as the unique parameter, the SQL connection. So remember, hearing index.js, we are requiring this file here. We're calling the default export. So basically this and that returns a function. So that's why we are going to pass the SQL IF function here. So I hope now this makes sense. Okay. So now inside this function, we need to actually return a class. So we're going to create a class user that extends from a model class. Again. And this model class needs to be imported from SQL ice. So important from cyclize, this model class. Okay? And here we're going to have a static associate method which is going to receive the models object, which remember, is passed here. So we're saying if that model has these associate method, then call it with the models object, which obviously right now if it's empty because we need to create all of our models. So yeah, this is going to have, this is going to have all of the models, once we create all of them are, isn't it? So let's pretend for a moment that we already have the first token model, though, a role model and the user model. So we're going to say that user, that refresh token is equal to user that has models that refresh token. Okay? So that is going to set up a one-to-one relationship between the user model and the refresh token model. We actually need to do something like in the refresh token model, refers to ok, dot belongs to user models that user. So we're going to obviously do that, but when we create that model, Not right now. And also we need user that rolls. You said that has many models that role. Okay, So just to clarify, this thing here can be whatever you want. You can put whatever you want here. But obviously, putting refresh token to say that this has a static static property called first token, and the user class has a static property called rolls. Again. So this doesn't affect anything. You didn't have to follow convention here for this to work. In fact, you don't need even to assign these two variables. But we're going to see later that we need these to be assigned to variables. But we're going to see later why. Okay, So we actually need also this is static Async hashed passwords method, which is going to receive a password. And we're going to implement the logic in later videos. And we also need another static method called create new user, which is going to receive all of the things that we want to save in, in our database. So like an email, a password, roles, which is going to be an array, an array of strings, username, username, first name. We're going to receive a last name. And we're also going to receive a refresh token. Okay, But again, a method that we're going to implement it later. Okay? So these are all of the static methods that we're going to implement. Now, let's define the properties of these user model. So for that we're going to say user dot in it. And here, the first argument is going to be an object that finding all of the properties. So for example, an e-mail, which is going to have a type. And for specifying the type, we need to import this data types from cyclize. And we're going to say, Hey, this to be a string, and we're going to limit it to 100 characters. So I don't think there is saying e-mail with more than 100 characters. Maybe there is. We're going to say Allow know to be false. We're going to say unique to be true. Okay, so this basically means that we're going to create an index on this e-mail field. We're going to say validate. We're going to say that this needs to be an email. If this is not an email, we're going to say not a valid email address. Okay? So don't worry, we're going to write tests for this so we can check that this indeed works. Okay, so that's e-mail. We're going to pass a password is going to be another property. And the type of this property is going to be a string, that a type string. And we're going to say Allow not be false, we don't want no password. Then we're going to say username. This is going to be of type, again string. But we're going to limited to 50. We want this to be unique. We want to validate the length of these username. So for that, for this validate instead of e-mail, we're going to say length. And this length obviously. And the arguments is going to be an array with the, with the limit the, how do you say this? Well, the minimum amount of characters and the maximum amount of characters. And a message saying username must contain between 20 and 50 characters. So we don't want empty usernames or the username that unless two characters. And again, you can configure this if you want 10, and that's up to you. You can put 35, whatever. Okay. Then we want also to define a firstName. And this FirstName, I'm just going to copy and paste this because it's going to be very similar. Let me just I think I am putting this in the wrong place. This should be here. And I'm going to copy and paste everything here. And well, the firstName is not going to be unique. That can that can be repeated. The validate. Well, let's change this to three just for the sake of having something different. Let's put this first name must contain between 30 and 50 characters. And let's copy and paste this. Copy and paste saying firstName, lastName. Let's say this is again three, but let's change the validation message. Okay, So now that we have created all of the properties, but we need to pass a second argument. So this very big object is the first argument, and the second argument is going to be an options object. And these options object, well, we need to pass the SQL instance that's mandatory. And we need to pass the module name, which I'm going to say this is going to be this user string. So this is going to be the modeling. And remember that this model name is going to be used here to populate our model object. Okay? So we're going to also return the user class. And we haven't finished yet. We need to do, we still need to do lots of things like creating these hashed password and create the user. So that's what we're going to do in the next lecture. So hope you like it. See you in the next lecture. Bye bye. 22. Creating the User model (Part 2): Hi and welcome back. So let's try to complete our user model. So let's tackle her first, this hashed password, which as the name suggests, is just going to take a password and hash it with big crypto algorithm. So for that, we need the big crypto package. So we're going to import it and we're just going to return, encrypt that hash. And if we see at the function definition, it says here that we need as the first argument is a string, which is going to be basically our password. And the second argument is going to be the salt or routes, which can be string, or it can be a number and returns a promise, okay, which is going to be a promising results to a string, which is going to be basically the hashed string. Again. So let's pass the password. The first argument are humans. And we need the salt rounds for from the environment. So we're going to say environments, important environment from config environment. And here we're going to say environment Salt rounds. Okay, so that's, that was pretty easy to implement. Okay? So now that we have implemented this before we implement these static scene create new user, we're going to implement a hook. So what is a hooks? Basically, it's some code that runs after a certain, certain action or before certain action. So in our case, we're going to say user that before save. So before we saving user, we're going to say, we're going to have these callback. And here we're going to hash the password, hashed password, weight user that hash password. And we're going to pass the user the password. And we're going to say that the user that buzzword needs to be equal to the hash password. Okay, so that's it. That's pretty straightforward. These Syncom addresses the user hand options. We're not using these options parameter. But you can see here that the interface is this update options or this save options. So in our case, it's probably safe options. Okay? Maybe we can see that save options here. If we control-click on this before safe. Here we can see Save Options, and here you can see the things that you can expect to be in that options object, but we're not going to use it. So i, if you want, you can read on the documentation to expand your knowledge. And so that's basically the hook. This is going to guarantee that every user we save, The password is going to be hashed. So we are never going to save a plain text password. Okay? So this is all of the implementation. Now let's create a, another, another method. But this is not going to be a static method. It's going to be and an instance method. Okay, so that means that the, we have an instance of this user, then that instance going to be able to use this method. And to create instance methods, we're going to say user that prototype dot and the name of the method that we want to create. So in my case, it's going to be called Compare passwords. And this is going to be an async function that receives a plain text passwords and returns a Boolean saying whether the past password is the same as the hashed password. So basically, the big crypto algorithm is going to take care of it. So we're going to say return be crypt, compare, password, this password. Okay? So again, this returns a promise because we need to do some computations here. And for example, if we have something like user is equal to await you, sir, that fine. Find one where email is equal to test our example.com. So we have something like this. This is going to return a user instance and then we're going to do something like this. You said that compass compare passwords and we pass the password like uno, suppose Desmond and threes and password. And if this is the password from the user, then is going to return true. If this is an invalid password and is going to return false. And obviously we need to wait for this because it's an async function. So that's how we are going to use instance method. Okay? And then let's try to create some scopes. So we're going to say scopes. But first, let's define the default scope. So what is the default scope when we make a query like what we did here. So let me just Control C here. Okay, So when we get the result of a query like this one, this user is going to have the information. So it's going to have something like e-mail. It's going to have user, username or dot, FirstName, LastName, and user that password. Okay, so even if the password is hashed, we don't want to expose that as Word 21, right? Just when we need them. So just when we need the password, we're going to pass in scope and say, Hey, including the query, the password, but otherwise, we're not going to include the password. Because, why, why are we taking this decision? Suppose that we somehow returned in a controller, we return the user to the client. Okay, so we make a query and we return the user. We don't want that to be included by mistake. For example. Obviously there are things like serializers and things like that. But in this course we're not going to implement that. So if you want, you can into material acids, but we're not going to date. So this is a security measure just to make sure that we are passing the password in any query. Okay, So for that, we're just going to, we're just going to say default scope are going to say attributes. And we're going to say exclude the password. So this is going to be an array with excluded attributes. For now we're just going to exclude the password. So this is going to be the default scope, but as I said, there is going to be a time that we are going to need the password. And that is going to be for our login controller. So for that, I'm just going to create a scope that is going to be called with passwords. And basically I'm just going to say attributes include password. Okay, so only we make query with this scope. Then just in that case we're going to pass the password to the query. Okay? So don't worry, if you don't understand this right now, we are going to understand it once we create the logging controller. Okay, so that's needed for this video. In the next video, we are going to handle the implementation of these create new user, a static method. So I hope you like it. See you in the next lecture. Bye bye. 23. Creating the User model (Part 3): Hi and welcome back. So as you can see, our user model is pretty complex and we still need to create or implement the create user method. So we're going to create a new user with roles, with a refresh token and with all of the properties from the user model, right? So we need to do multiple insertions. We need to do an insertion in the users table, another insertion to the refresh token table, and multiple insertions to the roles table because we can have multiple roles. So if one of these insertions fails, then we want the whole thing to fail. And I've already told you about this. This is where transactions come in. Transactions allow us to roll back all of these changes. And Eve, all of the changes were successful. If all of these insertions were successful, then we're just going to come in the robot. And if you remember, if we go to the index.js file from these database class, remember that we're using these namespace in order to have managed transactions. Okay, so basically what we're going to return here is the result of a transaction. So cyclize that transaction. And remember the cyclize is available because we have, we have it here. And these transactions expect to call back. So we're just going to write a callback. And inside here, we're just going to put all the logic that comes when we create a new user. So first of all, let's create here. Wait, you sir, that creates. And here we're just going to pass the email and password, the username, the firstName, and lastName. Ok, so we have put all of these things in the users table. But we also need to find a way to create this user with roles and with the refresh token. And that's where these things here are going to help us. Okay, So for the refresh token, it's actually pretty easy. We just have to pass this second argument. And we're going to say include and is going to be an array. And we're going to say include that user dot refresh token. Okay? So now here we can simply say We're going to put the refresh token. And this is going to be an object that expects a token that is going to be the refresh token. Okay, so remember in the presentation I did earlier, I said that the refresh token table is going to have these field called token. So this is how we create an associated refresh token with this user. Okay, we pass an object specifying the token and for the roles. Well, it's a little more complex. We can say here user roles. And then we're going to save roles. And these needs to be an object, sorry, an array of objects. So something like this, role customer. And then another object like role had something like this. Okay? But these roles is just going to be an array of a string. So we need to convert that array of strings to this thing here. So before these await you, sir, create, I'm just going to say let roles to save the an empty array. And then we're going to say if rolls is defined and if Rawls ease and our aim. If these two conditions are met, then we're going to say Rolls to save, going to be equal to roles, duct, map, roll. And we're going to convert this to an object like this. So basically, if rolls is something like this, customer admin, then rolls to save. Roles to save is going to be an array of objects like this, role, customer, role, admin, something like this. Okay? So that's all done logic that we need. Obviously here, we need to replace this with roles. And we are done with our user model. I think. Let me review quickly my notes to see if there's anything I'm missing. And it looks like now this is everything we need. Obviously we're going to write tests for this. But before writing those tests, we're just going to write the other models because they are so easy. So let me add everything Admin make a comment saying the user model. So that's it for this video. Hope you like it. See you in the next lecture. Bye bye. 24. Creating the Role model: Hi and welcome back. So we have created our most complex model. Now it's time to build the ECS, the easier ones. So let's go and create this role model. And again, this is going to be a function. We're going to export default, the function which receives a SQL connection. And we're going to create this class role that extends from model. And remember we need to import model from SQL. Where is it? Model? And also datatypes to define our our types. So in the static methods, we're going to write our associates static method. And remember, received some models of the models. And here we're going to say roll belongs to models that user. Okay? So here it is not necessary to assigning to a variable because we're not going to make that creates greater, great new roles like that is going to be a very easy model. So after Dad, I'm just going to say roll dot in it. The first argument is going to be an object. And this is going to have a role property. And the type is going to be a string. So something like this. So it's up to you. You want to put any kind of validation for me. I'm just not going to put them in validation here. For the second object, I'm going to pass the SQL Instance, which is mandatory, and the model name which is going to be Rho. And finally, we need to return the class, the role class. And that's it, That's it for our role model. So hope you like it. See you in the next lecture. Bye bye. 25. Adding Refresh Token model: Hi and welcome back. So we have created our role model. Now let's create the last model, which is going to be the refresh token model. So again, this is going to be very, very similar. In fact, let's just copy and paste this and save time. And here the only difference is that, well, obviously the name of the class. So I'm going to use this feature for ambitious to your code to rename it in all places. Okay? If you're curious, it's too that you have to press in order to change the name everywhere. And here I'm just going to say, well, this is going to stay the same because the refresh token belongs to the user. And here we need to change this to Tolkien. These to refresh token and nothing else. That's it for this model. So how do you like this video? See you in the next lecture. Bye bye. 26. Inspecting the new tables with DBeaver: Hi and welcome back. So now that we have created all of our models, well, they are registered here in this index.js file inside the models folder. Then also we have here in this database that index.js. Remember at the end we have the sink. So sink, if you remember, is going to create a table if it doesn't exist. So let's run npm, run dev here. Okay, so if the connection to the database was successful and the sink was successful. So if we go here to our SQL ice cores, main dv, Let's refresh just in case. Look at the schemas, at the public schema, and look at the tables. You're going to see that the table's got created and that's because the sink was successful. So if we click on Users and C on the properties, we are going to see that we have this. Does ID, email, password, username, first name, last name created at updated that well, these two fields and the ID field were added automatically by civilized. And here you can see the frame keys constraints. Here you can see that we have that the email is a unique key constraint. The user's primary key, the username unique key. And the indexes. We have this email in the x because it's a unique column and the username index because it's also in income. And obviously the primary key, which is a, and it has an index because it's primary key. Also, we can see here in the DDL, the query that cyclized needed to do in order to create this table. And the same can be done with the roles and refresh token. You can, you can basically see everything here. So what's interesting here, for example, in roles in the DDL, we have these constraints and it says this and delete and update and all of these things. So my point here is that all of these things shouldn't be determined by SQL. Why? Well, because first of all, we don't have any mechanism to roll back, for example, on migration. And this is where the concept of migrations come in when we want to create a new table, when we want to create a new column or add a new index, we need a migration. We cannot let supplies the term mind what is going to happen? Because migrations is a way to have a record of history of what changes were made to the database. So this is great, but we need migrations, and that is the thing that we're going to do next in this course. Okay, so hope you liked this video. See you in the next lecture. Bye bye. 27. Configuring the Sequelize CLI: Hi and welcome back. So remember that the beginning of this course we installed the Secret Life CLI dependency. So in order to use it, we actually need first to configure it. So for that, I'm going to create a SQL. Sql IS RC file. And here I'm just going to require this path here. And I'm going to export this object here, this configuration object. So config is going to be path that result source, config, database a GS. So basically this means that all of the configuration is going to be taken from these database that JS object. And then we're going to say models. And it's going to be resolved source models. Okay? So this folder basically and migrations bath is going to be resolved. Source database migrations. So we haven't created this folder yet. So inside database, let's create a folder called migrations. And that's it. That's how you configure Synchronize r. Now, we can hear in the terminal type npm SQL ice. Okay? So if you type that, then you're going to have all of these commands. For example, SQL, DB migrate, db migrate schema timestamps. Db migrate status db migrate undo to rollback, emigration, db migrate onto all to roll back all migrations. The seed to run seeds. We also can specify here is cedars. But we're not going to use that cyclized need to initialize the project. We already have that initialized. We can also, for example, January immigration like this. Okay? And what else we can generate? So these were generating a skeleton of a migration. And this is for generating a skeleton of a model, and this is for generating and skeleton of AC. So in the next lecture, we're actually going to use this command here in order to generate the skeleton for the users table. And we're going to see how to write these migration. So hope you liked this video. See you in the next lecture. Bye bye. 28. Adding User Migration: Hi and welcome back. So it's time to generate our first migration to create the users table. Okay, so let's run this command and the uncivilized to see how to generate these migration. So it looks like it's synchronized migration generates. So let's run that migration generator and let's type dash, dash help to see the options. So here you can see that we can pass, where is it? Again, we can pass the name. That is going to be the name of the migration. Where we can pass all of these options. Basically, you can read all of them you want. But I'm just going to use these flat here. So I'm going to say name and pass the name of the migration, which is going to be creating users table. Okay, So here if we go to migrations, you can see that these generated automatically skeleton for us. So here we're going to put the up and the down. So here in the app we have to add altering commands and in the down there reverting comments. Okay, so this basically is for migrating and roll back in. So let's delete this comment here. And here, I'm just going to say await query interface that create table. And we pass the name of the table which is going to be called users again. And the second argument is going to be all of the definition. So for example, we're going to have the ID. Here. We have to define actually the ID. It's not like SQL light that generated that ID for us. And well, it's not that difficult. We just have to say that the ID is going to be allow low false. Also Increment, incremented, true. The primary key is going to be true, and the type is going to be SQL like that integer. Okay, So that creates our ID. But we need to generate all of those other fields like the email, which is going to be of type, cyclize, string, and 100 characters max. Allow know to be true, to be true. And here we can put something like validate, because that's specific for the modelling initialization. And we cannot say to the database, database Postgres please validate and check if there's an email. So Postgres is not is not capable of doing that. So synchronizes what it's going to do that. So that's why we put that validate. But in the model for the password we're just going to, this is of type string and allow know to be false. For the username. We're going to say type that string 15. And unique to be true. And we still need first name, which is going to be of type SQL lines. That's drink of 15 and nothing else. For last name. It's going to be the same thing. Copy and paste this. And we also need to manually create the createdAt. So alone, no, false. And it's going to be of type, synchronize that date. And the updated alone or false and time. Again. So these are going to be our fields. Quick note. And maybe people want to do something like this. Firstname, use underscores. This is up to you already. So you can leave it like this or use underscore. But yeah, I'm just going to keep it like this for now. Okay, so that's it for the app migration, for the Data Migration. And it's going to be very simple. We're just going to say query interface that drop table users. And that's it. That's our migration right here. So how do we run this migration? Well, first of all, we're going to do it on the test database because it will try to do it right now. The main database are going to run into problems. Okay, so let's go here and type npm SQL DB migrate. But we're going to pass this flag. And we're going to say, Hey, this, but on the test environment. And yet that was successful. So if we go to test here, if we go to test, we're going to see that this created the C-Cl ICE table, which is basically a table which contains the name of the migrations. And here, users, hearing users. Well, if we go to properties, we're going to see that we have the same properties as a table from here. So let's just compare things to see if they match or not. So first of all, here we have, this is the table from the test, and this is a table from the main table. Okay, so let's go to the DDL and see both of these details. So as you can see, we have some difference here. So for the email on the test, we have that is this can be known. And that's probably something that we'll want. Let me seem so ML allow know. So I said an hour alone all to be true, but I wanted to be false. So that's a mistake. I mean, so we need to roll back this migration. So this is a good opportunity to robot demonstration. I'm just going to undo all because we only have one migration. Happened. Seem dv, oh, it's migrate on the wall. Db migrate and low. Okay, so that reverted the change and then we are going to migrate again. But you seen the new migration here. So let's go and refresh this table here. Refresh. Okay, so now these two things match. So here is the properties or the DDL from the main table, and this is from the test table. Okay? So as you can see, the only thing that changes here is the color of this thing. I'm not sure why here it's not yellow and here's yellow. But apart from that, everything looks the same. So let's see the columns right now. So here, if we change here, they look the same. But now let's look at the constraints. Constraints here. And they look the same as well. Well, we don't have foreign keys. Let's look at the indexes. So they look the same. Okay, let's see the dependencies. Well here, they change because we have these dependencies on these refresh token and Ross model. So that's why we have that. But when we add them aggression for the roles and the refresh token model, we're also going to have that. Let's see references, partitions, triggers, rules. These are the same or game. So basically they are the same except for these dependencies. But that's only because we haven't created the migrations for the roles and the first token that are going to reference this table. So after we do that, okay, But apart from that, everything looks, everything looks the same. So well. Migrating the test database is actually not very useful because we're going to drop the table. Remember we have that same force true. So it's going to basically drop this user's table and recreate it. But it's going to recreate not using the migrations, but using the sink. So that's one reason why we need to sync the model definition and the migration definition. Okay, so that's it for this video. Hope you like it. See you in the next lecture. Bye bye. 29. Adding Role Migration: Hi and welcome back. So it's time to create the migration food or roles table. So let's type in SQL. Migration generate what was the command? I already forgot? Nps SQL. Migration generates Migration, generate name, create, roles, table. Okay, So that created these empty migration here. Let's remove this code and this code as well. Okay? So let's write down. The down part is going to be very easy. Wait, green interface, drop table roles. And the app is going to be weight, core interface, great table roles. We need to pass all of the fields. I'm just going to copy and paste everything here. And obviously delete lastname, firstname, password, everything that is not from the roles model. And I'm going to say roll is going to be of type SQL string. Perfect. And we also need to create that user ID foreign key. So for that, the type must match the type of DID in the user table. So I'm just going to copy this type here. And here comes the funny part. References, references the model whose table name is users, okay? And the key is going to be the ID. Okay, so this is the migration. Now, let's run this migration in the test environment just to see what it did. And lexicalized db migrate test. Okay, so it's succeeded. Now, let's go to dbVar and see what happened. So let me check here the table. So there's going to be this is going to be the table for that database created with the sync command. And here, let's go to the test database and go to the row table. Just refresh, just in case. Okay, So let's see. The one on the left is the one created by SQL ice, and the one in the right is the one created by our migration. So let's see both of them. Let's compare them. And for the columns, they seem to be the same. Let's see the constraints here. So the constraints are the same. Let's see the foreign keys. And this is where we have our first difference. So if we see the table from the right, you're going to see here that for the delete rule, we have no action and for the update rule we have no action. And for the one created by SQL eyes we have the delete rule is set null and the update rule set to cascade. So this means that if we delete the associated user, then these records inside the roles table is not going to be deleted, is just going to set this user ID field to know. And if the user ID is updated in the users table, then here is also going to be updated. And here, simply as the num, as the name says, if the user is deleted, then these roles, this record is going to be kept intact, so nothing is going to happen. And the same with the update rule. So as I said in the last video, we want these two things to match. So why? Because for the test database, remember that we are going to drop the database. Started again, create all of the tables, so we want these things to match. And when we create new, the new tables with a sink force command, we're not going to create them via the migrations, but we're going to create them via the sink command. So the sink command must yield the same result as a migrations and vice versa. So in this case, I want both the same command and the migration to have these an update to set to cascade. So let's put here, first of all, let's revert the migration. So to revert the migration, we say migrate and do and pass the name of this migration. Okay? So let's pass name like this. Okay, so we reverted the migration. And then here I want to put on update cascade and ON delete. I want to also cascade. So here in the immigration we have an update and delete set to cascade. Now we need to go to the model, to the role model. And here in this role belongs to we need to pass those two options as well ON delete cascade, on update cascade. Okay. Okay, fine, So now let's run this migration again. Okay, so let's go here and let's go to the roles table. Let's refresh it. And probably we need to refresh the connection or stuff like that. Oh, no, this this, this is a test database. So as you can see now, we refresh the table. Another delete rule for the test db is to cascade and the same for the opposite wall. So now let's delete all of these tables inside the main database so they can be recreated with a sync command. Where is it? Okay, So now let's run npm, run dev. So these create the tables again. Let's refresh and see the roles table. So here you can see again the literal cascade update rule cascade. So this matches this. Okay, So for the indexes, it's also the same. For the dependencies. Looks the same to me. References, nothing here, nothing here, nothing here, nothing here. Triggers. We don't have triggers and have rules. And see that the DL, so the DDL looks exactly the same. So now we have managed to make these two things match. So the model and the migration, and that's great. So that's it for this video. I hope you like it and see you in the next lecture. 30. Adding Refresh Token Migration: Hi and welcome back. It's time to add our last migration, which is for the refresh token table. So npm Migration generate name, grade refresh token. And how have we been naming this refreshToken table? Like this? Okay, so now we have our third migration here. Again, the down is pretty simple. We just have to wait. The core interface, drop table, refresh tokens. We're going to name the table like that. And here I'm going to say await, great interface and create table, refresh tokens. And again, let's copy and paste something from here. And these fields here. And let's add the token. The token, let's go to our models. So yeah, there's something here that I need to fix. Here. We need to put these as type text because string will have a limit of 256 characters. And remember that the token is a decent Web Token and it can have more than 256 characters. So we're going to change these. Next time here again, we're going to have it of type text. Okay? So, yeah, we have the token, we have the createdAt updated AD user ID. And again, we need to match here this thing. So here I'm also going to put on delete cascade and on update cascade. Okay, so that seems correct to me. Let's hear, removed these tables in the main database. Just remove everything here. If I have to do this. Like this. Yes. And let's run npm, run dev. Okay? So now let's run NPM SQL DB migrate, have desk. Okay, perfect. And let's refresh just in case refresh here for shear. And let's see gamma table. Refresh tokens. And here we have schemas, Bob, refresh tokens. So the one from the right is the one from our migration, and the one on the left is the one sink with SQL ice. So let's see. Here we have these things. Match. Is constraints. Match the frame, keep the match. Both are set to cascade. The indexes, the match dependencies they match. And the DDL will also match. So that's it for the refresh token migration. Okay, so that's it for this video. Hope you like it. See you in the next lecture. Bye bye. 31. Applying Migrations: Hi and welcome back. Congratulations. From going through this section. We have done a lot and we still need to write tests for user model. But before doing that, remember that we have here these tables in the main database that are created with a SQL ice. So with a single eye, same command. So let's delete them. Okay, and let's go here and type db migrate status to see the status. And as you can see, all of the migrations are down on the development database. So let's just migrate. And the three migrations got applied. Now let's refresh this. And now we have these tables created with the migrations. So now when we run, actually, when we run npm run dev, okay, So it says here connections things successfully. But in reality, the sink command is not going to do anything right now. So if we go to index.js, now remember that this is not going to do anything if the table's already exist. So that's what we want, right? But for testing, this is going to drop the database and recreate it with this same command. So that's why we need that match between the migrations and the models. And for production, we obviously want the database is created with the migrations. So that's it. In the next lecture, we're going to add tests for our user model. So see you in the next lecture. Bye bye. 32. Small improvement to the User model: Hi and welcome back. Before we proceed to writing tests for our user model, I want to make a small change in the create new user method. So here inside the callback of the transaction, we have this async callback that is basically a way for this user to be created. So what is returned from these callback is also b is also going to be returned for the create new user. And here, as these callback doesn't return anything, these returns undefined. And basically if we call an await create new user, we are going to receive undefined. So what I'm trying to say is if we do something like this result await, create new user with all the vena result is going to be on the final result. And the find. They're going to be the same thing. Okay? So I want to basically return the newly created user. And we simply need to return, remove these async and simply return user. Not great. Okay, So this is a primates. So this transaction is going to return a promise. And that basically means that these create new user returns a promise. But if we are weighted premise and we're going to get the newly created user, okay? But there is a drawback here. So if we return the user like this, the password is not going to be hidden. So we have two options here. The first option is to delete our, again, do like we were doing here. And a weight. Okay? And then, but in this, into this result variable, and then deleting the password from these results. So that's one way to do it, and that's totally fine. But there is a better way to do it. And remember that is with hooks. Ok, so we can create in your hook. And this time it's going to be called after Create. Okay? And this is going to receive a callback, which this time is not going to be a sink. It's going to be synchronous. Okay? And here we can simply say user that data values and the password, and we have to delete this. So we say delete. And that's it. After we create this user. And we return it here. Then we're going to delete these password from the database. Okay, so that's basically the change I wanted to do. I hope you liked this video. See you in the next lecture. Bye bye. 33. Adding User model tests (Part 1): Hi and welcome back. It's time to write some tests for our user model. So inside these tests folders, create another folder called models. And here I'm just going to create a new file called user.name test dot js. Okay, so here I'm going to import test helpers, helpers. And I'm going also to import models from source models. Okay? Now we're going to create these describe block. And I'm going to do this before all. And inside here, I'm just going to write and sing callback, which is going to call this Test Helpers, started. Then an after all, which again is an async call back saying await test helpers that stopped the beam. And then a before beforeEach. Again an async call back. But this time I'm going to call the test helpers that sink. Okay? So what this is going to do is to basically drop the tables before each test and recreate them using the models definition. Not the migration, but the models definition. That's why it's very important to match the migrations with the models definitions. Okay, Now let's start by putting a described block here, saying it's static methods. So here I'm just going to test all of our static methods. So the first one is going to be hashed passwords, okay? And these hashed password is just going to contain one task. And this is going to say it should hash the password, pass in the arguments. Okay? So basically here I'm going to put an unseen callback. And here I'm going to get from the models object, I'm going to get the user model. And I'm going to create a password like this, some random string. And then I'm going to say hashed passwords. Sql to await user that hash password. Like this. And when we pass a password, and then we can make our expected statements saying that word and not to equal the hashed password. Okay, perfect. So let's open a terminal here. First. Let's make sure we have the DB up and running and then npm run test watch. Okay, so yeah, these tests passing. So that's great. Now let's create another describe block inside these static methods. Described luck. And this is going to be for our test related to the create new user, a static method. So here I'm going to create the first test, which is going to say it should create a new user successfully. Okay, perfect. And then I'm going to get from here again the user model. And I'm going to define these data object, which is going to contain some random data. Email, password, test 123 roles. So this event to have admin and customer, for example, the username, the FirstName, LastName, and some random refresh token. Okay? Now I'm going to create a new user with a weight user.name, create new user. And I'm going to pass all of these data here and make sure that this is a sink. Okay? Now remember that these new user returns a user. And also remember that we created this after create hook. And that basically means that we're going to take out the password from these new user. So we can also test that these after Crete hook is a working as expected. But first of all, returning these user is not sufficient because it may be the end God saved to the database. So we can make an assertion of how many users there are in the database. As we have these before each and is basically removes everything in the table, in the users table. Then after doing this, after calling this create new user, then we shall have just one record. So for that, I'm going to call the discount method that is available on any, on any model. And I can expect users count and to equal one. Okay? And look, this test is passing. Now we can make assertions on what these new user. So we can expect the email to be data that email. We can expect new user password to be undefined. Okay? So by doing this, we're basically testing this hole right here. We can expect also the username to equal data that username. We can expect new user firstName. Data that FirstName. We can expect your user dot last name, dot last name. We can expect new user that refresh token, the token to equal data that refresh token. Okay, so lots of assertions here and our test is still passing. We can also expect new user that the roles but length to equal to. Okay? So basically, this means that we created these two roles here, but that's not sufficient. We also want to test that these are indeed the roles that got saved to the database. So for that, we can get this saved roles like this new user dot roles. And we can map each saved row 2, saved role, dot-dot-dot all. Why? Well, because each one of these roles elements, because remember Rawls is an array of roles object. So it saved role is role object and each row object you can call the roll method. Okay? And let's see what happens if we try to do this. Saved rolls equals to data dot roles. Let's see what happens here. Okay? So in order to improve this test, what I will do is to sort that this here. And here, I will start as well. So not here but here. Just to make sure that we are We're having to erase that are equal. Because I know it can happen that this thing here is not returning as the same order here. So just for safety, I will do this like this. Okay, so that's it for this video. In the next video we're going to write more tests. So hobby like it. See you in the next lecture. Bye bye. 34. Adding User model tests (Part 2): Hi and welcome back. So we're going to add more tests for the create new user method. So this method is little bit complicated because we can easily add like ten more tests for this thing. But we're going to keep it simple and add all of the unnecessary tests and feel free to add more tests. So probably that's one of your exercises that you shall do. Add more tests for this great new user. So now that we have these case created, now let's remember that we have all of these validation here. So for example, on e-mail we have allowed know to be false. So this is a validation that actually is made both at the database level and also the SQL light level. This is the only validation that is done on both sides. The only one there, there isn't any other. But we also have these validation of email. Okay? And well, also we have unique true. So if you create first one user successfully and then tried to create another user with the same email. Then you're also going to have an error thrown and password. We have again these allow law, which can also be tested. And the username we have again these unique and we have these validate. We throws an error with this message if it's not between 115 and is firstName, which is very similar to username. So without further ado, let's try to first create a user with an invalid email. So I'm going to say initial error if we create a user with an invalid email. Okay, So I'm going to get from the user models. And we're going to get the user model, sorry, I'm going to define an e-mail which is invalid. So something like this, a password which is going to be okay. It's not going to be no. And then I'm going to define this error here. And I'm going to put this user that create news new user call with the data inside this tribe. And in the catch, I'm going to catch the error. And that error, I'm going to assign it to this error variable that we created here. So first of all, we need to expect that the error is fine to be defined. Now, let's make sure we have our database up and running. And let's run Test1. Okay, So the test is passing. Now let's console log this error to see what it contains. So first of all, we have here the type of the error, the message of the error, the stack of the error. And here we have additional properties. So first of all, note that we have these errors property and this is an array. Again. This is honoring. And right now it contains one element. If we were trying to make multiple things fail the time, that will be a problem because we wouldn't know like the order of those errors. So that's why it's a good idea to make things fail 11 thing at a time. Okay, so now that we know that this is an errors, the errors is an array of arrays. Let's make another expect. We can say errors, error, errors that length to equal one. And let's see if this passes. Yes, This is passing. And now we can make assertions on these single item inside this ring. So we can expect error, that error, the first element. And we can save the message to equal not a valid email address. Okay? What is it? Not a valid email address? And we can also think it's banked. Let's take that error object. Here like this error, that errors. Then we can say error object bearer, objects that path to equal e-mail. So that basically means what property is failing. So as you can see, path e-mail, value tests and I mean, you can make the assertions you want here. Okay? So that's great. Now, as I said, it's better to make things fail one at a time because that will facilitate testing. So let's try to do the same thing we did here. So let's copy it and paste it here. But this time, let's not pass Damian arrow. So in this data object, I'm going to remove it. And I'm going to rename this test to ensure error if we do not pass an email. Okay, So now these tests fail in basically because the error message is different. Okay? So Let's see. The error message is user.email cannot be 0. So yeah, um, I was expecting that because remember here I have the e-mail alone is equal to false. If we go to the documentation, you're going to see here in these validations and constraints. Constraints, sorry. And here you can see the difference between validations and constraints. Basically, validations are checks performed in this equalized level in pure JavaScript. They can be arbitrarily complex if you provide a custom validator, validator function, or it can be one of the built-in validators. Validators offered by civilized. So basically like we did in email, we use that built-in is email validator. And if a validation fails, no SQL query will be sent to the database at all. So that's great. And on the other hand, constraints or rules, rules define the SQL level. The most basic example of constraint is a unique constraint. If a constraint check fails and error will be thrown by the database and SQL as we move forward this error to JavaScript, in this example, throw in a civilized unique constraint error and know that in this case a SQL query was performed on like the case for validation. So very useful to know that. And where is it here if we go to validators, know here in this note about alone or implementation, it says the law, no, check is the own check-ins equalize. That is a mix of a validation and a constraint in the census described at the beginning of this tutorial. So I think I already told you that. So first it makes the validation at the JavaScript or SQL OS level. And if for some reason that fails, I mean that is successful. For some reason, which is very probably impossible. But I don't know it could happen by a bug or something like that. But then it will be a constraint that database. So in the database it will say, Hey, this is a null value. So I'm going to throw some error and civilized going to forward. Also, what I was going to tell you is that this alone, no. Where is it? Here in this example, you can pass a custom message like here that no message, Please enter your name. So here in the test, basically not putting any custom message that we can do it. No message. Email is required. Okay, so now you can see that this change, and we can also change it here. So email is required. And by simply doing that, then we are making these tests pass. Okay, so I think that you got the idea. I'm just going to repeat this one more time. But for the username error, if we create a user with an invalid username. So this time I'm just going to put up a valid email like this example that come. And I'm going to pass the username, which is going to be just one predictor. Okay, so it's just one character than these errors should be thrown. So again, I'm going to replace this with this, and here, this path should be the username path. So now our tests is asking, again, that's why I had told you that we can make very easily more than 10 tests for this. Because let's see what we're missing the test that this is an exercise for you. So we have here check this validation, this validation, but not this one, for example. So your exercise to create a user, then create again another user, and check for an error to be thrown. Here we need to validate is megatask for this, make a task for this. And here I think we have already. So yeah, we haven't made that four-person him, but it's pretty similar to username. So you can basically copy and paste and replace the error messages. And yep, So as I said, you can do lots of more tests for this create new user method. But for the sake of time, I'm going to let you do this as an exercise. Okay, so that's it for this lecture. I hope you like it. See you in the next video. Bye-bye. 35. Adding User model tests (Part 3): Hi and welcome back. So before we write further tests, I want to add a new method here in the test helpers that is going to help us a lot. So that will be a static Async, create new user. And we are going to pass some options. And this basically is going to create the new user using the model subjects. So we need the models. And here I'm just going to require source models that default, remember, the default export is these models object. Okay? And I'm going to deconstruct from the options. And we're going to deconstruct the email, which is going to be tasked at example.com. If we don't specify that field in the options, the password again, we're going to specify some options, the roles again, the same story. Okay? Let's say the user named the same story, the first name, the same story, the last name. So actually here, Let's put my name here. Okay? Also, we need the refresh token, which is going to be some random string. Okay, now we can get also the user model. So where is it you SIR model from models. And here I'm just going to create a data object with an email password roles, the username, the FirstName, LastName, and the refresh token. So very big object. And we're going to return user.name, create new user with the data, honestly. So, yeah, that's it. This is an async method. This returns a promise, so we can await on that promise. Now let's go back to our test here. Okay, so the next describe blocks. So remember these very big describe blog is a static methods. The next is going to be the scopes. So remember we have two scopes, the default scope and also the width passwords scope. Okay, so basically what we're going to do is to define this user. And before each test, we're going to pass an async call back. Okay? And here I'm going to sing this user to await tests helpers that a new user. And we're not going to specify any, any options here. Okay? And then this there is this nested describe blood. And I'm going to test the default scope. Okay? And I'm going to write a test same initial returning user with the passwords. Okay? Let's see. I'm going to get the user model from models. And I'm going to say user found or whatever. And I'm going to say await user find by primary key. And we pass a primary key which is the ID of the user, remember, available here. And then we can expect user found that password to be on the final. Okay, so this is very similar to the test that we did here, but they are not the same because here we're testing the hook, the hook. And here we are. We're testing the default scope, which is not the same thing, because the default scope is for queries. Okay, so let's run npm run test watch. Now let's see, looks like I have okay, So here in the test helpers, whereas it looks like I am missing an S here, typo. Okay, so now this test is passing. So by that, that means that the default scope is working. Now let's test the other scope, which is the width password scope. Okay? And here I'm going to say it should return a user with the password. And we're going to pass it a sink. And here I'm going to say models. User, user found the same thing, the same story. But this time I'm going to define the scope. So we say that scope with buzzword. And I can expect user found the password. So equal. And here it's basically any string. So expect any string. And let's see if this passes. Yeah, it looks like this is passing. So that's the test for the scopes. In the next lecture, we're going to test the only instance method that we have that ease these Compare passwords method. So hope you liked this video. See you in the next lecture. Bye. 36. Adding User model tests (Part 4): Hi and welcome back. So we are pretty close to finish our tests. Now we're going to test our Compare passwords, passwords instance method. So let's write another display block, same instance methods. So we're going to say Compare passwords. And we're going to declared these passwords. Okay? And before each test, I'm going to basically create any user with the password here and all the other information is going to be the default one. So the first task is going to be return true if the hashed passwords. Well, if the password is correct. Okay. So I'm going to get from the model subject, I'm going to get the user, the user model. So I'm going to say const, user. Wait. Yeah, maybe I'm going to also declared is user and assign it here. So I'm going to say again, user found, await, user.name, cope with password. So remember this time we need this password. And I'm going to say find by primary key user dot ID. And then I'm going to say our bus is password, correct? I don't know. I'm just going to make the spec. No, let's do it like this. Is password, correct. Okay. And I'm going to say await user found that compare passwords. And we pass the password. And we say is password correct. So equal true. Let's see npm run test watch. And this is failing. Let's see, this needs to be sync. Don't forget. Ok, now our test is passing and let's make another one similar. It should return false if the password is incorrect. Okay, so here I'm basically going to boot some random string, valid password like that. And obviously we need to change this from true to false. And there you have it. We have that this test is also passing. So that's basically it. We're not going to write more tests. So, yeah, I hope you liked this video. See you in the next lecture. Bye. 37. Adding User model tests (Part 5): Hi and welcome back. Let's go two models. You, sir. Okay, And actually there is a bug in our code. So we go to the user model. Here you can see that it will try to hash the password even if it is not passed. Remember, remember that this is before safe and not before create. So that means that these hook is also be triggered when we save or update user. So if we update the user, for example, we have did the email field, but we're not updating the password field, then this will fail. And why is that? Well, because we are not going to have the user that password field. Okay, So actually we shouldn't have skipped a test for the hubs. So let's try to add a new describe luck with the hooks. And let's just add a one test. And it will be it should not attempt to hash the password. If it is not given. Then sink. And here I'm just going to create a user with our test helpers. And then I'm going to say user that email test 2 at example.com. And then I'm going to say await user that save. So let's see if I have the database up and running. Okay, looks like another one. Let's do it again. Okay, npm run test watch. And as you can see, we have these failing tests. And this is because it says data and salt argument required. Basically. It's complaining because we were not present here any password. So easy solution. If you use her that passwords are going to do this. And that's it. The test is now passing. So yeah, this personal detail, but well, it's not small. It's a big deal. But the thing is that we're not going to update any user in the controller. So that's why I didn't realize that this bug earlier. So hopefully we fix it and that's it. Hope you like it. See you in the next lecture. Bye bye. 38. Adding Role model tests: Hi and welcome back. So we have created a lots of tests for our user model. Now, we can also test for the role and refresh token model. What are we going to test exactly? So here, there's not too much to test. Creating a new row. Well, that's pretty trivial. I didn't see anybody doing that. Maybe what we can test are these ON delete and on update cascade. So we can create a new user with some roles and then delete this user or updated and see if these indeed is updating the, the ID in this case or deleting those records in the database. So let's go and create a new role, that test.js file. And here I'm going to create this test helpers, going to important models. I'm going to go this describe block. And I'm going to say before all. Well, the same thing for the user tests. So let's actually just copy and paste. Okay. Now let's create tests Saint. It should delete the records. The role records. If the user is deleted. Let's bass and a sink call back. And let's take from the models, let's take the role model. Perfect. And this is very useful that test helpers create new server because I'm using also, using also it here. So I'm just going to create a new user. And the first thing I'm going to say is lead roles. And I'm going to say await role that count. And here I should expect, well, let's do something here. Let's define the roles admin and customers. So we have more visibility in the tests that these are the roles. Okay? So let's expect, when I was going to say here, Rawls, two roles for new user or whatever. So here I'm just roles, roles for new user. Again. So I was going to say Rolls dot length must equal roles for new user that length. So let's run npm, run test. And let's see, we have a failing test. It says test helpers is not defined. Oh, so it's test helpers. And here's test helpers. Okay. So let's see. Here I say, okay, so here it should be rolls count because we're already returned in the account. So Rawls count. And now we have the passing test. But this is not what we want to, what do we want to assert? We want to first destroy this user created. And then let's again made these roles count and say roll that counts. Okay? And now we should expect rolls count. So equal 0. Okay, so now our test is passing. Okay, we have created this test for deletion. Now, let's think about how to test this on update. Okay, for me, this doesn't have too much sense to test. And I'll tell you why. This means that when the user IV changes, then the user ID is going to change as well here. But let's think about this. When will the user ID change? Let's think about this in production. When will you want this user ID to change? I will say never. And the reason is that it's a bad idea to put things that change as primary keys. It's a really, really bad idea. So as a rule of thumb, if your column changes, then it shouldn't be a primary key. The primary key set. It shouldn't be changed. Never. Okay, so if we tried to actually change the primary key, so make a test and create a user and make the ID of the user change. Actually, SCL lines is not going to allow, allow that. Because cyclize is smart enough to say, Hey, this is the priority, we shall, we shall not change that. Okay? It's not going to throw an error, but you can try it yourself. And you're going to see that it's not going to change the user item. Because civilized considers that changing the primary key at runtime is very, very dangerous. And indeed it is. We don't want to do this in production. We don't want to change the primary key. So that's why I'm not going to make a test for that. And this is just for having consistency between our migration and the sorry, the what is it? Yeah, these are the model. I didn't find the word. Actually, we can remove this, but we can also, we need to also make sure that the migration is the same value is put. So also we, we put set null here. For me, doesn't really matter what we put here because we don't want this to reach this scenario. Never, never in production. Okay, so that's it for this video. See you in the next lecture. Bye bye. 39. Creating the Express app: Okay, So congratulations, are going through all of these model related things. I think it's the most complicated part of the course, but we have finished our guess. So now let's create the Express app. Are going to take object-oriented programming approach here. So let's create inside source file called app dot js. Let's import express ceramics. Let's import also the environment variables from I guess, config environments. Let's also import the logger from Morgan. So remember this is a package that we installed. Where is it? Here? And this is just a way to lock the requests. So I'm going to export default class called AB with a constructor. Okay? It's going to have a central routes method. It's going to have a get up, and it's going to have a list methods. So these are the formats that this class is going to have. So first of all, in the constructor and we're going to say this data is going to be expressed. Then I'm going to say these are apps that use. And here I'm going to say logger deaf. And I'm going to skip this. Accepts us a call back. Okay? And here I'm going to skip this environment that Nadav is equal to test. So we're not going to log any requests if we are under test environment because it will clutter all of our console apps. Then I'm going to use the Express Jason. And basically this is for parsing Jason. And I'm going also Use Express URL encoded. True. Okay, so this is not necessary if you want, just doesn't include it. But I'm just putting these four say for the sake of completeness, this is for parsing encoded URL. And these extended Drew says for using these QS library versus the string length. Again. Then I'm going to call this method. And this is where we're going to register our routes and also our middleware. Okay? So right now we didn't have any routes nor any middleware, so is going to do nothing. And in the gut app are just going to return these drab. And in the lesson, we're going to say comes from the environment. I'm going to get the ports. And here I'm going to say listen for it. And we're going to listen and that towards, and I'm going to answer log saying listen, listening boards. And we interpellate this port here. And that's basically another thing I want to do in the test helpers. So let's go to test helpers is to create in another method called get up and is going to be static. Get up. And basically we're going to get, we're going to require from source the default, which is this class here that we just defined. And simply we're going to return. And from that, we're going to call this, get up. And yeah, that's it. We're going to need this because, well, we move the app in our tests in order to use super test. So don't worry about it right now. We're going to do it later and you're going to understand why we need this test helper here. Okay, so that's it for this video. I hope you like it. See you in the next lecture. Bye bye. 40. Creating the errors middleware: Hi and welcome back. So let's create the simple, very, very simple middleware, which is going to be an errors mirrors. So it varies. If something goes unexpectedly wrong, one of our controllers, then we are going to catch this error in these middleware and return a response with 500 status, which means internal server error. And simple JSON objects such as false and the message, the error message. So let's do it. Let's create a new folder called middlewares errors. And here I'm going to say export default function errors, middleware. And these needs to accept an error, a request response. Next. So this is the weighing express knows that this is a nerve errors middleware. Usually these only takes three arguments, which is a request or response on next. But the errors middlewares, we have these additional errors object. So first of all, we're going to console error. Some message like error in errors made aware. We're good here at new line and print the Earth's time, which is useful. And then we're going to return, will not return that. Sent to these responses status, a status of 500, unsent success false. And the message, the error message. Okay? And then here inside the app, whether we're going to do is basically saying, these are the US and US errors middleware. So make sure that this is important correctly. And that's it. This is how we're going to catch any errors thrown in our controllers. See you in the next lecture. Bye bye. 41. Creating an Async Wrapper for catching errors: Hi and welcome back. So first of all, I wanted to say that we haven't created any tests for these errors middleware yet, because we can do these tests on the controllers that will be better. If we tried to make a test only were these function here. We need to make these and these and these. And that's not funny. So we are going to include these tests for the errors middleware later on the course. Okay, So now that I have told you that want to create utility function. So here I'm going to name these. Run. A singer, rapper, or maybe just sink wrapper will be a better name. Okay, so here I'm just going to export default seem wrapper. And this is going to accept the call back. Okay? Before implementing this function, before implementing this, let me tell you why we are implementing this. So when we have a sync code in our controllers, which is basically 99 percent of the time. If we have any error that is around there, then right now that error is not caught by that errors middleware. Unless we catch, we have a way to catch this error. So this is not going to be a problem in Express 5. Let me see if I'm correct. Yeah, we're using Express for and in Express 5, this is going to be implemented natively. So you didn't have to worry, you didn't have to do anything if you're in the future and you are already using Express 5. So here I'm just going to return a function which receives a request or a response and neck. And he's going to call these callback with the request response. And next. And I'm going to catch any errors. And if I catch any errors, then I'm just going to call this next here. Okay? So that's basically everything we need to do here. And these will make sure that we catch any error, any error thrown by any async function. So we hope you like it. See you in the next lecture. Bye bye. 42. Creating the Auth middleware: Hi and welcome back. So let's create another middleware. We're going to call it requires off. And these middleware is going to help us to verify either the access token or the refreshToken depending on what we want to verify. So I'm going to import JWT Utils from YouTube, JWT utils, okay? And then I'm going to say export default function requires us. And this is going to receive a token type. And we're going to default to access token. So now let's return a function. And this function is going to receive the request, the response, and the next function to call the next middleware chain. Let's get the auth header. Request that headers that authorization. So remember, this shoe contains something like this, bitter and sums like this token. Okay? So we're going to say if our header, we're going to try something here, try-catch. So in the try, I'm going to var not let, not const bar. And we're going to see why bearer token auth header, that is split. And here I'm going to split by the empty space. Okay? So this should give me just two things, the bidder and the token. First of all, we're going to verify that the bidder is indeed better to lowercase d should be equal to bidder or not token. Okay? And if this doesn't happen, then we're going to throw an error. And we're going to catch either if the error is here or if the error occurs in these split, we're going to return a response saying for a one that means not authorized. And a message or use an object with a successful and the message. Same beater, token malformed because yeah, the bears organismal form, right? Okay, so that's in the case that the auth header is present. If the header is not even present. So that will be the else. We're going to return, rest that a status for a $0.01 success and message authorisation. Heather not found. Okay, so now suppose we went through all of these. This didn't error. Then we need to actually verify the either refresh token or access token. So for that, I'm going to put another try-catch here. Okay? And in this trie, I'm going to say let JWT, and I'm going to say switch token type. And in the case is the refresh token. Then we simply are going to say JWT is going to be equal to j WGU tills that verify refresh token, pass the token that we splitted here. So that's why we are using var here instead of letter costs. Because lead or cans have a block scope, meaning that they will only be available inside this try block. But we're actually using this token right here. So for that, we need this token to be available throughout all of these functions here. And that's why bar is useful because they have function scope. So let's break here. And in the case we are dealing with an access token. We're going to do the same DWT, DWT uterus. But this time we're going to verify the access token. Okay? Okay, great. And if none of these things errors. So if this didn't throw an error and this didn't throw on there, then we're going to sign this JWT to the body of the request. Request. The body that JWT is equal to JWT. And we call the next function to go to the next middleware. Which in this case it's going to be the controller. In the catch. Something went wrong verifying the access token. So we're going to say send, success, false message, embedded token. Okay? So I think this is everything we need to do for these requires a middleware. And remember, we're not going to write tests yet for this middleware because it will be 100% issued to do it inside a controller. And that's what we're going to do when we write tests for our controllers. Okay, so that's it for this video. Hope you like it. See you in the next lecture. Bye bye. 43. Structuring the controllers: Hi and welcome back. So it's time to add our controllers. So let's create a new folder called controllers. And here we're going to add an index.js file. We are going to see how our structure, and we're going to import where it said here, I'm going to import the V1 routes, which we haven't created yet from the controllers folder, which remember is this index.js file. And here instead routes, I'm going to say that use the slash v1, v1 routes. Okay? Okay, so let's see how we are going to get this b1 routes inside controllers. We're going to create a new folder called V1. And inside V1, we're going to create another index.js file. And this, and here I'm going to import router from express. And I'm going to create the router, this router. And I'm going to export default this router. And between this line and this line, we're going to register all of our controllers, like the register login, logout, and token controllers. Okay, but now that we have exported this, let's go to this index.js file, which is empty. And I'm going to import the defaults as V1 routes. Or you can simply import view on routes from V1 like this. And I'm going to export these v1 routes. Okay, So this is how we're going to structure our app. When you have big projects, maybe you are going to work in a new place. It's very possible that they have multiple versions of their APIs. So suppose you're in a startup, maybe they are working on the V1 endpoints because that is the first version of the endpoints. Now thinks years go by and things go well in your company. The start improving things and they start migrating or creating new endpoints inside the V2 routes. So that's why I am doing this. Because this is one of the best way to go into the, one of the ways you're going to find when defining APIs. Okay, so that's it. In the next video, we're going to start building our register controller of you like this video. 44. Creating the register controller: Hi and welcome back. Now let's go to the, I will say fun parts of it. Easy part of it. I wouldn't know how to name this, but that is to build our four controllers. So the first one is the register or sign-up controller. Okay? I'm going to name it register. And here I'm going to import again router from Express. I'm going to import the models from the models folder. And I'm going to import the async rapper from that utils folder. Or is it utils async rapper like this? And also I'm going to import JWT Utils from see utils DWT. Okay, so first thing, let's create these runner like this. And let's get the user model from the models objects. Perfect. Now, registering will be a post request. So we're going to say router dot post. And here we pass the name of the route, which is going to be register. And we're going to call this async wrapper. And remember, these receives a call back. So the callback is going to be an async call back. That is going to get the request, the response, and optionally the next, but I'm not going to use that, so I'm not going to include it. Okay. Let's see. Here is all the logic that we are going to have in our controller. But guess what? We have almost created everything inside the model. And that is good because we need to have thin controllers. All of the logic, all of the heavy logic should VE in the models. So from the request body, Let's get the e-mail, the e-mail, and then let's get the user, Let's find the user. So for that I'm going to use weight user.email, find one. Okay? And I'm going to say where email, so that's why. Well, there is already an index for that because email is unique. When we create something that is unique, and index is automatically created. And then I'm going to say if the user return rest, that is 200, but we're going to send success false. And we're going to say message, user already exists. Okay? So remember this is the register controller. And if we have a user already with this e-mail, then we cannot create another user. Okay, so that's a little verification. Now let's see the case where these user doesn't exist. We're going to create a JWT payload with an email. We're going to create the access token. Like these data beauty you tills that generate access token. We pass the payload. Our going to generate also a refresh token like this JWT cells that generate refreshToken payload. Perfect. And here we're going to await user dot create, new user. Okay? And I'm going to say, I'm going to pass all of the data in the request body. Okay, request body and as well as the refresh token. Okay? So that's it. Then. This doesn't fail. We return a response which is going to be status to a 100 percent. And here we pass an object same success through a message saying user successfully registered, and also a data object with the access token and the refresh token. Okay? So that's basically it. It's a very thin controller in my opinion, but it does what it does. Creating a new user, generating the access token, the refresh token, and sending that to the client if this is successful. Okay, and if we have user already in place, then we're just going to say, hey, the user already exists, go to your house again. So that's it. We're going to add a test for this in the next lecture. So I hope you like it. Bye-bye. 45. Tests for the register controller: Hi and welcome back. One thing that I want to mention before writing the tests is that here, remember, we made discreet user to return the user. Okay? And this is going to be an instance of the secularist model. So if we try to do that, we can run into problems because this is an adjacent instances where an instance of a class. So something that you can do is like this, is her equal to user, to Jason. I think it's all capital here. That's one way, but still it probably is going to have information that you don't want to include. And that's where serializers coming to help. Because with serializers, you can pass an instance of the equalized model and return the attributes do want based maybe in complex things like rules and things like that. So that's adding just another layer of complexity. And that's why we're not going to return the user inside here, but it's still an option to do it and spray cone to do it as well. So inside the task, Let's create a new folder called controllers. And inside controllers, let's create the V1. So these are going to be the tests for the V1 controllers. And let's say register that test.js. And actually, let's steal some of these setup here. Where is it? And obviously remove this test here. Okay? Let's remove this as well. Okay, so we have almost the same, the same setup here. I have to import this correctly. And let's see here, Let's change this to register. And also I need request from Super Test, which is going to allow us to make fake requests to our app. And talking about up, we also need the app. So that's why before all, we're going to get from Test Helpers. Get up. So that's how we are going to get beat up. Everything is going to be the same. And here we're just going to add two tests. So the first one is the success. It should register user successfully. Perfect. That's a test. Same roles, for example, at mean customer. And now I'm going say Kant's response equal to weight. We're going to make a request or up. And we're going to make a post request to slash v1 slash register. And we're going to send with the following body. E-mail is going to be something like this. We're going to say passwords, something like this. Remember we can send plain text passwords on the body because maybe our client is using HTTPS, so that will make sending these plain text password safe. We're using HTTP, obviously that's unsafe, but I don't think you want to use HTTP untainted by one. So let's see firstName, lastName, and the roles. Okay? So look how we are not including here the refresh token because this is more high level, because we're refresh token is created inside the controller. Okay, So our first test will be something like, well first, let's make sure we have running. And then here, we can expect these to return to a 100. So that can be our first test. Let's run npm run test watch. Okay? And this is failing, and I guess it's because we're using a weight without async still failing. Let's see. Okay. So this maybe it's like this probably. Oh, so I'm getting 200. Okay. Got 400, 400 found. And the reason is simple. It's because I forgot to register these these route is router here. We're not even exporting that, so that's what we need to do, export default router. And here I want to say import register router from from register. And here I'm going to say router that you register rudder. And that's it. Now we're going to have 44 and tests are passing. Okay, So yeah, we're making an assertion that this is returning to a 100, but I think that's not sufficient. We can also expect the body. So we can say expect response that body, that success to equal, true. We can expect a response message to equal. What is it user successfully registered, okay? And then we can make assertions on the database itself. So I'm going to get the user and the rural, and the roles are from the model subject. Here, I'm going to search for all of the users, so it should be only one. You, sir. Final on here, I'm going to include the role. So I'm going to eager load the role in the query. I'm going to expect that the users that length to equal one because it's you have created just one user. And then I'm going to get the new user created. So that should be the first element of the users array. And here is where we can get creative and start saying, this should equal to this thing here. So in order to be more and more organized, I'm going to put everything here inside these data objects like this. In fact, this, as we did in the model, remember, okay, so I just need to send data. Okay? And here I can say these two equal data that email that she will pass. Yeah, it's passing. Now, let's do the same with username, firstName and lastName. Username. Here, firstName and lastName. Ok. So this should be passing yards passing. We can expect also that the user, that partner is not present. So these would be undefined because remember, we have in a default scope, don't return me the password. We can also expect new user roles that length to equal two, okay? Because we are creating two length, sorry, two rows. This is capital R. And here we can say that the role that length to be more precise. Okay? And what else I can expect on the saved roles, the user roles. And remember, we can map the same rule to the name role. And I can sort this. And I can expect saved rules to equal data. That rules of sort and tests is still passing. Okay? Yeah, we can also, we want to include here are the refresh token model. So let's do that. So let's see include role, include refresh token as well. And we can expect, we can expect here new user that refresh token, the token to all, expect any string and that she will still pass. Yeah, so this is still passing and this is a pretty descent test. Now, let's test another case. And that case will be when we create a new user, and then we try to create a new user with the same email. So it should not create a new user if it already exists. That's going to be the name of our tests. And I'm going to say a wait request, posts slash nuanced slash register. And I'm going to send just the email and password to make this test. Note that verbose. So password, whatever it's 123, and we can expect this to be 200. Okay, so we have created our user. Now, let's try to duplicate this thing here. Actually, I'm having a failed test and that's because I'm not using a scene here. Okay. So here I'm going to duplicate these requests that I'm going to assign the response to see the well it contains. So I'm going to say responsive body that success to equal false and response. The body that message to equal user already exists. Okay? So the test is passing, meaning that this is getting, we're getting this response when we are trying to create a user that already exists. So that's it for the tests. I hope you like it. See you in the next lecture. Bye bye. 46. Adding the login controller: Hi and welcome back. So now that we have our tests for the register, let's go to the next endpoint, which is going to be the login endpoint. Okay, so in cell B1, let's type login dot js. And here, let's actually just copy and paste everything here to have consistency. But obviously we need to replace this with login or sign-in, whatever you want. And other logic here also is going to be different. So until here. Okay? So the logic here is going to be the following. We're going to get from the request body. We're going to get the e-mail and the password. Okay? I'm going to get a user with a weight user, and I'm going to use the scope with password. And I'm going to say find one where I need to pass this where email. So I'm going to find the user with this e-mail. And first of all, we're going to say, if there isn't a user or a weight User.com passwords, remember our instance method and we pass a plain text password, then we're going to return early status for a one, send success, false message, invalid credentials. Okay? So this can happen because the password is incorrect or because email is incorrect because we didn't find a user with an e-mail. And that's why we're using this message here. Okay? Now we're going to say payload is going to be equal to email. Okay? And we're going to say access token. We're going to generate an access token. Jwt utils that generate access token. Because the payload. And then we're going to fetch for a refresh token, the refresh token table. So we're going to say Save, refresh token, await, user.name, get refresh token. So remember that here we could do something like include refresh token. Okay? And this is called eager loading because we are including the refresh token information ahead of time. But that's totally up to you. I will not recommend doing that because we can, there is a chance that we are returning early and that information It's simply not useful. This is called lazy loading because we are getting these information when we need, well, we need them, we will need this information. And that is after we have passed this check here. Okay, So then I'm going to declare these refresh token variable. And I'm going to do the following. Check. If there isn't a refreshToken saved refresh token or there isn't a token. The refresh token records. So this means there isn't a record in the refresh token table. And this condition means there is a record that the token field is null or empty. Okay? Remember if we go to our model refresh token here, we're not seeing anything like allow no false or something like that. So we have these two cases. And in both of these two cases, we need to generate a new refresh token, right? So I'm going to say JWT utils that generate, raise it, refresh token, and pass the payload. Perfect, Now let's see if we don't have a refresh token saved in a table. Now we're going to create a refresh, so m. Okay? And we pass this object refresh token. Okay? So if there isn't a record in the database, we create a new record into that database. And if there is a record in the database, well, save that new token, the token field like this, okay? And save it obviously. Safe, safe like this. Perfect. So this is a case where the refresh token is not present in the table or there's a record but that token is empty. But if these two conditions are not met, and if these two conditions are not met, and we are going to sign their first token to the save, refresh token. The token. Okay, So that's it. Then we need to return the response. And that is going to be 200. And we sent, and we say success, true. We say message, successfully logged in. And we pass a data object with the access token and refresh token. Again, if you want, you can pass this user but denier serializer, or you can do something like this email user.email. And that will also be correct, but it's better to have a serializer. But we're not going to do this in this course. Okay? So you can, if you want to pass the user, you can do it manually, like this or the e-mail. You want to pass a username, maybe user the username and things like that. But I'm not going to do it like this. Okay, so that's it. In the next lecture, we are going to actually write the tests. Hope you like it. But, well, first before we go, let's go to that index and let's import the login rudder from logging and say rather than use login rotor. Okay, that's it. Hope you like it. See you in the next lecture. Bye bye. 47. Adding a new test helper: Hi and welcome back. Before we do our tests for our login controller, we're going to add a new test helper. And it's going to be called register a new user. So you might be saying, Hey, we already have a method for that. It's creating user. Well, yes. But we want these to call the endpoint, well, use request, the request from super tests, so called the endpoint. And that is because the end point is going to return us the, sorry, the access token and refresh. Okay? By the way, we can also do that. We can also make the JSON Web Token, sorry, the access token, the refresh token to be returned here. But I will prefer this. And that these methods is not concerned about returning any refresh token or access token. So email will be tested at example.com. And password, I will default it to whatever. And I'm going to have a third property which is endpoint, which is going to be one register. I'm going to return requests. And here I'm just going to call it the helpers get up. And I'm going to post to the endpoint. And I'm going to send I'm going to send the email and the password. Okay, so now that we have these methods, in the next lecture, I'm going to use it in order to get the response, the response here. Okay, hope you liked this video. See you in the next lecture. 48. Tests for the login controller: Hi and welcome back. It's time to make some tests for the login. So let's create a new file login that test.js. And for the sake of time, let's copy everything here, paste it here, and remove the existing tests like this. Okay? And there's actually one thing that we need to include here in the before. We're going to create this variable, new user response. And here I'm going to assign that new user response to test helpers. Register a new user email. I'm going to pass this signal here for the password, and we're going to pass these password here. Okay, So now we're going to creating new test. It should login a user successfully. So that is going to be the success case. And it shows, Let's define this response and let's make a request to the app. It's going to be a post requests slash be one slash login slash sand. And we pass the email. We test our example that come. We pass the password, which is Test 1, 2, 3. And let's see, we can expect this thing to return to a 100. Perfect. And we can't get the refresh token from the response. It will be responsive body that data to the refresh token. And we can expect the refresh token to equal the new user response, the body data that refresh token. Okay? So remember that when we call this register a new user, it's calling the register endpoint. And that means that we are creating a refresh token records in the database. And so if we go to the logic here where he said, so if no, It's login, sorry. So if the refresh token exists, we're just going to return that refresh token in the response. Okay, so that's our first test. Now the second test is it should return, return for a one. If we pass an e-mail that is not associated with any user. Remember this is a sync. This should also be sink. And here I'm just going to copy and paste this thing. And here I'm going to change this to 40 1. And here I'm going to pass different email. So expect, we can expect the body that success so equal false and response that by that message to equal invalid credentials. Okay, let's run test watch. Okay, So all of our tests are passing. Let's repeat these tests. But now we're going to say if we pass an invalid password. So this time it's going to be a valid email but invalid password. And these expect she'll stay the same. Okay. We have three tests. All of them are passing. Now, let's make one more. It should create a new refresh token. Record. If there is not one associated with the user. So first of all, before we write this test, I want to say that this is pretty, that the probability is very low that this thing happens. Because when we create a user, we are going to create a refresh token record. And when we log out the user, which is something we haven't done. We haven't done yet, sorry. We're not going to delete that the record, but we're going to actually send that token field to know. Okay, so that the case where there isn't a refresh token, the refresh token table, it's pretty low, but still can happen. Unexpected things can happen in production. So first of all, I'm going to get from the model subjects, I'm going to get the refresh token model, and I'm going to delete everything here. So destroy where an empty object. Then let's refresh tokens. We refresh token that the count refresh token. Tokens count. Okay? I'm going to expect refresh tokens count equals 0 shall be 0 because we deleted everything. Then we're going to make the request to our API. So lets actually copy this one. Okay, Great, So we don't want the response here. Okay? Now, what we're going to do is to say, yeah, it's going to say refresh tokens count. It's going to be refreshToken the count again. And we can expect refresh tokens. Refresh tokens count to equal one. Okay, so that is indeed proving that we are putting something in the database. You want to be more strict. You can get the actual, you can get the actual token, this one, and expect, for example, that the token is not null or something like that. Okay, let's write our last test. It's going to, and this is going to happen. So set the token field to a JWT if this field is empty. So when we logout the user and telling you this right now, but we're going to see it as well in the login controller. We're going to find our refresh token in the database associated with the user and the token, we're going to set it to null. So for that, I'm going to get from the model's going to get the refresh token. And I'm going to get the refresh token from new user response body, that data, that refresh token. We're going to fetch that saved refresh token in the database. So we're going to say find one where n is equal to that refresh token. Then what we're going to say is set this field to know and obviously then safe. Okay? And then we're going to make direct requests. Let's copy and paste this. And now we need to reload the refresh token. So it can have the latest information. And we can expect save, refresh token, the token not to be. Okay, So this is path passing and that is great because it means that when we logout and then we'll again, then we're going to have a new refresh token. So that's it for the tests. Hope you like this video. See you in the next lecture. Bye bye. 49. Adding the token controller: Hi and welcome back. Now it's time to create our token controller. And this token controller, it's function is going to be to return a new access token provided we have a refresh token. Okay, so I just copy and pasted everything from the Login. Obviously shear, I'm going to change it to token. And here we're going to need also the refresh token model. Okay? And what else? Let's see. Let's remove all of this logic here. Okay, now we have a clean controller. Now, here we're going to need the Requires of middleware because we're going to need in the authorization header to have the refresh token. So I'm going to say requires. It's not helping. So let's import it manually. Of course, from middlewares requests on. Okay? And here I need to pass a token type and it's going to be a refresh token type. Okay, So if we are making a request and it doesn't contain a bidder token or malformed or anything. We're going to actually write test for that. Then this logic here is not going to be executed. Okay, so let's try to get from the request body. I'm going to get JWT. So remember we put this data in these Requires off and from the JWT we can get the email. Okay, perfect. Now let's, let's find a user with a email. Await user. Find one. And I'm going to say where email is the one that we passed. And we're going to include the refresh token model. So we are going to eager load the refresh token. That means we're going to have the refresh token information already. So I'm going to get the safe token, user dot refresh token. And here we're going to say if we didn't have save token or if the same token, the token is, is null or something empty, then we're going to return the elderly with an a status of 01. And we're going to send successful. And we're going to say message, you must log in first. So remember when this token is null, that means that we logged out and actually we're going to write, are going to write that logic in the lockout controller. So this means that you need to login first. Then we're going to build the payload, which is just going to be the email. And we're going to generate these new access token with JWT utils that generate access token. And we pass a payload. And finally, we return a response with 200 status and send success true and data access token, new access token. Okay? So that is all of the logic that we need for this token controller. This will generate In your access token every time we hit this endpoint. So that's it. Hope you like it. See you in the next lecture. Bye bye. 50. Token Controller Tests (Part 1): Hi and welcome back. It's time to add some tests for the token controller. So let's go to the test folder V1 and creating new file called token that test.js. Again, I'm just going to save some time by copy and pasting and deleting all of the tests here. Okay? So I think everything else is going to stay the same. But first of all, remember that we said that we were going to tests these middlewares inside any of their controllers. So right now in the token dot js flower using these recourse off. So I think it's a good time for making some tests related to these middleware. So let's start by doing that. I'm going to put a describe block with the requirements of people work. And I'm going to say it should fail if the refresh token is invalid. Okay? So let's see. Can get our response by Colleen, request up pose slash, v1 slash token. And I can set here and authorization header. So I can say authorization. And here I can say visitor on something like invalid token, whatever. Okay. And then I can send the request without any parameters. And I can expect a 401 which is unauthorized. Okay, let's see if the test is passing. Npm run test. Watch. It is not passing. And we have 404. Once again, I forgot to include the Tonkin in this router. So we're going to import Tolkien or router from Tolkien. Okay, token rather. And I shall get something different this time. Yeah, This time the test is passing. We can make some additional assertions by Saint body that success so equal false. We can say a responsive body, that message saying embodied token. Okay? Okay, The test is still passing. Let me just change here to run. Let's see. I don't know why it's running all of the test. It will run only the ones related to token that, well, I don't know what is happening right now. So let's continuing with the testing. I'm going to say it should fail if no authorization header is present. Let's see. Here I'm going to say conf response and I'm going to copy and paste this. But this time I'm going to send without this set here. Okay? And I shall get to 41. And I can also make assertions on the body. This will equal false, and this message should be authorization header not found. So remember, these messages and things like that are in that definition. Like here, we're just in this case here where the authorization header is and found. The last time we were we were sorry, we were testing this case here. What else? We can I'm going to make just one more test saying it should fail if the authorization header is malformed. So the same thing. I'm just going to copy and paste. And here, remember the message that we are going to, sorry, not this one, but let's go here. The message that we are going to test is this one. This is a case we are going to test bitter token malformed. So let's change it here. And to get to this case, we need to set the authorization header. Third session while we need to set it to something which is invalid. So I'm just going to say mallets or something like that. Okay, so right now, all of the tests are passing. Okay, So we have tested successfully these requires of middleware. Let's try now to test these errors. Middleware which we haven't write a test for. So here I'm just going to same errors middleware. And I'm going to say it should return 500 if something went wrong. So let's think about this for a moment. First of all, let's go to that token controller. Okay? So as you can see here, we can make this controller fail. If we find a way, for example, to these DWT utils that generate access token to throw an error. So that's exactly what we are going to do. We're going to pass a valid request data. We're going to make this thing fail. Okay? So how do we do that? Well, first of all, first of all, I'm going to define this. Dwt utils, a spine, and this is going to spy on JWT utils. So I hope that this got imported correctly. Okay? And on these JWT UTS, I'm going to spy on that generate access token method. And then I can say JWT utensils by that mock implementation. And here I can say, Hey, make this thing, throw an error. And I can say test error if you want. Okay, so now let me get the refresh token from the newly created user via these new, this test helper, this test helper register. A new user, returns these knees her response. So I can get the refresh token from body, that data. Refresh token. Perfect. Now I can get the response by making a valid, a valid request. And for that, I'm just going to copy and paste this. And here I'm just going to put something valid, which is going to be something like this. And then we're going to interpolator refresh token. So now this request is valid, meaning that we have to expect here 04 or 500. Okay? So let's see if this is passing yards passing. So this is throwing an error which is 500. That means internal server error. And before I forget, don't forget to mark restore, to restore this this JWT utils. Otherwise, the other tests are going to fail. And we can also make assertions and the body success in these needs to be equal to false. And here on responds that body, that message. If we go to the errors middleware, let's see in the message it going to be this error, that message. And remember the error message is this test error. So here I can say test error. And this should be passing. And indeed this is passing. So for now we're going and also look at this test. It's console error. So there's a way to suppress this her in just butt. And I'm going to do the, to do it right now. But this tell, this test is still passing these console error is just this thing here. Okay? So looks like all of her tests are passing, but we haven't made any test for the token controllers only for these two middlewares. So in the next video, I'm going to start doing the tests for the token controller. 51. Token Controller Tests (Part 2): Hi and welcome back. So it's time to actually write the tests for our token controller. So I'm going to say it should get a new access token. Successfully. Going to actually just copy and paste this. But this time I need to expect to 100. And also I can, from the response that body, that success to equal true. And from the response.body that message. So equal not message, sorry, this time it's data because we didn't have a message. If we go here. Here we have data, access token and access token. And here I am seen the diamond, a typo and a wire for this, but it should be sent. And here these needs to equal access token. And access token can expect any string here. Okay, so now the test is passing. Now let's make another test for when we didn't have a refresh token. Or the refresh token is no. So basically this case here. Okay? So we can make any of these conditions. As I told you, this condition is less probable that these one, because this one is harsher, but this one is not going to be very common. In fact, you shall never expect that. But as I said, in production, anything can happen. So here I'm going to say it should return for a one if there is no saved refresh token for the user. So this, we are very ambiguous. It can be this case or it can be this case. Let's go for this case, which we know it can happen again. So for that I'm going to need the refresh token model. Okay? And here I'm just going to say, where is it? I'm going to get first the saved refresh token. And I'm going to do it by first fetching that. So find one where Tolkien is equal to refresh token. And then I'm going to say Save refresh token. The token is equal to null. And then I'm going to save this refresh token like this. Okay? And here I need to expect a 401. Okay? And here in the response, Let's see. Model is not a fine. It should be modeled, sorry. Okay. And in the response, it is going to be successful. And message will be, you must login first. Replace this with this. And let's see if the test passes right now. And yes, the tests are passing. So that's it for the token controller tests. See, See you in next video. Bye bye. 52. Adding the logout controller: Hi and welcome back. It's time to add our last controller, which is going to be the logout controller. And before I forget, let's first copy paste. And here named is to log out. And before I forget, I'm going to register it here. Logout router. The router. Router, the logout router. Perfect. Now here I'm not going to require the refresh token, the access token. And for that, I'm just going to leave this as an empty list of arguments because remember, these has as a default the axis w. Okay, so let's see, I'm going to need everything here. You will need something, then I'm just going to remove it. Okay, so let's start putting the logic here. I'm going to get from the request, the body. I'm going to get a JWT. I'm going to find the user. And here I'm just going to add the e-mail. And I'm going to find the user, user that find one where email. And I'm going to include here the refresh token level. Okay, so I'm going to say user that refresh token, the token equal to no. And then I'm going to simply save this. Okay? I need to await. And finally, I have to return 200 with a message saying success, true and successfully logged out. So that's it for the logic. We don't need this JWT YouTube or we're going to remove it. And that's it. That's the only thing we need to look out. A user. See you in the next lecture. My vein. 53. Adding logout controller tests: Hi and welcome back. It's time to add some tests for our logout controllers. So let's say load out that test.js. Lets actually copy everything here is here, and remove everything until here. Because we're going to keep this test here. Let's remove this one and this one. So we're going to keep this test year. And the reason is that v, if we make a request to logout, It's going to first go through that middleware. But remember that it is going to be now the access token. So it is going to go here. And in the other tests it was going here. Okay? So that's important because now we are covering this line with a test. And basically it's the same test, but just changing the route here. Let's change also here the load out and everything is going to be the same. Now let's add the test for the controller itself. Let's run. Just watch. So yeah, the test is passing. Now let's say that it logout, be user, successfully. Sink. Okay? And I'm going to get the access token from the new user response, the body, the data that access token. And then I'm going to make a request, a wait request, that post slash v1 slash knockout, that set set. And here we're going to put bitter access token. And we're going to send a request. And we are going to expect to 100 here. And we can make additional assertions under responsive body that success, true and message successfully locked out. Perfect. Now let's make another assertion and the database. So for that, I'm going to get the user and the refresh token model from the model subject. And I'm going to search for the user, you sir, That find one. Where email is. Test our example of KM. And I'm going to include the refresh token model. Okay? And I'm going to expect user that refresh token, that token to be no. Let me see if there is a matcher to be no. Yeah. Like this to be known. And both of these tests are passing and I think this is everything. We are going to make that remove these because we're not using it. Let me see if here we're using it. Here we're using a game. So that's everything for this video. I hope you like it. See you in the next lecture. Bye bye. 54. Inspecting our coverage: Hi and welcome back. So we have added tests for all of our controllers. Now it's worth seeing the coverage of these tests. So remember that we created this script here, test coverage. So let's run it right now. Okay, so first it is going to run all of our tests again. And it's going to create this coverage folder that if you remember, we put in the beginning of this course in the gitignore because we didn't want that in our ripple. So here we have these LC report and here we have these index.html. Let me see. Yeah, I cannot. So let's click here. Let me open Google. Okay. So as you can see, we have 96.91% of its statements and 90.59 of the branches covered. These percents dash a function and this percentage of nines. So first of all, let's see at the source and let's see what are we not covering? Well, we're not covering the listen because in the test we're not calling this method. And that is totally expected because we don't want to create to listen and support for our Express app. So this is fine to be uncovered. Let's see what else in conflict we have everything in controllers. We have almost 100% everything. Okay? So that's great. A here we have branches, function. So everything is like 100% and that is great. And let's say in the middle worse, we also have 100% models. We have 100% in branches. We're missing something there, but we still have everything in green. In YouTube's when 100 percent the same. Well, for the test, women have something that is missing on the branches. For example, here, we're not using these default, but that's totally fine because we don't want to test the test helpers. Okay. Then in the database, Let's see what we're missing. Well, it looks like we're missing this console log, but not fine because again, we are in the test environment, so we're always going to, we're never going to have this. Again, this console log is when we are not in that test environment. And the same applies for this console out. So it find that they are not covered because with the test, we're never going to cover this. Because this is going to be only executed if we are not in the test environment. So the important part here is the controllers and models. So those are the things that are really necessary to be tested. And we have done a great job and covering almost every case inside these two folders here. So that's it. Hope you like it. See you in the next lecture. Bye bye. 55. Listening for connections: Hi and welcome back. So now we have everything in place. We just need to do something else, which is to actually put in the server, the app. And that is very easy. I'm going to say counts require slash up are going to import the default. And we're doing this because if we imported here, we're going to import also the controllers, for example, where I went import this thing here. And we're going to have that models is an empty object. So we need to first connect to the database and then require the app. So that's good, this as a capital up. And then we're going to say const new app, okay? And then call this app dot listen. And that's it. That's now, now we can run npm, run dev. And as you can see now we're listening on port 8080 and we are ready to make requests to our app using anything like Postman. So that's what we're going to do in the next video. Bye-bye. 56. Testing our app manually with Postman: Hi and welcome back. Now let's run this command, npm, run dev. And let's go to Postman because right now we can start doing requests. So let's say localhost 8080 slash v1 slash register. And in the body, I'm going to say wrong. And I'm going to select JSON. And I'm going to say email. An example that come. And I'm going to say password, test 1, 2, 3, whatever. And let's send the request and see what happens. User successfully registered. Now let's go to the beaver and see if something got created in the main database. So let's go to schema's public tables, users, and let's go to data. And there it is, you have your new, your new user, right there. We tried to send the request again. User already exists. Let's see, Let's duplicate this tab here. Let's type logging. Okay, and also by the way, that's go to the refresh tokens. And as you can see here, this refreshToken got created. Okay? Okay. So this same refresh token should be sent to us when we login the same user. Then we just copy this thing here and bases, well, it was already there. Let's send it. And this is the refresh token that is in the database. So let's say these ends with BA. Let's see this one. It ends in BAA as well. Now we have the access token so we can log out. Or let's first test what I said, token. And for that I'm going to select here authorization. I'm going to say bitter token, and I need to paste the refresh token. So let's copy this and paste it here. And let's send the request. We don't need a body this time, et cetera requests. And there you have it. It gave me this refresh token, sorry, this access token. Now let's try to log out. So for that I'm going to grab this access token. Okay? And let's go here. And let's go to authorization. Let's get these were as it were and we are token. Let's paste this access token without the quotes. Okay? And let's send the request to see, but first logout, okay. And there you have it successfully logged out. Now, let's see. Let's try to send this request and it test. You must login first because I logged out. Let's login again. Okay. Now I have to pass this refers to put it here. Hey, send requests and there you have it. So this is how we test manually. But all obviously, we are not relying on this. We are relying more in our in our tests. That's what I wanted to say. Okay, so that's it for this video. Hope you like it. See you in the next lecture. Bye bye. 57. Using the debugger: Hi and welcome back. So there's actually one more thing that I wanted to teach you and that is how to use this debug a script here. So if we run npm, run the book, and we're going to start the app. But additionally, you can see that here, we're listening, that the burger is listening on this thing here. Okay, so if we go to chrome colon slash slash inspect, then here we're going to have these remote targets. If you don't see that, then you can put these local host colon 29229. Okay? But here we can click on Inspect. And these will give us access to the console that we have here. So as you can see, we have now debugger attached. Where is it? Here? Okay. You have all of the tools that we can use for the debugger, like the console, like the sources, like the memory, whatever. Okay, So let's try to, I'm going to go to Source controllers. I don't know login. And here I'm going to put a debugger. So, well, this is one thing that can be improved. And that is that I have to go here and click on Inspect again. And here I'm going to send. And as you can see, this is taking a long time. And that is because here we are hitting these debugger here. And you can, for example, look at all of these variables here. You can step over and start seeing the variables here. Look at the call stack and things like that. You can also step into functions like here. So if you step into the function, you are going to go to the function definition of January taxes token. You can step out of the current function and it will go to the controller again and things like that. So this is how a pro debugger uses this script. And that is because lots of students still think that console log is the best thing on there, but debugger is the best thing other. Okay, So that's everything for this video. See you in the next lecture. Bye bye. 58. Conclusion: Hi and welcome back. So you have reached the end of this course. Congratulations. What have we learned here? Well, a lot. And probably the most important skill that I want you to have from now on is testing untested code is broken code. We also learned how to use the ORM. But it's not only SQL ice. If you go and use something like Active Record or type ORM, which is also a very famous hour and four note or any other or RAM in general, then you're going to see that there are things that are exactly similar. But with other syntax. We learned how to do migrations, how to configure models and configure the app in general, express we have learned, we have also learned the basics of JSON Web Tokens and how to use them. And in general, best practices. So we can still improve our code even more. But this is only an introductory course. And that's why we're going to end the courts here. I hope you have learned a lot here. I hope you like this course. See you in my next course. Bye bye.