Node.js Full Course for Beginners | Complete All-in-One Tutorial | 7 Hours

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome to seven hours of node.js tutorials and instruction this video is made up of 15 tutorials for learning node.js that build upon each other much like the chapters of a book you will build projects and learn the fundamentals of node.js the express js framework and mongodb before beginning i recommend that you already know the basics of javascript this tutorial is for node.js beginners but not absolute beginners in javascript throughout the lessons in this video i will mention links being available in the description below i've compiled all of these links into one github resource that you will find in the description hi i'm dave gray and i'm the creator of these node.js tutorials you can subscribe to my youtube channel for more tutorials like this one you can also follow me on twitter and if you're feeling generous you can even buy me a cup of coffee let's get started learning node.js with chapter one here we can see node.js is a javascript runtime it's not a new language it's not a different language it's a javascript runtime and it's built on chrome's v8 javascript engine it's not a framework or a library either but it does run on the server and that's what makes it different we're used to javascript running in the browser where the html and css is and that's all on the front end but no js is on the back end so you'll want to go to nodejs.org if you haven't already download note downloaded node.js and you'll want to download the recommended for most users version is fine or if you want to get the one with the latest features either way download node.js and you probably already have it or familiar with it but if you're not i just want to mention i will be using visual studio code and you can download that code editor you can also use others that you're familiar with however my examples will be with visual studio code and you can get that for free at code.visualstudio.com okay with nodejs and visual studio code both downloaded and installed let's get started okay i've got visual studio code open and you can see i have created a new folder just for this tutorial called zero one tut you can create a folder and name it whatever you want to but open that folder up in visual studio code and then go ahead and create a new file named server.js now with that said i want to mention you should already know some html css and javascript before this tutorial series possibly maybe some experience with other libraries and frameworks like react or vue but that's not necessary but you will need the basics of html css and javascript so while it is a nodejs beginners tutorial series it's not an absolute beginners for web devs if you haven't already learned html css and javascript you should probably start there before attempting this series now with that said we need to focus on how no js differs from vanilla js just plain old javascript first of all and what will be the running theme throughout the differences is that node runs on a server not in the browser and that is a big difference so you're working on the back end not the front end we're not relating to the browser anymore and because of that the console is now in the terminal window it's not in the console window of devtools in the browser because we're not using the browser at all let's open a terminal window by going to the terminal menu and choosing new terminal in vs code and with the new terminal window open we will be able to run node right inside the terminal so if i type node we're now running the console directly in the terminal so if we can add in any actual javascript that would be an expression such as two plus two and we get four in return so this is just like the dev tools console except we're now using the terminal for node and with that said we can also exit by pressing ctrl c and then it will tell us to press ctrl c one more time and now we've exited node but what if we put a console statement in our file so if i just put in condyle console there we go console.log and i put in your standard hello world and save we can also run any javascript file from the terminal with node we'll just type node and then the name of the file we don't need to put the js extension after i'll press enter and now we get hello world in the terminal another difference between node and vanilla javascript is that there is a global object instead of a window object the window object once again referred to the browser where we could do window dot inner height and different properties like that the global object is much smaller but it does have some of the same properties we were used to seeing in the window object so what i'm going to do is just say console.log and i'll put global in here because global is the keyword for the global object and i'll save and now we can run our file once again by typing node server in the terminal and it logged the full global object i'll expand the terminal window up and scroll just so we can see this object here so we have our hello world again then here is the global object and you can see there's a clear interval clear timeout set interval set timeout those are things that we already had in vanilla javascript that we're used to and it's a much smaller object than the window object if you were to go into a browser and to log that but that is another difference in node.js a fourth difference in node.js is that there are common core modules that we will explore and vanilla javascript doesn't really have those these are modules that relate to the operating system the file system and other things that we can do on the server and to import those common core modules as well as any other modules we use common js modules common js imports instead of es6 imports and now there is some work being done to use the same syntax that we typically use in vanilla javascript that is such as import whatever name from whatever file and that is how we do it in es6 however common js uses a require statement so let's go ahead and import something and we can learn how to do that with let's call this os and set this equal to require dot os and that's pretty much all there is to it it's just a different syntax than we're used to seeing with the import and now that we've imported the os let's go ahead and get some information about the os from it so we can say os dot type and we'll go ahead and log that and i'm going to copy this down a couple of times and change type to a couple of other values we can get about the os such as version and home directory and that is abbreviated with home dir you can see that i'll comment out the global object log because it takes up a little more space let's go ahead and save this and once again call node server in the terminal and here we get our hello world and then you can see os type delivers windows nt os version is windows 10 pro and then os home directory shows my home directory in users dave gray there are a couple of other values that we always have access to in node and let me type the first one out it's der name for directory name and it starts with two underscores and that will always give us the directory name in node and then the other one is two underscores and file name for the file name we're using here i can see i'm being inconsistent on the semicolon so if anything i'll just remove the one i typed let's go ahead and save that and once again call node server in the terminal and here's what we get after the home directory that was delivered from the os common core module in our console log statement right here you can see directory name the value that we have we don't even have to import a module to get that is this full length here to my 01 directory and then you can see file name gives that same full path but also includes the file name at the end there's another common core module that we can import and i'll do that right now and we'll call it path because it is called path as well so there is path with the common js import and now we can use file name within path so let me give some examples of that to get more values here we'll log the path directory name and pass in the file name and we'll see that it is very similar to what we just got by using the directory name here however if we're using path that might come in handy as well there's also path dot base name and we'll also pass in the file name there and i'll copy this down one more time and there we'll just change base name and this will be extension name and we'll go ahead and save that now let's run the file one more time with node in the terminal and see what we got in return so after our directory name and file name here if i drag this up just a little we can see it all so we have the directory that's the value before we use the path import and here is the server file name before we use the path now the final three that we used with the path import we got the same as we did above for the directory so using the path directory name is the same as using this value in this instance and then the base name was just server js so that allowed us to just pull the file name out instead of having everything included as the file name value does up here on line 22 and then the extension name gave us just the extension of the file the dot js what i've found to be even more useful than any one of those individual values is to oh i had my fingers on the wrong keys console.log path dot parse and then pass in the file name and we'll see what we get in return once we call this one more time in the terminal node server and here we get an object with all of these values so we have the root the directory the base the extension and the file name itself so we can really pull all of that together in any way we want to if we just go ahead and parse and then get each individual value as well now besides the common core modules we can also pull in packages that other developers have created and some of you may be familiar with node package manager already and i will cover that in some detail in the near future but we can also create our own modules and so we have a couple of imports here we'll make room to import one more but first in the file tree let's create another file and i'll just call this math.js inside of mathjs i'm going to create some functions i'll call the first one add and set it equal to a anonymous function it's an arrow function really and from there it'll just be a plus b which would return the sum of the two parameters a and b now i'm going to copy this down three times and we can just change these so here we'll have subtract they'll all have the two parameters a and b we can also have multiply and we can have divide so instead of a plus b of course it would be a minus b a times b and a divided by b right now though while we have these four functions we have not exported them in any way so we can have a statement at the bottom that says module dot exports and then we can set that equal to an object and we can pass in the names of all the functions there is another way to do this that i'll show you right afterwards but first let's attempt this way which is a common way to see this so we're exporting all of the functions that we defined to import these back in the server we need to come over here and let's just define math and we'll set this equal to require and now since it's not a common core module we can't just say math we have to say dot slash and now math is available to us there but we don't need the js extension so we can save that and then let's go ahead and comment out all of these console logs and we'll add the console log for the math underneath here so console.log and then we could say math.ad and we could pass in two variables two and three and let's go ahead and call that below with our node server and we got hello world of course it's still in there and then we got the total five so there is math being called however we don't need to call it as an object where we use dot notation we could destructure right here so instead of math we could destructure and just say add and remove the math dot and save and this should work in the same way so if we go ahead and call the server again and we got five once again with our hello world now we could go ahead and destructure and pull in the rest of the functions as well subtract multiply and divide we have all those functions available to us now so if we go ahead and copy down and we'll change each one to subtract multiply and divide we can save go ahead and call the file once again and here are the values looks like i'll need to move this just a little bit to see all the values but we've got five and then two minus three is minus one two times three is six and two divided by 3 is essentially 2 3.66 and on now before we're finished with the custom module let's go back to math and i'll show you one other way this could be done instead of combining all of these at the end there we go if i'll comment out this export here instead of the const here with each definition i'll just select all of those we could change this to exports dot and then it's essentially adding each of these functions to the export so exports.add is equal to this anonymous function and exports.subtract is equal to this anonymous function and so on but this will work in the same way so once again if we go ahead and call the server file from node we've still exported all of those functions and we actually deconstructed them over here to pull them in so you can also export in that way instead of using module exports at the bottom okay with that said we have covered quite a bit but there's one more difference to point out that we will see down the road and i'll just put it here under number five and that is nodejs is missing some of the apis that are available to vanilla javascript and one notable one is fetch but of course we can always pull in packages into node and there is a large amount of packages available through npm4 node so we won't miss it that much in the next tutorial we'll be working with files as far as reading writing creating updating deleting all of the things that we can do with files and we'll be using the file system common core module for that today we're going to look at the file system common core module for node.js it allows us to create read update and delete files and work with directories on the server and that's because node.js is a javascript runtime that actually runs on the server instead of in the browser now i'm going to click docs at nodejs.org because nodejs.org is the source of truth for information about node much like mdn would be the source of truth for information about vanilla javascript as well as html and css currently the stable version that i have installed is 14.17.5 as you view this tutorial the versions that are stable may change so go ahead and click on whichever version you have and now you can see we have node.js documentation today we're looking at the file system module so i can click that right here and there are many things you can do with the file system with directories and different files so amongst all of those things what i usually do is press control f i'm on windows and then i type what i'm looking for and we're going to start out by reading files so when i type read file i can see the fs dot read file and it shows the structure here for what i want to call and then you can click it and get details about that i just wanted to show you how to find the different documentation on node.js and now let's get started in visual studio code as we work with the fs the file system common core module i've got visual studio code open with an empty index.js file i've also got a files directory here in the file tree and you can see a couple of starter text files a lorem text file that has a lot of text in it and a starter text file that just says hi my name is dave we're going to start by importing the fs common core module here and we use common js imports for that and so it's just require fs after that let's go ahead and read that starter file so we need to specify the file and it's in files and then it's at starter dot text from there we have a callback function that has error and data that we read and so we'll say if air we need to throw the error and otherwise let's log the data to the console now if you remember the console in node.js is in the terminal so i'm going to press control and backtick to open a terminal window you could also do that from the terminal menu now here to run our little node file in index we just type node and then index we don't need the js and let's go ahead and take a look at this data from starter and notice after we read the data it's presented as buffer data so that's what we get right here if we want to be able to read the data we can put a to string method afterwards i'll save and i'll go ahead and call this again and now we can see hi my name is dave in the console but instead of two string we can also put in a parameter here that says the encoding or defines the encoding so we'll say utf-8 before the callback as a perimeter and now let's go ahead and run it again node index in the terminal and once again we get hi my name is dave now notice the throw error here according to the node documentation if we get an uncaught exception we need to go ahead and catch that and i'm just going to paste this in if we have an uncaught error we should exit so we listen for this uncaught exception using process now process is one of those values that node has available to us we don't need to import it it's already there so we're listing for an uncaught exception then we pass in the error to the callback here and we're just logging the console error there was an uncaught error and then we put the error there and then we exit the application and this is direct from the node documentation so let's go ahead and throw an error on purpose i'll just look for a file to read that doesn't exist named hello and once again we'll call node index and you can see we get an uncaught error and here it is there is no such file or directory now let's change this back to starter so we can keep reading the data that exists and i'm going to put a console log statement underneath and this is to demonstrate that read file and node in general the functions or methods you'll find from node will be asynchronous and so we're logging the data here but we're also logging hello here and node has the ability to say i'm going to process this but let's go ahead and tackle the rest of the tasks in the program and when i finish reading the file i'll get that data to you if you're familiar with async a weight this should be a familiar concept but let's go ahead and save this and let's see which we get in the console first hello or the data and we get hello and then we get hi my name is dave so node said it would read the file but it went ahead and processed this console log statement and it actually was logged to the console first and then when node completed reading the file it logged the data to the console instead of hard coding the path like we see here in read file there is a better way and let's pull in the path module to do that so we have path and then we use require and we're requiring path and the reason is the slashes sometimes if you're familiar with different operating systems sometimes backwards sometimes forward there can be some problems not always but there can be when you hard code file paths like that but if we use the path module we can eliminate this problem so let's use path dot join i typed json there we go join and then we need to specify first the directory name and that's two underscores first and remember that's a value that's always available to us in node after the directory name we'll say the files directory to attach on to concatenate to that directory name and then we need to say the actual name of the file itself so now we've got starter text so if we supply this instead of hard coding a file name it's a much better approach let's go ahead and save and run this one more time and everything still works as it did now that we know how to read files and catch an error let's go ahead and copy the read file and underneath this console log statement i'll paste this in and we will write a file but it's just a little different i can change just a little bit of the copy and paste so instead of read file we've got write file and this path here will change the file name because we're going to write a new file this will be reply dot text now we don't have to specify the utf-8 that is by default now we will have a callback and the callback will only have an error we're not reading data we're writing it so if we have an error we'll throw the error in here instead of data we can just say operation complete or more specifically let's say write complete and we can save this and now let's go ahead and run this code and we got an error oh and that's because i forgot to specify exactly what we're writing to the file i'll just say nice to meet you [Music] and then we have our callback had things out of order so again path name content we're going to put in the file and then the callback with that saved let's run it and there we go we've got hello hi my name is dave and then the right is complete let's look at the reply file we created and it says nice to meet you i'm going to copy all of this right file operation down one and then we can change it to append file which is updating a file adding more content to it we'll go ahead and create a different file here and that is to show you that a pin file will go ahead and create a file as well if it doesn't exist so let's just call this test and we'll say testing text or something like that here and other than that it is basically the same syntax as right we'll save this and go ahead and run the code again and we got write complete and append complete and then notice due to the asynchronous fashion of node.js the read completed last this time and we have hi my name is dave after the other operation is completed in the file tree we now have our test file as well it has the testing text in it so append file worth noting that it will modify an existing file and can append content to it but will also it will create a file if it doesn't exist so due to the asynchronous nature of nodejs and these different methods we're calling here from read file write file and append file if we wanted to modify the file that we created such as reply it would be better to put a pen file i'm going to cut this and put it inside of the callback of the write file operation that way it would definitely create the file and then we would be ready to append to it instead of wondering if we would possibly create the file first with append and then write over it with write file so here let's change this to reply.text and it says nice to meet you let's give a couple of line breaks and then say yes it is and if we save that we'll go ahead and delete the test that we're no longer using and our reply because we will create it once again so we've got reply and then we will modify reply with append and it's inside of the callback of write file call node index in the terminal hello write complete then we got the read operation completed and then the append completed so if we look at reply now it says nice to meet you and yes it is in the order we expected now as you might imagine if we wanted to do something to this file after we added more content and we wanted to make sure it happened in the order it needed to such as renaming the file then that would need to be in the callback of the append file i'm going to go ahead and copy a pen file and then inside of the callback i'm going to paste it and change this append here to rename so we can rename the file and we're grabbing the reply file and then we're going to replace this parameter with what we're going to name it and we'll just call this new reply and then of course it has a callback with an error as well and then we can put rename complete now let's go ahead and call all of this in the terminal with node index and it does happen in the order we expect we got write append and rename and you can see this time the read operation completed before the others once again asynchronous so we don't know which will happen before the next but in this way we're controlling it because we're putting the append inside the callback of the right and we're putting the rename inside the callback of the append let's go ahead and look at our new reply and it does have the content we expected now if you've worked with javascript for a while at this point you would be saying yes this is nice dave but this is starting to look like what is called callback hell and yes it is because we're putting one inside the next inside the next and they're all inside the callbacks of the other so we are controlling the flow but at the same time we're able to avoid this in vanilla javascript using async await and now we can look at how to avoid it in node by doing the same i'm going to comment all of this code out and up here we can get rid of the console log hello as well and then at the top where we have fs we'll switch this to fs promises and let's attach dot promises to our import here so we are now importing the file system promises instead of just fs and now i'm going to create a function and i'm going to call it file ops for file operations and this will be an async function and then inside this function we can use try catch so here we'll have our catch for any errors and now inside here i'll just say console.error and pass in the air or we could throw the air but that's actually what's happening here and we're catching them so it will not be an uncaught error and then inside the try block i'm going to define data and set that equal to fs or sorry before that a weight fs promises dot read file and now we need to specify our file path and that's what we have here part of why i saved that so i could just copy it up and i'm going to hide the file tree momentarily so we can see a little more after that we can still specify utf-8 and then we don't need the callback here that has the error and the data because we're using a weight and we're catching the error down here so this should be just fine now now once we have the data let's go ahead and log the data once again and i didn't remember my semicolon after that being a little inconsistent okay so we have file ops i'll delete the read file operation and now here we're just going to call file ops into action we'll have node index in the terminal oh and i didn't save the file yet there i'll save the file hopefully we don't have unexpected results now and node index in the terminal and we got hi my name is dave the data that we expected to get let's add another await in this process of file operations we'll say await fs promises and now we will write a file and this file is going to be promise right so we'll have the same type of path once again which i can just copy and paste but we'll just call this promisewrite and after that we want to pass in the data that we just read and now i'm going to copy down once again and after we write a file let's go ahead and append to the file and now in the append area we'll just say nice to meet you oh let's put a couple of line breaks here with backslash lowercase in so two line breaks and one more copy down and now let's rename [Music] and we're renaming promise right so we'll just copy this once again and instead of content now we need to put the new name of the file and this will be promise complete and we can save that so you can see we're taking the data from the starter then we're writing a new file called promise write then we're appending to the file and then we are renaming the file and finally let's go ahead and copy these two lines once again and put them right here and now we'll call this new data and here we want to read the new file which is promise complete and then we'll go ahead and log that data as well so you can see there's several different operations happening here we are reading data from a file then we're writing it to a new file then we're appending to that new file then we're renaming that new file then we're reading the new file and logging the data from that file so i hope that's not confusing i just wanted to show all the operations that we have gone over and then use them in an async await fashion so here is node index and here was the original content hi my name is dave but then the new file has hi my name is dave and nice to meet you and let's go ahead and look at the file tree there it is and we've got promise complete right here that has hi my name is dave nice to meet you let's go back to the index and let's add one more thing right here i'm just going to copy this one line and above it i'll paste in again and here instead of write file i'm going to say unlink and after that we don't even need to pass in data because unlink is actually a delete so we can delete this original file that is called starter text there it is and now that we have it being deleted and i can get rid of the space here as well so we're reading the file logging the data to the console and then deleting that file then creating the new file and we can even get rid of promise complete here again and we'll get rid of new reply we're not using that anymore let's make sure we save the index and we'll call it into action once again we got the same in the console and we have promise complete over here but no more starter text it's gone because we deleted it with the unlink right here and this is also available without fs promises as the first examples i showed that were just fs and then read file write file and so on unlink is what you would use to delete a file okay now i'm going to create a new file over here and i'm just going to call this stream.js now if we have larger files sometimes it is good to not grab all of the data at once it could be too much just like moving a large pile of sand bucket by bucket or moving all the water in a swimming pool bucket by bucket rather than attempting to grab everything all at once so this could be more efficient and a little bit easier on the application if we do this so let's say cons fs and once again let's require fs not fs promises just fs and here i'm going to define rs and we're going to set this equal to fs dot create read stream from here i'm going to specify our files slash lorem.txt once again you could use the path module would probably be a better option i'm just doing this quickly so i'm hard coding that in and now putting in the encoding and this is utf 8 once again so we've created a readable stream and we've specified the encoding in the options now let's go ahead and specify a writable stream and this is going to be ws.com write stream [Music] and now what do we want to write this to would be the question so let's call this from stream ah let's call it new dash lorem because it is our lorem text still that works so we have new lorem and really we don't need to specify anything else here we already specified what was being read is utf-8 so we're good there and i did make a mistake here i needed to make this fs not ws because this is getting this from the fs module the create write stream and that's why it didn't help me out when i was typing it okay so once we have that we need to listen for the data coming in from the stream so here is our readable stream and we can say on now we're listening for the data that's coming in and here let's say this is a chunk of data or a data chunk if you will and inside of here we could console log the chunk or we could just write to our writable stream and pass in that data chunk so let's do that and i will save and now let's go ahead and run this so we'll type node stream and notice now we have new lorem as well and this will be a large file of lorem probably about a thousand lines yes so it did it very rapidly but once again a example of a large file just a test example we could have much larger files but in that case when you're working with a large file this is much more efficient now speaking of efficiency i'll go ahead and comment this out there is even a better way to do this instead of the listener just take the readable stream and use pipe and then you can pass to the writable stream this will accomplish the same thing and piping is more efficient than this structure with the listener here i'm going to save this i'm going to delete the new lorem file and now let's go ahead and run our stream once again by typing node stream in the terminal and you can see we once again got our new lorem text file and it has all 1000 lines of lorem ipsum text okay i'm going to create one more new file in the file tree and call this dur.js which is short for directory once again let's go ahead and define fs at the top and require it and after we do that what i want to do is create a directory with fs.mkdir which stands for make directory and we'll have let's just call it new we're specifying what we want to call it right here and then there's a callback that has an error and this is the same as we've seen previously so if error we could throw error now i won't go ahead and copy and paste the uncaught error handling code in here that i showed you earlier just to save time but you could use it in the same way so if we have an error throw an error and if not we've created the new directory so we'll just log directory created and we can save this let's go ahead and run our code so here we'll type node dur which is our new file dur and directory is created and now we can see here is our new directory now earlier in the tutorial we threw an error on purpose because we attempted to read a file that did not exist well we can check to see if files and directories exist or not so we don't get those errors and we also might want to check in this regard to say if the folder if the directory already exists let's not create it because we don't want to write over what we already have so we can use the exists sync method and let's start out with if and then we'll say if it does not and not would be the exclamation mark fs dot exists is it exist yet two s's exists sync and then we'll say the same folder slash or the same directory dot slash new so if it does not exist then go ahead and do what's inside of the if statement and we'll put that right there let's go ahead and close that out and close this out and save and now let's see if we create the directory when we run it in the terminal and no no directory was created because it exists so this says if it does not exist create it so let's go ahead and delete the directory and now let's run this once again and now it created the directory again because it did not exist you might find checking for file existence fairly useful before you attempt to delete a file if it exists or not or before you attempt to even rename a file or copy a file several things that you want to make sure the file exists likewise you can check directories in this regard now let's go ahead and write some code that deletes the new directory okay let's copy this down highlight everything and bring it down here to line 10 and now let's check to say if it does exist and this is the folder we're going to remove the directory and that is rmdir for remove directory so this would be a zero sum game here if it does not exist create it and if it does exist remove it so now let's say directory removed and we'll be able to tell by the console but in the file tree we should not have a directory when these operations are complete and the directory was removed it already existed so it wasn't created but it was removed let's go ahead and run it again and now it was created and removed and so it's still not in our file tree but we can see both operations completed today we're learning about node package manager which is also commonly known as npm and when you install nodejs from nodejs.org which i have open right here you also install npm however npm also has its own site and documentation at npmjs.com so let's take a look at that and you can see the npmjs.com site here one little quirk i really like about npmjs.com is they give wrong answers for what npm stands for in the top left so every time you come back to the site you'll see something different here right now it says new prog mixtape it really stands for node package manager and npm provides thousands of packages for us to use in our applications the difference between a node common core module and an npm package is that npm packages are node modules that are created by third parties in other words other developers so let's search for something here like axios which is a node package and we see the results axios is at the top with an exact match and you can see they're also ranked by popularity quality and maintenance and you see the little chart over here to the right so essentially other developers create reusable modules and share them through npm so instead of recreating the wheel we can search for a module that already exists and then we can import that module into our applications now today i'm going to go over what i consider to be essential npm knowledge and we're also going to install some packages that we'll need in the near future when we create an event logger i'm going to start by showing you where the documentation is at npmjs.com click on documentation at the top then it takes us to docs.npmjs.com now when we're there what we're really working with is the cli and that's what developers typically use when they're integrating npm into their projects and their cli commands configuring npm and using npm there's quite a few commands i'll just go over what i consider to be essential what i use the most and what you really need to get started but i always want you to know where to find that documentation and reading the docs is definitely a big part of being a developer okay let's move over to visual studio code i've got visual studio code open and i have a new folder for the tutorial and then an index.js file that is completely empty right now we're going to start off by just putting a console log statement and saying testing inside of our index.js and we can save that file now i want to open a terminal so we can go to the terminal menu or since i'm in windows i'm just going to press control and the back tick and it will open up a terminal now in the terminal we can install a node package globally that we can just call from the command line without adding it to a specific project so i'd like to do that first i'll type npm and then the word install works but you can also use the alias i or there's also an alias ad i typically use just i from there i want to install node mon and this is a great development package but it's also good to install globally because you might just want to call it from the command line and with nodemon we want to put dash g now what nodemon does is it monitors your files and as you save it automatically restarts the server so we're not always typing node and the file name in the terminal it just kind of does it for us so i'm going to go ahead and press enter to install this package globally and then when it finishes we'll see how it works with our index.js okay and the package installed we're ready to try out nodemon so let's type nodemon instead of node and it's going to look for the index.js by default so i don't really need to type that name but if i had a different file name like server i would type server or something like that right now i'm just going to type nodemon and it will know to look for the index.js and it says it is watching the extensions js mjs and json and it started our index.js and here we can see the message testing so it did go ahead and log to the console testing now i'm going to change the file add an exclamation mark and save and then you can see it was restarting due to changes and then it went ahead and ran the file and we got testing in the console so that's how nodemon works now to exit nodemon you can press ctrl c just like we would exit a node application that we were running if we tested it by typing node index now that you know how to install a package globally let's go ahead and add a package to our project but before we do that we have to initialize npm for our project i'll type npm and then just like when we initialize git if you're familiar with working with git we type init now it will ask some questions at the beginning if i want to skip those questions i'll just put in the flag hyphen yes to answer yes to all the defaults but i'll go ahead and not do that just to show you the questions it will ask and then i'll just press enter on each one to go ahead and accept the defaults but first it's going to initialize npm okay it's asking me the package name and the default would be zero three tut what i named the folder and then the version by default is 1.0.0 description you don't have to enter one entry point by default is index.js but we could change that to server.js or something else if we wanted to test command nothing to enter there we don't have a git repository yet no keywords you could put your name for author if you want to and there's the license by default and then it says is all of this okay and the default is yes so i'll just press enter one more time now if we look over in the file tree we see a package json file and this pretty much has all the information that we answered those questions to then the package json file is important because this is what npm reads to know what packages to install for your project and that is because this file will stay with your repository if we send it to github but we won't send the packages itself and that way we don't have to transfer as much data or store as much data and then when somebody else clones or installs this application it can just read the package json or likewise if we were to host it and build the application at a host and run a build command then it would install those packages there without having to transfer them over from github so now that we have this let's go ahead and add a package to our program and i'm going to say npmi and then i'll type date dash fns which stands for date functions and press enter and it will install this package as a dependency which we will see in our package json file okay that completed installing and we now see dependencies listed in our package json file and these are production dependencies we see listed here so when the project would build with a build command it would include this package because we would know it would be part of the overall application that needed to go into production but we can also have dev dependencies before we get to the dev dependencies though let's go ahead and look at the file tree because now we have a package dash lock dot json and we don't want to change anything in there that's just handled by npm but you will see it show up in its file tree we just work with package.json we also see a node modules folder and this can get fairly large fairly fast because there will be a lot of files and folders in here and that's because any dependency that we add can also pull in other dependencies and if this package needs all of these dependencies this gets very large and that's why we don't want to store that in github so what we should do is always add a dot git ignore file oh and i didn't press dot i got a slash there we go dot get ignore and in this get ignore file the first thing you should add should be node underscore modules now i'll go ahead and press save and now if we were to initialize git and save this to github the node modules folder would not be included and that's important because there is a lot of data in node modules now i'm not going to delete the node modules folder right now but if you were to clone another repository and it had the package json but did not have the node modules you would get an error if you tried to run or tried to start the project so what you want to do is type npm install and if you just type npm install and press enter it's going to read the package json file and go ahead and install the node modules you need and that's important of course when you're pulling down another repo say from github maybe you cloned it and then you want to install the node modules that are used in that application okay with the date fns dependency let's go ahead and use it now in our index js i'll get rid of this console log statement that we have here and at the top we want to go ahead and import and we're going to destructure because we'll just import format and this is using common js again so we use require and then we'll say date dash fns and now that we have that imported we can use it in the statement so i'll just put another console log here and i'm going to paste in the format but then we can go over it so we're calling the format function from date fns and it accepts a new date and after it accepts a new date we have to tell it how we want it to format it and of course you have to read the docs to know how to format it and i am pulling in the year the month and and i didn't mean to do that let's undo that the month and the days and then i'm putting a tab in and then i'm putting in the hours minutes and seconds and so this will be tab delimited so we'll have two columns we'll have the date and the time and we could use this in a log format and that will be the end goal eventually as we learn about events but right now let's just format this date and go ahead and send it to the console now remember we're not running nodemon again yet so let's go ahead and add nodemon as a dev package to our project okay back in package json we're going to add a dev dependency now easily i could run nodemon right here from the terminal as a global dependency because we'd already installed it but i just want to use this as an example of installing a dev dependency so here we type npmi once again i'll type nodemon but then i want to give the flag you could do dash dash save dash dev but there is just a shorthand for that and it's dash with a capital d and this will save nodemon as a dev dependency so i'll go ahead and press enter and let that install all right now with nodemon installed as a dev dependency you can now see that in the package json as well and it lists a dev dependency so let's talk about scripts and how to run our application using scripts because that's what a server would use if we were to host this somewhere and you often see a start script a dev script and a build script if you're familiar with react or something similar you have definitely seen some of those before so let's go ahead and add a start script and now in the start script we need to just go ahead and call node not nodemon but node and we can say index right here because that is what we want to run our project with but then let's go ahead and we don't need a test script so let's change this to dev and i'll go ahead and replace the test script now with nodemon and we'll go ahead and we can specify index here as well but remember it defaults to index js anyway so let's go ahead and save that now if we're to start the project start is one of the few words that works without the word run so we could just type npm start and start our project but we don't need to do that yet we want to use dev so let's say npm run dev and press enter and you can see nodemon started and we've got the date over here with the format i gave it which is year month and day and then there's a tab spacing and then we have the time and you can see we're using military time which would be 0 through 23 hours and then minutes and seconds now back in the index if we were to make any other changes nodemon will continue to watch this and go ahead and restart the server so then if i just put another console log and said hello save the file nodemon restarts and we should get the new information in the console as well and that's what we get with the hello now i want to go ahead and stop this again because we want to add another dependency to our project while you don't have to look at the package json while you install dependencies i'm going to go ahead and do that so we can see the new dependency added and here i'm going to type npm i for install once again and this is a production dependency so we don't need to put a flag after it it'll go directly to the dependencies and we're going to install uuid which allows us to generate ids that of course are different for each entry so i'll go ahead and press enter and now we can see uuid installed here as a dependency in our package json also so let's go back to index and use this package as well so we need to import it at the top and here we'll say const and now this is a little different now with es6 imports we would say import uuid as and give the name that we want to give it now here we need to import a version which is a specific version it's v4 but we want to import that as uuid and then we can say equals require and then specify uuid here now you may see this done in different ways as well so instead of the v4 this way some could just use it as v4 or you might see an import and just here have uuid and let me get rid of that curly brace there and then in the code they could possibly use it as uuid dot v4 and call it that way as well what we're going to do is use it as uuid so back here we want to make sure it is v4 so i'm going to say import v4 as uuid and now we can use this and this will log a different id or generate a different id to the console and then of course our console log statement is what will log that so let's go ahead and save this and now once again in the terminal i'm going to type npm run dev to start nodemon nodemon started up and you can see we've got the format of the date with the date and time and then on the next line the second console statement we got the result of calling uuid and if we just make any change basically to the console it's going to generate another uuid that's different than the one we got before of course so you can see how it generates a different id each time and that can be very useful including with something we would log such as an event whether it's an error or a request or anything like that that we might write to a log file we might want to give each entry its own id i want to jump back to chrome really quickly just to draw your attention to how we can search for these packages because you might be wondering how do i know about these packages well you could search for id and see what would come up and remember they're also ranked by popularity and we've got nano id short id but we don't see uuid but somewhere i learned about it along the way and if you do search for uuid it will show up here it is the exact match popularity is huge quality is good and so then when you go to the page you can read about the details for the package you want to use so here's some good information about it it tells you how to install it and of course it quickly tells you how to install it here shows you where the github repository is weekly downloads that's a very popular package right there so this is a good example of course there's some docs as well and you can look that up and of course you can search again at the top i'll look for date dash fns many times a package will have its own website as well that has documentation and date fns is definitely one of those that do of course notice it changed nomadic people migration at the top for npm i always like the different uh definitions it gives npm again node package manager this says it's like lowdash for dates lowdash is another package you could use but this datefns has its own github repository it also has its own web page that i believe is linked here somewhere if i scroll down maybe we'll see that oh here it is see datefns.org for the docs so there's all kinds of information about each package as you explore that i just wanted to highlight that again as we work with these and now let's take another look at the package json because there is a little more detail we need to look at look at the packages we have installed here under dependencies or also under dev dependencies and you can see we get the semantic versioning numbers now let's talk about these because this first number means a major version the second number means a minor version and the third number means a patch now the carrot we see in front means go ahead and allow an update to the minor version and the patch if needed but do not update a major version a major version could have breaking changes to your application so you don't necessarily want to allow those you can now if you don't put anything in front of the number this is saying specifically this version and only this version for this project will work so once again if you put the carrot that is saying go ahead and update minor versions or patches but not a major version so now if we have what's called a tilde the little squiggly kind of let me put it there this is saying go ahead and update a patch version but do not update a minor version so if you see the tilde that will allow patches only and not minor versions or major versions now if we got rid of this all together let me go ahead and put the carrot back because i'm going to want to replace that and you just saw an asterisk in here this would mean go ahead and update everything all the time use the absolute latest version every time that is not too safe although you might see it this is what you'll typically see and what is installed by default to your package json is to have the carrot here and it's worth noting that when you install if you specifically want to install a different version or any kind of version you can just have npm install and then say we would type uuid and then put the at symbol and after that say the specific version you want if you wanted 8.3.1 then this would install that specific version however if you just say uuid you're going to probably get the latest version when you install here but then it's going to mark it to not update any major changes because those could once again cause a break in your application so that could be what would be considered a breaking change i'm going to go ahead and save the package json now and if there were updates or if you wanted to check for updates to say okay is uuid does it have a new miner version or something like that if we had it like this remember it would not install the major version but if there was a minor version or a patch you could just type npm update and npm will check for any updates for your packages and you can see i had no updates or it would say something about that as well so there were no updates there so the only thing that i typically use or would might need to use that i haven't shown you on a regular basis would be uninstall so here we can type npm and then you could use the full uninstall or you can just use on or you can use rm for remove so let's just go ahead and use rm and then we're going to uninstall nodemon but nodemon is a dev dependency so you always need to add that specific flag if it's a dev dependency or if we wanted to install the global version i would put the dash g as well now if it was production you wouldn't have a flag at all so let's go ahead and uninstall the dev dependency node mod this is worth noting we did uninstall it so there is no longer a dev dependency listed it went ahead and kept the dev dependencies in here but it's just an empty object right now however we still have nodemon listed in our script it's not going to automatically change a script for you so that could be an issue if you want to install something that you have in a script you need to remember to go and check for that as well the nodemon is something i would probably have installed as a dev dependency so we could just re-add that but again worth noting if you uninstall a package it doesn't remove it from your scripts so you need to check that as well today we'll be learning about the events common core module in node.js and more specifically how to both emit custom events and how to respond to those events when they are admitted right now we're picking up where we left off in the last tutorial about npm modules and if you didn't see that tutorial you can just catch up by installing the dependencies you see right here so for production dependencies we have the date fns module and the uuid module you could also refer to those as packages also as a dev dependency we have nodemon installed and then in the scripts of course the start script is node index but what we would use in development is the dev script and that is nodemon index so if we type npm run dev it will launch nodemill and nodemon will listen for the changes in our files and restart the server without us constantly having to type that so again if you didn't see the previous tutorial just update your package json and npm installs to this and if you don't know how to do that please do watch the previous tutorial okay let's move over to the index js and you can see we're already importing format from the date fns module and then we're also importing uuid and it's actually v4 there's different versions in the uid so we're importing v4 as this is an alias as uuid so we can call that right here and you can test these out with these console log statements that we had from the previous tutorial but what i want to do right now is rename this index file so i'm going to right click and choose rename and i'm going to name this log events in camelcase.js so this is a complete different file and i'm going to make this into a module that we import into an index.js that we haven't created yet so we need both of these imports but we're going to make a logging function of course logging events is something that's very useful on a server let's go ahead and also import the fs module so we'll require fs and then we're going to want to use promises so let's say fs promises set this equal to require fs and then dot promises and we also need the path module so here is require path and now that we have all of the imports we need and notice these are the only two that we really needed to use npm for because these are all common core modules here that we imported now that we have that i'll get a couple of extra lines let's go ahead and define our log events function that we can export and it's going to be an async function and it will receive a message parameter now inside the function we need to define we'll call it date time and let's set this equal to and let's just grab this format that we have right here and copy this because that's what we essentially need i'll use a template literal and inside here i'm going to paste the format the new date it's got the tab and then it will just in the template literal and leave it at that and then we're going to take another definition here and call it log item and we'll really use the date time so i'll put another template literal and we could have done this all in one line but this gets kind of long if we do that so i wanted to break it up and so we've got the date time then i'm going to put another tab and remember there's a tab in here too so what we're doing is creating a tab delimited log file and now i'm going to use uuid and call that to get a unique id for each log event and then one more tab and we'll just put in the message there we go and now that we have our log item let's go ahead and log that to the console so we can see it while we're in development mode here as well and now we need a try catch block let's get to the async await portion of this function and we'll catch an error if an error happens and let's just log the error to the console if we have an error writing to the log we won't be able to write the error to the log so this is the best thing we could probably do right there but in the try block we can await fs promises and then let's go ahead and append file if you remember from our tutorial on working with files a pin file will also create a file if it doesn't exist and now we need to use path and we'll use path join and two underscores and then we'll use the directory name value and then let's put it in a logs folder and after that let's call this event log dot text and then we still need to pass in the content that we're going to put in the log right after that parentheses we need the comma and that would be our log item that we defined okay now we can save this much now i am thinking of something that could cause an error in the future and we'll get rid of these console log statements down here but i want to leave it like this for now so we can actually test out getting the error as well or catching the air so let's do module.exports and set this equal to log events now we're exporting our log events function and we'll be able to use it in the index that we're going to create so over in the file tree we'll create a new file called index js from here let's go ahead and define log events and set it equal to require and now dot slash because this is once again a custom module not a common core module or an npm module and so dot slash log events and now we're ready to work with the events common core module and what we want to do is define an event emitter and let's set this equal to events the common core module events after that we need to define a class so class my emitter and it's standard to capitalize instead of use lowercase on the first my there for a class and then we want to say extends event emitter and then we can just have the empty curly braces right here this is i know it looks strange but it's directly from the docs as well from here we can initialize the object that we're going to create so we want to create my emitter but now oops this needs to be a lowercase m to start out so don't let it change on you or or select the option that would select the previous my emitter and now that we've got my emitter defined let's set it equal to a new object that is my emitter right here so we've initialized the object i know that's a little confusing but that's what it looks like in the dock so i just stuck with that and then we've got add a listener before the log event so then we can say my emitter dot on and that is how we listen for an event and i'm just going to call this a log event we could be listening for any event we want to this is the first parameter of listening for an event so we just say which event we're listening for and then we can call this anonymous function to pass in the parameter message and now inside this anonymous function we'll call log events and once again send that message that was passed in so now that we are listening for the log event we need to go ahead and omit the event to test this out now i want to set a timeout which will hopefully let us understand how everything is processed a little bit better but we're just going to emit the event you don't have to have a timeout to do this i just wanted to put a little delay in there so once again we use my emitter dot omit now not on on is listening so emit is emitting the event now we'll emit the log event and then let's go ahead and send our message i'll just say log event emitted that looks good now let's put a delay in here with the timeout and i'll put two seconds that may be too long it may not be long enough to see the difference just depends how long it takes nodemon to restart the server so now that we've got that saved and this is our index let's go ahead and open a terminal you can do that from the terminal menu or i do control backtick i'm in windows and now i'm going to type npm run dev to launch nodemon and our index js and we get an error so let's see what we got i did expect to get one notice we did log to the console so here's what we would have written to a log file we've got the date we've got the time we've got the unique id and we've got our message log event admitted so that all worked out as expected but we have an error and let's see what it says here console error is not a function well i should have typed console log here let me go back and fix that we definitely have another error that i was expecting to see so let's drop this back down and of course nodemon should restart after i change this so instead of console error let's put console log we might have to restart nodemon let's see yep now it restarted and we can see the message that i was expecting to get so here once again we got the log file and then we got no such file or directory and that is because append file will create the file if it doesn't exist but it won't create the directory and we didn't have a logs directory yet so we need to modify our function because if you think about this when you install some software there may not be all of the directories created that you need so let's modify this try block to account for not having that logs directory to begin with if you notice we haven't used the fs module yet we had used fs promises so in the try block let's say if and then we'll say not if it not exist is what we're going for here so fs dot exists sync and then we want path path.join two underscores and directory name and then we're just looking for the directory so if this does not exist essentially is what we're saying then as you might guess we want to create that so we'll say await and now use fs promises oh and then we need dot mkdir which is make directory and we can say path.join once again two underscores in the directory name and create the logs directory please so now if the logs directory does not exist it will create the directory and then it will either create or append to the event log file so let's make this change and now if we look back we can see we got no error on this latest execution once again everything wrote to the console and now i'll bring this down and if we look over here we have a logs folder and we have an event log and there it is we wrote to the event log now let's go ahead and run the program again we'll need to make a change of some sort to do that and then we can check the event log so let's just make a quick change here by putting in a console.log or no you know what we don't need to do anything like that we could even just put in a comment say testing save and we should be able to see some changes once again if we go back to the event log oh we've got another problem after our message we didn't put a line break and so then it just wrote the next log on the same line so we need to put in a line break after that as well so let's go to our log events and where we define our log item at the end of message then let's put a line break with a slash in and now this should make a difference let's check the event log again and maybe it made a difference i'll tell you what let's try this i'll just delete this all together now the file doesn't exist i'll get rid of the testing save write the file let's look at the file there it is now back here once again i will undo put the testing back and save and let's look at the event log there it is we've got another log event emitted on a new line and everything is lining up as we expect delete testing again and save and there it wrote a third line to the log so this is working as expected so here is a abstracted log events function that you could use you could accept more than one uh parameter as well and if there was a second parameter here when we would be in the index.js when we admit this we would just need to put the next parameter right here so there can be more than one parameter as well and this is how you set up an emitter to not only listen for but to emit events now there might be all sorts of actions that you want to emit events for when we create a web server we're wanting to emit events to show what requests came in and log all of those so we have some detail of the activity for our web server and that's what we'll be building next a web server with node.js today we will be building a web server with node.js no framework will be utilized and this will help us learn more foundational knowledge about nodejs and then in future tutorials i will introduce the express js framework we're picking up right where we left off from the last tutorial about the nodejs events module so let's go over some quick changes and file additions and i will be providing a link to a github repository in the description below okay in the package json you can see i have changed the name to o5 tut for the fifth tutorial in this series you can change that whatever you want now i've also got server.js instead of index.js as the main file and i have changed the scripts accordingly so it says node server and nodemon server instead of node index and nodemon index other than that we still have the same dependencies as the last tutorial so date fns and uuid are here and the dev dependency of nodemon is here and those are the few changes for the package json of course i have renamed the index file to server.js you can see everything else is currently the same here in the server.js file that was previously the index.js file and we will come back to that i want to delete the event log file that is currently in the logs folder you can leave the logs folder if you want to if not it will be recreated and that's because we still have the same log events js from the last tutorial here as well and we might make a change to that but i won't do that now either we'll come back to the whole events topic what i do want to show you are the other folders and files that i've added and these are simply to be served by the server so we can make sure it's working i've got a style dot css file in the data folder i've got a data.json and a data.txt and you can just put in whatever information you really want to and style the page or web pages however you want to i've got one image in here again you can download the repository and get exactly what i have or you can use your own and then in the views folder i've got a 404.html an index.html and a new dash page.html and i also have a subdirectory named subdir and in this subdirectory is another index.html that will be the default page for this subdirectory route and so we're going to serve all these different file types or content types from the server today now let's make some changes and additions to the server.js file i'm going to eliminate some of these blank lines and then when we created a class my emitter that extended the event emitter in the last tutorial it got kind of weird when we initialized our object and it was also named my emitter so i just want to name the class emitter and this is just kind of for my peace of mind after that we can get rid of that extra space too we will leave all of this here i'm going to get rid of the comments about the listener i'll also get rid of the timeout that we added because that will not be needed and i'm going to comment out both of these right now and then we'll come back to those later on when we need them give a little space in between now let's go ahead and import the common core modules that we'll need for this file at the top and the first one we need is http and so that's one we haven't covered yet that we will today and we just require http after that we need path and we'll require path and we'll also need fs for the file system so we'll require that expo require and we're also going to need fs promises so that equals require fs but then at the end dot promises and those are the common core modules we're going to need and now we need to define a port for our web server so not only will it have the address of localhost because it will just be a development server on our local machine but we need to say what port it will be on and so now we'll just define port in all caps definitely a constant here and we should say process.enb dot port because if we were to host this somewhere it would use this information and then we can say or and i'll say 3500 today i've seen different ports used and so today we'll be using port 3500 if we were to host this somewhere it would have a different value here now that we have defined the port let's go ahead and create the minimal server we can do that by defining server and let's set it equal to http dot create server and now that gets a request that we'll just call req and a response in a function and now we have our request and response headed into the server and we won't really do anything here at first except let's log the request dot url and let's log the request dot method we're not quite ready to launch our server yet because it still needs to listen for requests so we say server dot listen and this should always be at the end of your server.js file and we give the port value and then we have an anonymous function and here we'll just say console.log and inside this console we'll use a template literal we'll say server running on port and then let's once again give the port value here and that's really all we need so once the server starts we can see this message and i'll go ahead and press alt z to make it wrap so we can see it i've got chrome open over here so we can eventually request a page as well and we should see this statement in the console once we start our server i'm going to go ahead and save the file and then open a terminal window by pressing ctrl in the back tick you can also do that from the terminal menu that's hidden behind the three dots right now in my visual studio code and now let's go ahead and start the server by typing npm let me lower case there run dev and this will start nodemon that will listen for changes and the server should start up and we can see that we now have server running on port 3500 it's not going to serve anything we're not sending any type of response back yet we're not using the response but it will log the request and the request method so let's go ahead and type localhost 3500 and notice in the console we've got the request here which is just the slash and then the method is a get request not a post request or a put request or a delete request but a get request and so we did successfully log those requests but there's just nothing that comes back yet i'm going to go ahead and press ctrl c for now because we don't need to run the server while we're making a few changes and now of course it can't serve a page but that's no worry we'll be serving a page soon what we can do is talk about what else we could put in the server and so after we're logging the url and the method and the url was just the slash as we requested the index page what we could do is build a path and then serve the file so i'm just going to copy some code in to discuss it but this is not what we'll want to do and i'll discuss why i'm going to go ahead and expand visual studio code for now too so we don't have to wrap the lines but we could listen for a specific path so we're defining path here we've got two semicolons we just need the one and if it is just the slash or even if we specified index html either one of these would work and this is an if statement then we could set the response dot status code to 200 which means successful we can set the response header content type to text slash html because we would be serving the html page and then we could go ahead and use path to define the path value and look in our views folder for the index page that we have right there and serve that page and how we would do that would be to read the file that we currently have and i didn't bother with handling the error in this version but what we would do is read the file and take this data and then send the data and we would be sending the contents essentially of the index.html file this would work but this is not efficient we would have a statement for every address that came in and actually every file because of course we'll be serving some files that are not text html and feel free to try this version out i'm going to show another version that we will not use but that you would also see in a possible simple server and i'm just showing part of it here i guess i could go ahead and close it out but we could put in a switch statement and we could look at the request url value that comes in and here if it's just a slash we could go ahead and once again set the status code set the path read the file and then of course break out of our switch statement and we would have to have a case for every value that came in even a duplicate case essentially if this were to be index.html and not the slash and this would also be very big and you would have to think of every possible file that could be requested your default could of course be the 404 if it doesn't exist but this also takes up a lot of space and once again it's not dynamic and so this is not what we want to do today either a switch statement is useful though so let's take a different approach but we will still use a switch statement as we construct what our server does today so we'll start out once again let's keep the console log statement with the request url and method that could be useful as we monitor things during development and then let's look at the extension of the request url that we get and so we can use the path dot name method to get that extension so let's just pass in the request url now once again if it's a slash maybe there will not be an extension name but then we can handle that as well so now that we've defined the extension let's also define content type and now we will use a switch statement to set the content type and i'm going to paste this in because we'll be looking at all the different possibilities for file extensions so there are several and now we can go over this but what we see up here above is we set our extension and then we define content type with a let at least we begin the definition and then we can set it in the switch statement so here we're looking at the extension and now if it's dot css we set the content type to text css and we break and we go on and do this for every type of request that we expect to get or file content type that we expect to have requested and you can see there's a couple of different images here we've got an image slash jpeg and an image slash png text for text slash plain we also have json which is application json so all the different types of files we expect to serve and importantly here the default is the text slash html because this could not have an extension at all it could just be the slash or it could have the extension of html and so we just handle that as the default okay the next part if you have not worked with chain ternary statements you may not like me too well right now but i do like chained ternary statements so i will paste one in and explain it what i want to do is set the value of the file path and now a chain ternary statement like this one can be confusing especially if you haven't worked with them much or if you have worked with them at all but let's break it down we're saying that whatever the result is will be saved here in the variable file path so we say if the content type is html and the request url is just a slash then this will be the value and we set the path name using the views directory as well as the full path name here we get from the dur name value and we set it to index.html but if that's not the case then we look at the next condition and that next condition is here and we're saying okay if it's an html file type or content type then if the last character in the request url is a slash this accounts for our subdirectory possibly and not just the main directory and so this would be just a little different because we not only need the views in the file path but we need the request url that would specify the subdirectory and so this is what happens if that is true and then if not we go ahead and just check now to see if the content type is html at this point since these other two were not true and then we would look at whatever was requested in the views folder because that's where the html should be however if that's not the case then we're going to go ahead and just use the directory name or the file path and the request url because this could be css or an image or something in one of the other folders that would be specified in the request url so another way to break this down is everything that starts with content type is a conditional statement and everything here that starts with path is a result if the previous conditional statement is true and then the final one the final path because there's two paths in a row is just the default if none of the others were true and so you could break this out into an if else if else if else statement if you want to do that i prefer chain ternaries myself and that is what we end up with let's go ahead and add one more statement here for the file path and this will be an if and we'll say if there is no extension which means it was probably a slash and didn't have a file extension and the request url dot slice minus one which is the very last character of the request url is not equal to a slash so maybe we've just requested a file like about or new page we have a new page over here but we didn't type the dot html afterwards well this will make that work anyway and sometimes that's cool to do so this wouldn't really be required but we're just making our addresses work even if we don't add the dot html at the end so then we'll just say file path plus equals and then we'll add the dot html here so we still serve the correct file although we might not have typed in the dot html in the url bar in the browser so we should probably add a note to this and i'll just say whoa i went too far here we go makes the dot html extension not required in the browser and that's what that statement is for okay now we have our file path and content type so we're ready to actually check and see if we want to serve the file and we can do that with defining file exists and setting this equal to fs dot exists sync and let's just pass in the file path because now we are checking to see if this file exists or not so this will be a true or false value that we get back and we can check that by saying if file exists we don't need to say if it's true we're just saying if the file exists then we're going to serve the file but if it doesn't exist we also need to have an else and there are possibilities if it doesn't exist this could be a 404 or this could be a 301 which is a redirect now we still aren't serving anything yet we have determined our file path and we have determined our content type but this is where we would serve the appropriate files right here for now let's just go ahead and log to the console and what i want to log here inside of the else is the path dot parse that will tell us the different parts of the file path let's go ahead and pass file path in and take a look at a file path that doesn't exist so we need to start the server again i'm going to go ahead and change this so we can see the browser as well and then i'll open a terminal window and now let's go ahead and type npm run dev and the server is running we can reload first and just make sure we get the home page well i guess we won't get a home page but we can make sure the request goes through there we go and so we'll add the homepage very soon but let's go ahead and look for something that doesn't exist at all because the file does exist so when it checked it didn't get into that else area let's just say this is old right here okay there was something that didn't exist i'm going to expand the terminal window up so we can see this broke out now and we can see using the path.parse we get these different parts of the file path and what we're interested in right now is the base notice it's old.html even though it didn't exist that's what we get because it was added in the file path so that's what we're going to use as we come into this area that does not know if the file should be a 301 or a 404 and we'll determine that with a switch statement i'm going to go ahead and highlight this and just change that console log now into a switch and now instead of just path.parse.filepath we want to put dot base at the end of that so that would be that value and then we get our curly braces for the switch statement we don't really need the semicolon there and we need to put our cases in here so our first case would be old-page dot html and this is an instance where we had an old page and we want to redirect it to the new page that we see over here in our file tree so let's handle this redirect first and this will be response dot right head and then a redirect is a status code of 301 and now we need to go ahead and put in the value here for the header and this would be location and then the location is slash new dash page dot html and now that we've handled the redirect we need to go ahead and end the response and after we end the response well we need a little column there we break out of the switch statement there and now let's add our next case our next case is going to be another redirect and it's www.page.html and now i'm just going to copy this much because it's very similar here for another redirect and paste it down we've got a 301 again but instead of new page we're just going to redirect to the root which is the slash and so that will just redirect back to the home page once again end and break and now let's have a default as well for our switch statement and this could be larger if you had more redirects to put in here but the default should be the 404 and so this is where we're going to serve a 404 response and let's save this once again i'm going to expand visual studio code because that was wrapping a little weird but here you can see what we have now we're currently not ready to serve the new page or the home page yet we haven't got anything else being served but we did handle the redirect so what we need now is a function instead of repeating the same function here for a 404 or up here for other files a function that we can call in both spots okay let's scroll back up to define our function and we will put that before the server and after the port so let's call this function serv file because that's what it will do it'll need to be an async function and then it's going to need the file path so we can grab the file that's needed it's also going to need the content type so we can set the content type that is going to be sent and it's going to need the response object to go ahead and send that response so now that we have our parameters defined and we have the name of the function let's go ahead and start by defining the try block we already know it will be an async function so there will be a try and a catch so we can use await as we get the information we need let's go ahead and set the error block first so we'll log the error to the console and then we also want to set the response dot status code this would be 500 it would be a server error here if we could not read the data from the server that we want and then we need to end the response notice i called the parameter the full word response before we were sending the res for response right here and that's what we will pass in as we get down there further but in the function i'm using the placeholder here's the parameter with the full word response and now in the try block let's get the data from the file so let's define data and set this equal to await fs promises and then dot read file now we need the file path to read and we'll use utf-8 and after we read the file and we are awaiting that information we can use response and then right head and inside right head we'll go ahead and say 200 status code and then the content type there we go content type will be equal to the content type value that we have passed in and then finally we'll have response dot end and we can just send the data back now some of you may be thinking ahead and there are some problems that we will have with this but this is the very basic to start out with so i want to do that first now let's go back down into the code and call the function where it needs to be so after we have the file path and the file event exists here we say serve the file so this is where we would call our serve file and this should have the file path value you have the content type value and it needs the response object and notice here it's res because that's what it's defined as to begin with not in the function definition of serve file but what we're using in the server okay let's just copy this and we'll make some changes below as we want to serve a 404 here so i'm going to paste this in and then we'll just change a few values okay here we know exactly what file we want to serve so we're going to use path dot join and pass in the directory name and then we know it's in the views folder and then we know it's the 404.html file and we also know the content type so we can just set that to text html right away and then once again we need to pass in the response object so let's save that as well now i'm going to resize visual studio code again and we'll go ahead and scroll down and it looks like of course nodemon's already working and yes the requests are coming in and we served our 404 already because old doesn't exist so let's go ahead and back out of here and see if we can serve the index and yes the index page serves just fine too i'm going to go ahead and show the terminal so we can see all these requests coming in and you can see old was a get request and then it requested the style sheet requested a fave icon which we don't have requested a index page then and once again the style sheet and once again the fave icon after that but we still have some file types that will be issues so let's take a look at some of those as well say if we went to our data folder data.txt well that seems to work okay even if we aren't sending the accurate file type with it but what about data dot json that's just text that's not really json like we would want to send back even though it looks like it and could possibly be parsed into it that is not the format that we really want to send let's also check our new page because it should have an image on it and the image doesn't work either so we have some file types creating problems what should be working is the redirect so let's go ahead and type in old-page.html and yes it does redirect immediately to the new page so that's good and what about requesting something in our subdirectory and yes we got our subdirectory index page so that also works like we expect it to let's go back to the data and see if we can fix that json first so data slash data.json i'm going to hide the terminal window for the rest of this and scroll back up to the function that we created serv file and i'll go ahead and expand the window once again let's start by changing data that we've defined here to raw data and then let's define data separately so here we have data and this is going to be equal to a ternary statement we'll look at the content type that we already know and if the content type is equal to application slash json then we'll have a true value that follows the question mark and that true value will be json.parse and this would be parsing the raw data that has been read otherwise the false value would simply be the raw data likewise when we send the response we're going to need an extra line for this so we'll just do it on a separate line and keep the parentheses up here and down here now what we need is another ternary statement here and we'll look at the content type once again we'll say if it is equal to application slash json make sure i spell json correctly then we're going to have a true and a false and the true would be json.stringify and we can go ahead and pass in oh not the raw data the data and otherwise it's just going to be data that we send oh and i don't need that semicolon that would cause an error and we can save our file let's go ahead and resize visual studio code and reload our json and now we can see it is served in a much more expected manner here and this is truly json that has been stringified and of course it was parsed to begin with now let's go back to new page where we have a broken image and we can fix that as well so right now we definitely get our new page html but the image doesn't come through now this is because the image would not use utf-8 encoding i'm going to expand visual studio code again and let's go ahead and put these values on separate lines as well and now we can close out the parentheses down here on a separate line too now we still want the file path here but instead of just utf-8 we're going to start out by saying if the content type and that is not so we'll say if it does not include but we're using includes here and we're looking for the word image in the content type because both the png and the jpg had the image in the uh content type that we have down here in our switch statement and you can see it right here okay so we're looking for that to see if the content type includes image and if it does or if it does not include image i'm sorry because we have the exclamation mark that means if it does not include it would be utf-8 but if it does let's just put an empty string because a string is expected in that spot but if we don't specify then it will go ahead and let the image go through so now we can save this and go back and check our new image page let's go ahead and reload it and we've got our image now that we have the cute dog image there's one more change we need to make as i expand this and if you have thought about this we're sending a status 200 even when it's a 404 because the 404 processes through here as well so we need to check we don't want to send a 200 if it's a 404 so right now in the right head let's go ahead and break these out as well into separate lines just gives us a little more room to work and see everything that's happening so now instead of just saying it's a 200 status code we can say if the file path dot includes once again and if it includes 404.html well then we know it should be a 404 and else it should be a 200 so once again a ternary statement just determining the status code between a 200 and a 404 here in our function we can save that and now we are close to being finished we are serving all the files and they are having the correct content type header sent with them but we haven't logged anything yet so let's go ahead and remove the comments here and let's copy each one of these and first let's take where we're going to emit from before we handle the listener and as we do that we'll scroll up here to see the server now right after the console log where we're looking at the url and method would be a good place to emit and we're going to admit a log but what we want to say here is a template literal instead of that generic log event emitted that we had we'll go ahead and pass in the request url and then after the request url we have a tab delimited log file so we'll put in a tab then we'll put in the request method and after the request method we'll go ahead and put a comma because we're going to add another parameter to our log event handler and so now what we want to say is which file we want to put this log to and this will be to the request log dot txt so we can save that one and we'll go ahead and copy the emitter one more time because we also want to put the emitter up in the error where we could catch a server error and here we'll log something different so instead of request url this is going to be the error.name and instead of a tab here we're going to have a colon and a space and then we can put in the error dot message and we're going to go ahead and log this to the error log dot txt and we can save that too now let's go back and grab that listener that we need and get rid of these extra lines at the bottom you can see we've used just about a hundred lines even and let's go ahead and get rid of one of the lines here because by the time we finish we will have 100 even that way now where we'll put this is right between the emitter and the port and we will be listening for a log but instead of just a message we're also going to have a file name passed in and then here we'll take the file name in the log events function as well so let's save that too but we need to go back to our log events function and here we can say it's really the log name so let's say log name and we need to replace the event log that we used as a generic example last time for log name right here and with that saved we should be good to go so let's go back to the server just to have it pulled up and i'm going to open the terminal window again and looks like we're already running on port 3500 so let's switch this over and now let's reload our new page and we got several things here including the log statement because i believe we're still logging those to the console so that's kind of cool let's look in our logs and i'll make the terminal windows smaller and here's a request log so we got a request we got several requests in and we logged exactly what we were getting the request url and the method and they're all get methods they're all get requests so what about an error well we're going to have to create an error so let's do something simple like change something we know is wrong so where it says read file let's just remove the e off of read file we'll save nodemon will restart the server and when we reload we should definitely get an error yes and we log the air to the console because that's part of our function we didn't get a page served because we crashed with the error here or at least it caught it and that's what we should do let's look at the error log and this is what we would want to check out if we had a problem it tells us of course the date and time is the stamp and there is the error name a type error and there is the error message fs promises dot read fill is not a function and that's because we had a typo with read file so we can go back and fix that now being in development mode nodemon is going to restart due to the changes and all should be well as soon as the servers back up and run so let's go ahead and reload and we got our new page again of course we can get our index page as well and everything seems to be serving as it should now there are some issues here as we look at our typical request log file what really stands out is these are all get requests we didn't put anything in our code to handle any other type of request really we just assume the request method is git and of course we would have to put in more checks to see if it was a post or a put or what we might want to do with the information in interacting with a database so there could be a lot more to it but this is a dynamic server that will serve the typical files you would have with a website and even some data files that we have as far as data json and text file here now express js makes this so much simpler but this gives us a lot of context to think about and what all goes into creating a web server so i think you will appreciate express js that much more once we begin to work with it now that you have created a web server with node.js only here we're at the webpage for express and you can see the definition of express it is a fast unopinionated minimalist web framework for nodejs and this is found at expressjs.com now you need to have node installed already and be able to use npm and then you can add express to your project and as it shows here it shows npm install express and then dash dash save you no longer need that you can actually just type npm i express today we're going to reference some documentation not from the getting started link but from the guide and go to the routing page and this way you'll know how to find the documentation for what we're going over today let's go to visual studio code in the last node.js tutorial we build a web server using only node.js i'm going to start with the completed code repository from that tutorial and that's what you see right here in visual studio code but if you don't have this repository you should be able to easily follow along without it or you can download or clone it from the starter source code link that i'm providing in the description below okay i'm looking at the package.json file for the repository now if you just downloaded or cloned the repository you're still going to need to install the dependencies not that we're going to use all of these today but if you just want to get the repository up to where we are you could go to the terminal from the terminal menu and choose new terminal or you can use control and the backtick that's what i use in windows mine defaulted to powershell and that's not what i want let me switch that over real quick to get bash that's what i expected it to be and once i have a get bash terminal you would type npm install and this will go ahead and update all of the dependencies or install them if you don't have them so i'll go ahead and do that as well and you can see it will just check my dependencies here it shouldn't take long and when it's finished i'll know i've got everything installed that would be in this repository so currently i have nodemon as a dev dependency uuid and date dash fns which stands for functions all installed as either a dev dependency or a regular dependency now what we want to add is express so we'll type npm i express we don't need the dash dash save that's understood at this point so we want to install express as a dependency and it just takes a few seconds and express should be added and you can see it here in my dependencies listed between date dash fns and uuid now just to update a couple of things for this tutorial i'll switch the name to zero six tut instead of zero five and instead of node.js web server tutorial i'll just put express tutorial in the description but those are minor changes and nothing that you actually have to do i just wanted to go ahead and update that let's move over to the server js file or we'll make the rest of our changes today now much of what is here and i can close the terminal as well much of what is here we don't need anymore so if you want to make a copy of this file or if you want to rename the server.js to old server.js or something like that to save this code in your repository go right ahead because we're going to get rid of most of it we need to keep the path requirement the path import at the top and then i'm going to remove everything else down to line 12 where we keep the port definition and then i'm really going to remove everything for now except where we listen here at the very bottom on the specific port now we can go ahead and make some changes right at the very top on line one let's go ahead and import express so we'll define express and we'll set it equal to require express after that let's define app now we could use another name here like we've used server but typically you'll see examples using the word app so that's what we'll go ahead and define as well and you set it equal to express and you call express and so now we can use the app where we've been using server so we'll have app dot listen at the specific port that we have provided now we'll use path later it's the only thing we haven't used up to now and now let's come down a couple of lines and we can define our first route so we use app and then we specify the http method that we want to route so we'll use the get method here so any get request that comes in that looks for just the root this would be our index page then we can specify what to do with that and this takes an anonymous function here or a function it doesn't have to be anonymous but this is what you would typically see and what i will do and so now what we do with the route it happens right here inside this anonymous function so let's start out very simply as you might expect and let's just say response dot send and then we can say let me use a single quote just because i like to better hello world and that's what would be sent in response and so now we can go ahead and start the server and we will expect to get this at the index page now to start our development server if you remember as we specified in our package json we can use our dev script that uses nodemon so nodemon knows to restart anytime we make changes when we save our file it will identify those changes and it will restart the server js so let's go ahead and open our terminal again and with the terminal open at the bottom i'll type npm run dev and it should take just a second but the server will start up and we expect to see that server running on port message inside the terminal window let me drag this up and see what we get there we go server running on port 3500 so now we'll go to chrome and open up chrome let's open a new tab and let's go to localhost and we've got port 3500 and we get a very small hello world that is simply delivered in text okay let's minimize chrome and let's drag the terminal down so it doesn't take up quite as much space but we'll keep the dev server running but let's go ahead and serve our index file that we have in the views folder now we do have an index.html here instead of just sending hello world we can send a file and you do that with res which is the response dot send file now inside of send file there's a couple of different ways we can specify the file to send in express one is to put in the path say dot slash views slash index.html and then we can provide options and one option is to specify the root directory and this is where we can use that dame value that is native to node and this will tell node and express exactly where the root directory name is and then inside the root directory we would look inside of views and there we would find the index file so this should provide the file let's go ahead and save and it says it's restarting due to changes once the server restarts will bring chrome back up and now that we've got it let's reload and now we've got our index page and i'm going to resize chrome so we can just see it and the console when we want to at least when i pull chrome back up if i can get it to drop down not that we really need the whole thing we don't have much content here but we've got that so now i'll go ahead and minimize and pull it back up again when we need it so that is one way to do it now let me copy this down so we can just leave that in commented and the other way to serve a file is what we're already used to doing in node and that's why i usually do it this way is we can use path.join and then we specify the directory name and then we join in the views folder and then we go ahead and join in the index.html and this will work in the same way so let's go ahead and save this now let's bring chrome back and we can reload and we should just get the same result and we do we still have the index page so that is more how i would do it because i'm used to using path.join but you could do this either way okay in the file tree we can see we also have new dash page.html so let's just highlight all of this and i press shift alt and the down arrow and i can just copy all of it down and then we'll remove the commented outline and then we'll change our app.git route here so instead of just looking for the root we're looking for new dash page dot html and upon that request of course we want to switch this to new dash page dot html as well and save now let's go ahead and look at chrome and see what we get if we type in our new dash page dot html so we have slash new dash page dot html and we get the new page so that works just fine so we can tell that we're not just intercepting the route right here because this is only looking for the slash so even though this has a slash this does make it past and this is okay we get new dash page dot html instead of stopping right here because this does read this down like a waterfall so it would check this route first but now we know it does make it to this route however if you have the same question in your mind that i would you'd be thinking about what if somebody requests this slash index.html well this is where express really helps us out because express also accepts some regular expressions in the routing so instead of just saying slash here we can specify and we can say this must begin with the slash and this must end with the slash and then we can say or and then we can also say slash index dot html so if that request comes in it will route also to the index.html let's go ahead and save that and once again look at chrome and now let's switch back to our slash without the index and now if we go ahead and put slash index.html we still get the index and if you remember when we built the node server we also made it so you could just type in index without the dot html let's see what happens if we do that oh we get cannot get index so that means it could not find that page and this is what express returns by default if it's a 404 and cannot find that and it's also worth mentioning where we did a considerable amount of code to handle things like the status code and the content type in our nodejs only web server here express automatically sets the correct status code and content type so for that 404 it already set the 404 likewise for this html and we're sending an html file it already sets the correct content type and of course it sends a 200 if it finds it as a successful response now we can add just a little bit more regex and that way we can make the dot html optional on this request and if we put the dot html inside of parentheses and put the question after it that's exactly what it does so let's go ahead and do that to our new page as well and so we'll put the dot html and a question mark after it making the dot html optional in the request so we'll save both of those let's come back to chrome take another look and now index without the dot html let's go ahead and reload oh and the server is still restarting as we see down here restarting due to changes let's see if it's going to restart it's taking just a little bit may need to restart the server altogether do control c to get out of that and then i'll do npm run dev again and we'll get that server running again okay with the dev server once again running i'm not sure why it hung up there let's go ahead and refresh the page and now we get our index page with no dot html inside of the url something else we handled in our node web server that we created was a redirect so let's do that with this express server now and i will copy down the new page request but now if we're requesting an old dash page with or without the dot html at the end we want to redirect that to the new page express makes this very simple so let's go ahead and remove a lot of what you see right here and we'll put in res.redirect and now we are sending that to the new page but we do need to put a slash here so we have our new page and we'll go ahead and get rid of that parenthesis we don't need now there is one thing missing and what's missing here is the response code now one will be sent by express but it's going to send a 302 by default and a 302 will not necessarily get the search engine to change saying it is a permanent redirect what we really want is a 301 so we can do that by specifying the status code at the beginning of the redirect and then putting a comma afterwards and that will go ahead and send the correct status code that we need because we would want the search engines to go ahead and say hey this has been permanently moved to new page there is no more old page and we can go ahead and check that in chrome as well i'll pull that back up and inside of here we can just type old dash page we don't even need the html and it redirects to the new page now as i mentioned express handles these routes like a waterfall so at the very end of the route you can essentially put your default your catch all if you want to and here once again we'll use just for a get request we'll put in the slash and then an asterisk afterwards which is the all and that's kind of like if you're used to writing sql a select all so what we have here with regex is a slash followed by anything will default to this route let's go ahead and put in our function as well so we have our request and response and the arrow function and now inside of here what we can do is essentially send our file so i'm going to copy this line and bring it down here and we do have a custom 404 page and that's what this is for because express will send a 404 status code and tell you it cannot find what it's looking for even if you don't supply anything but we want to supply a custom 404 and so i'll go ahead and switch new page to 404 here but what it won't do because it will find the file to send is it will not send the 404 status code it would be a 200 because it could find the file and it would be serving exactly what we told it to so it wouldn't know to send a 404 at this point so what we can do is chain in the status code here with a status 404 and just another dot so that all changed together so now we have a response with a status code of 404 and we're sending our custom 404 file let's save this and go back and just request something that doesn't exist so up here instead of new page i'll just put page and we get our custom 404 what we haven't talked about yet are route handlers so i'll just put that here in a comma we have route handlers and that's exactly what these are following our app get route where we tell it what we are routing these anonymous function expressions that we have here following the route are route handlers and we can chain those or use more than one of those so let me give you an example of that so we'll have another app get and let's say the request comes in for hello.html and let's go ahead and make that optional as well since we're doing it with the others so we have the dot html is optional and after the quote we put a comma and now we have our function expression here the anonymous function and it's request response but then we also add in a next and this is an arrow function inside this function i'm going to console.log and just say attempted to load hello.html and then after our console log or our call to the console log we call next and what that does is it moves on to the next handler or the next expression and you won't see this often but you can put a comma and then just put the next function right afterwards so here we'll have a request and response we could have a next if we were going to chain another one after this but if this is the last one in the chain it won't have a next it would just be the request and response and here we can response.send and we'll just go back to our hello world message that we had at the very beginning and if we save this we'll go ahead and be able to see the console at the same time let's pull up chrome and over here we'll go ahead and request the hello and now we get hello world in our small text in the browser and we also got our console log message attempted to load hello.html so you can see we're calling one function and then when next is called it goes on and calls the next function in the chain now let me show you another way that you might see functions chained together and this way is really the way you would probably see it more often i'm just pasting in some very very basic functions here so i've got function one that has request response and next and logs of the console 1 and calls next function 2 same construction logs of the console 2. function 3 doesn't have a next it logs the console 3 it also sends the response finished and then it is complete so how would we use that in a route all three of those so instead of the commas we saw chaining the anonymous functions we can say app.get and let's say this is for the route let's just call it chain and we'll go ahead and make the html optional as well and after that you can provide these handlers in an array so we'll just have one two and three in this array so all the route handlers are provided right here in this simple line and we're calling all of the functions that are above so let's go ahead and save and go to the route chain in the browser i'll switch from hello up here at the top type in chain and you can see in the console we got one two three and in the browser we got finished in the small text because it just sent the text finished and these route handlers work in a way that is very similar to what we would call middleware and middleware is what we'll be covering in the next tutorial but you'll get used to seeing this call to next so it can call the middleware likewise we'll make a change for our 404 as well because right now we're just delivering a custom 404 for get requests and that come in right here with this path but we can go ahead and improve that using middleware as well and we'll also talk about how to serve those static deliverables like our style sheet the css any javascript that we want to go to the browser and anything else like images that we have currently broken on the page when we go to new page or some data so we'll talk about how to provide all of those as we cover middleware in the next tutorial today we'll learn about middleware in the expressjs framework we're going to start out with the code repository from the last tutorial but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link i'm providing in the description below so what is middleware it's really anything between the request and the response so the route handlers we created in the last tutorial are really middleware too and we can see one of those right here that i'll highlight on the page we've got a route handler for the new page route so you could consider this middleware and of course we covered different things you can do with these route handlers including chaining them as we see right here i've got a route handler a comma and then a second handler or we chain them in an array by creating three separate handlers here and then putting them in an array in the route right here so just a little bit of a recap but those are overall considered route handlers even though they are essentially middleware so what about creating some specific middle well where there are three types of middleware there's built-in middleware there's custom middleware and there's middleware from third parties of course the custom middleware is what we create ourselves so let's get started with the built-in middleware i'm going to create some space right underneath the port definition and i'm going to paste in some built-in middleware and the first thing we should notice here is that is app.use and app.use is what we often use to apply middleware to all routes that are coming in and of course just like our http methods get and of course we could use post delete put and other methods as well just like those methods this all works as a waterfall so if we put app.use above our routes then this will apply to all routes that come in and you can see in here we're calling express dot url encoded and then this receives an options options object there i can say it and extended is set to false and that's usually how you see it you can look in the documentation if you want to dive deeper into that but that is typically what you see so what is this middleware for well it's for handling url encoded data in other words form data so when that comes in in the url then you can pull the data out as a parameter so we need to add this middleware that is built into express in order to get that data when form data is submitted now i'll add an additional layer of middleware and this is for json as you might expect so not form data but if json data is submitted we need to be able to get those parameters or that data out of the submission and we use this middleware to do it so once again app.use and then express.json and now this is applied to all routes as it comes in and finally for the last piece of built-in middleware that we'll apply today we're going to serve static files and this is important because if you remember from the last tutorial we were not yet applying css we had a broken image in our new page and files that should be available to the public were not available and that's what this middleware does it serves static files so once again we start with app use and then it's express dot static and we supply the path and here i'm using path join as we have many times before we supply the directory name value and then the public folder is what we're going to put all of those in so when we save this we now need to create a public folder and inside this public folder we need to drag our css folder and we need to drag our image folder and let's go ahead and create one more folder in here and let's call this text and then from our data folder let's pull down the data dot text and put it inside the text folder so now we have some files that we want readily available for the public and express will automatically route those files there because this is applied before our other routes so it will search the public directory for the requests before it moves to these other routes let's go ahead and open a terminal window from the terminal menu you can choose new terminal or like me control and the backtick and it opens up the terminal here i've got a bash window and that should work just fine i'm going to type npm run dev to start nodemon for our development server and this should launch everything and yes we're already running on port 3500. let's go to chrome and i've got a blank window open in chrome so we can type localhost 3500 was already there and we get index and it's already applying the css so now let's go ahead and comment out the middleware so we're not using those static files and let's reload our index page and see what we get now there's no css applied so it is absolutely finding those public files and applying them however we didn't really change the path in those files and we should now i'll reload this and we do see it's applied but let's take a look at those files here's our index and we were going up out of the views directory and then into the css directory and that's not really there so this is being a little forgiving let's just get rid of that because we know this path is available to the public of course after the directory name there so after the root of the url it should just be css style dot css and we can double check that by going to chrome and from there we can just type slash css style dot css sure enough we pull up our css file in the browser so it is available to the public let's go ahead and make these same changes on our new page dot html we can get rid of the dot dot slash for image for the image directory and for the css directory and save that and also in our custom 404 we can get rid of the dot dot slash and save now all of those should be working fine and they really were before but this cleans it up now let's go back to the server js and let's consider adding some custom middleware that we write ourselves let's create a custom logger and we want it before anything else because it we could put it i guess after the static files are served but then we would not log the request for the css or the images or anything like that so if we put it at the very top then we'll see the requests for everything as they come through so we'll just call this custom middleware logger and now we'll start with app.use and inside of app.use we'll put an anonymous function that gets a request response and since we're creating this it needs to have next so we can move on notice the built-in middleware did not need next call it's already built into that but we need to call next inside of our custom middleware so let's log to the console inside this logger and we'll go ahead and log the request method where here's the request dot method and then give a space and we'll log the request dot path as well and now with both of those sent to the log the only other thing we need to do is called next so let's save this and now let's go back to chrome and we can still see our console here let's request the page and you can see we get the get request here and there's the slash which is the home page and we also see the request for the css file while logging to the console is okay for our middleware logger what we really would like to do is create a log file and we've already created a log events function back when we were working just with node so we can go ahead and use this log events function in our logger as well let's create a new folder in the file tree and call this folder middleware from here let's pull the log events dot js file straight into that directory and now that we have log events there we really don't need to change much and we are already exporting log events as well so that's good what we will need to change is where it writes the logs because we don't want it to create a logs folder in the middleware folder so if our with our path dot join what we need to do is add in one extra spot here i did not mean to hit return there we go and just go one directory up with the two dots and now that we've got that i'll copy it and we need to add it to this path and this path as well so when the logs directory is created it is here where we already have our logs directory from the past rather than being created in the middleware directory and now we need to take log events and import it into our server so we'll scroll to the top and let's just put it underneath path and we'll say const log events equals require dot slash middleware slash log events and that completes that we can save and now we can use log events inside of our custom middleware logger let's put it right above the console log and we have log events and log events accepts two parameters the first is the message and the next is the file that it should write to or create so inside for the message we'll create a template literal and i'm just going to paste this in so you can see the full message it is the request method and then we put a slash t for tab so we have a tab delimited log file and then it's the request.headers.org which should be saying where the request is coming from what website sent it to us and then we should get what url was requested so say it's a get method and the request is coming from google.com and they are requesting our index page after that we need to tell it what file to create or write to and we'll call this rec for request.log.txt and now we should be good to go with our log events function let's go back to chrome one more time and let's go ahead and request our index page it was requested we see the requests here and now we also see a request log has been created and there are two requests it was a get request both times and it was undefined because we're just running our node server right here on our local host and you can see what was requested as well the slash for index and the css style.css and while this works once again let's look at the server.js while this works we're really importing a function to use inside of our anonymous function that is our logger that has the request response and next as any middleware should so we can clean this up a little bit let me go ahead and copy the anonymous function and everything inside of it ctrl c to do that and now we'll go back to the log events.js file and here we can define another function just called logger we'll set that equal to this anonymous function and now logger can be our custom middleware that we export so down here instead of just exporting log events which we'll use later or we wouldn't need to right now at all i'll go ahead and put both inside of curly braces once again we won't be using log events anymore inside of the server js though i'm just exporting this for use later when the need arises so back at the server js instead of log events we'll need curly braces now that there's two functions being exported and we'll import logger from the log events file and now with logger being imported and all of this logic inside of logger we can just say app use logger and now this is much cleaner and should still work in the same way so let's pull up chrome once again and let's request the index and we see the console logs still work let's look at the request log and yes we have two more requests in the request log once again notice that it says undefined here is the origin because we're just using our local host server here as we pull this up so let's make a request from another domain i'll pull chrome back up and now a new tab and we'll go to google and on google let me go ahead and expand this and open up the dev tools with control shift i now that i have dev tools open what i want to do is just call fetch and i'm not really interested in the data we're just going to fetch the destination and let's see what we get we get a course error it says no access control allow origin but let's go ahead and check our log file and our log file does show google.com as the request origin so you may have seen that error we got before from google that showed the cores error and that stands for cross origin resource sharing and now this will lead us to third party middleware so we can install a dependency i pressed control c to stop our dev server i'm going to type npm i for install and then cores cors and this should take just a second to install and we'll be able to see the new dependency in our package json when this is finished and it says it's finished already let's check the package json and here we see cores now added as a dependency so let's go back to the server.js file okay so we're in the server.js file here and we need to go ahead and import cores so we define cores and set it equal to require cores once we have that we need to apply the middleware so we want it to come as soon as possible but after the logger so let's go ahead and apply cores here so we'll say app.use and then we can just call cores inside of the app.use i'll go ahead and put a note here that core stands for cross origin resource sharing let's save that and now go back and start our dev server again with npm run dev and once the dev server has started we'll pull up google it says it's good to go it looks like and let's go back to google and let's make the same request and now there's no cores error we get a promise pending of course from fetch as we expect you there but there's no error and that's the main thing is we can request data now from the google.com domain and it doesn't create a course error let's minimize chrome and let's look at our request log again and we once again see google in there so the domain the request origin did come from google.com okay now let's go a little deeper into course i don't want to make this a full tutorial on cores because that can get pretty deep however cores for cross origin resource sharing is something that does need to be applied or you will get those errors however this just leaves it open if you had an open to the public api this would be fine you're using cores and everyone can use it but for many applications that's not really what you want so let's create a white list and we'll define it with const white list and inside of that we can have more than one domain so let's say https slash and then www dot your site whatever your dot com is whatever application web application domain will that will access this back end node server that's where you want to put this domain here but say you might also have a variation maybe you've got a variation without the www dot or maybe you're working on a local dev server and you launch from go live down here click to run live server live server always runs on http colon slash 127.0.0.1 which is your computer and then it gets a port like 5500 i believe is the default so maybe as you're building a react app you're running your react app on this port or a different port on your local host or you've used the ip address which 127.0.0.1 is the same as having localhost there anything like that so let's add those to the whitelist and of course we should add http slash local host and we're using 3500 here today now you would take these out after development but of course you would leave in whatever domains should be able to access your data or your back-end server and that would be your web application say your react application is at whatever domain you would leave that in here so we've created a list that is allowed to access the back end that cores will not prevent so now we need to create the function that will allow cores to do this and this is all contained within the cores options so that's what we'll call this lowercase cores and then camelcase here with a capital o for options and we set this equal to an options object and the first property is origin and origin can accept a function so we have an anonymous function here and it gets the origin which is not the same as the origin right here necessarily this is the origin coming from whoever requested it say google.com and then a callback function and again the two origins a little confusing but it's right from the documentation so that's kind of how we need to do it so we've got the origin there with the anonymous function and we can say if the white list dot index of and then we pass in the origin that is passed in to the function if that index is not equal to -1 in other words if the domain is in the white list then we're going to go ahead and let it pass and then we can do the callback and the first parameter in the callback is null which is usually the error so there's no error and then we set the second one to true and that just means that the origin will be sent back saying yes that's the same origin and it is allowed and then we can have an else and in the callback here we have an error instead of null and we create a new error and we can just say not allowed by cores and so that is the message to go along with the error now that is the first property here in the course options we need to add one more so we put a comma and then we put lowercase here options success status there it is and we send a 200. and with that we can save and now that we've created the course options we need to pass those in right here and notice we did not include google in these course options now google could access without an error before we put in the options let's go back and make the same request from google and see what happens now we once again have a course error so let's go back and let's go ahead and change your site to google.com server is restarting it looks like it's hanging up nope it's going to go ahead and do it there we got it and we go back to google once again and now it's in the white list and we fetch and there is no error so we know our function is working as we expect it to so when we come back and look once again you can change this to your domain whatever your project wherever it will be hosted say you've created it in react or view or even vanilla javascript spelt even whatever you might create a front end project with that will access this back end you want to put that domain in here or maybe variations of again remember you might not have the www or it might be optional anything like that so that allows you to put in domains that can access the routes and otherwise cores will prevent them so very useful third-party middleware i want to go back to chrome one more time and create that error one more time now that we've taken google out of the white list at least i thought we took google out of the white list maybe i didn't save after we did that that's exactly what happened i hadn't saved the server js file yet save here nodemon is restarting it's taking it just a little bit maybe i need to go ahead and restart it once again every now and then i have to restart it manually so npm run dev get the nodemon server up and running i'll pull up chrome and let's see if we can get that error again so yes we've got the cores error here now let's look back in visual studio code as well and you can see we got the server's still running but we got this big error and up here it says our message error not allowed by cores and this huge error here now we can handle errors in express as well but express is already handling them it has the built-in error handler by default and that's what's happening when we throw this error it is going there however let's go ahead and add a little custom error handling so we scroll down to the very end remember it's a full chain so we want this after everything else even after our 404 here i'm going to paste this in and you can see i'm using app use once again and then this is an anonymous function and it doesn't just get the request response and next it also receives an error parameter and then we can log to the console the error stack if we want to or just the message or whatever we can go ahead and send a status 500 server error and we can send the message to be displayed in the browser so i'm going to save this and we'll go back to chrome but we won't use google anymore let's go ahead and just use the page that we have here and i'll see if i can resize there we go i'm going to reload and look we got a not allowed by cores even though we requested our index page but our custom error did work and it sent this to the browser now why did we get that well let's go ahead and look at the log here's our request log you can see it's once again undefined so undefined is a problem because that's not in the white list so during development you want to go ahead and make one modification to this function right here after the minus one go ahead and put in the or operator and then say no origin essentially the exclamation mark origin which would be the equivalent of undefined or false and we save that and now it should work now after development we probably want to remove that as well just like we want to remove some of the development urls that we have up here in the white list so now let's go back to chrome and see if we can reload our index page yes and now everything is working as we expect it to and we can also tidy up that custom error handler so let's scroll back down to it and we see the function that we have here inside of app use i'm just going to copy that complete function and now inside the middleware folder let's create a new file and let's call this error handler with a capital h there so camelcase errorhandlerjs and now let's define our error handler and set it equal to and we'll remove the function keyword and we'll go ahead and put an arrow after this and we've defined our error handler but what we want to do that we're not doing yet is also create an error log and this is where exporting the log events function that we left here comes in very handy so now we need to import that here not the logger but the log events so let's define log events inside of the curly braces set that equal to require dot slash log events and now that we're importing log events we can go ahead and use that in the function as well so we'll call log events right here before we log to the console and once again this function gets a message first and then the name of the file that it needs to write to or create so this will be a template literal and i'm just going to paste in the values once again here instead of anything from the request such as the method like we were logging before we're going to log the error name and the error message and then we'll put a comma and go ahead and specify error log dot txt as to where we want to write the error to and we can save this but we're not quite finished yet because we need to export this function so we do module dot exports set this equal to error handler and now save and now we need to import error handler into our server so let's scroll to the top of our server js and right underneath logger i'm just going to go ahead and copy this down and let's change this to error handler and instead of log events we're importing from middleware error handler and save now we need to use the error handler where we previously had the larger function in this file so it will be much cleaner so let's go ahead and select this full function delete that and paste in error handler and we can save and we got an error the app crashed let's see what we've got so if i scroll up it says app.use requires a middleware function so something about the function probably didn't get imported correctly let's go ahead and scroll up to the top and look at our import statement and oh yeah we were using curly braces around logger because it was one of two functions from the file but from the error handler it's the only one so let's go ahead and remove those curly braces around error handler and see how everything goes it's restarting the server right now and server running on port 3500 that part looks good so with the server running the best way i know to create an error would be to go ahead and remove this or no origin for now and we'll go ahead and save and then we'll try to reload the index page once again in chrome so it's starting the node.js server and now that it's running let's reload and we've got a not allowed by cores as we expected an error in the console and now we have an error log file over here in the file tree and we can see we got our error not allowed by cores at 1827 so let's go ahead and look at the request log and we should be able to line that up with what request happened here as well and we can't so everything there is working as expected so now that the error is logging let's go ahead and put that or no origin statement back in for now so we do not keep getting rejected by cores we can go back and we can once again request the index page and everything should work well when the server restarts there we go we've got the index page now okay there's one more thing to do before we're finished today and that is to compare app use to app dot all and that's what we're going to do right here as we change up the 404 just a little bit so with app use we could do something like this app use and specify here at the end of the chain everything basically that came in from the slash which would be the root but app used does not accept regex and also app use overall is more likely to be used for middleware but app.all is used for routing and this means it will apply to all http methods so it also does accept regex so what we can do inside of this is just put an asterisk it's at the very end of the page so we can just say pretty much anything that made it here should get the 404 at this point let's go ahead and save the file and test it out i'll pull up chrome and here we can put in the slash dave and yes there's no page that's dave html so that is a 404 although the request did log just fine we can customize our 404 response just a little more so let's start that out by just setting the response status because we know it's going to be a 404 no matter what after that let's check the type so we can say if the request accepts and now we'll look at the type the content type and we can just say html here and express will translate that for us and after that then we'll put what happens because if this will resolve till true or false here so then we can go ahead and look at sending a file or something else inside of here so what we'll do is say response dot send file and go ahead and send that 404 now this is very much like what we were already doing but now we can check for other types as well that might be accepted so let's go ahead i'll just copy all of this down and we'll change some of it so shift alt and the down arrow copies everything and now we'll say if the request accepts json well then we don't want to send a file at all so this will be entirely different let's get rid of all of this and say response.json and we can put some json here inside of our response and let's just say error and over here we can say 404 not page let's just say not found which is essentially what a 404 is and really what we're doing is creating a small waterfall effect here with the if so we could make it another else if here and then finally an else for our last possible outcome once i can spell else and here we'll just respond and we can set the type to text just txt for the type actually and then we can send and inside the send we'll just put the same text that we have up here 404 not found so i'll paste that in and that should work as well so now i'll go ahead and remove these blank lines and we will test out our 404 once again i'll go to chrome and i've already got slash dave in the url so i'll just see if i can reload this 404 once the server restarts and now it's restarted i'll hit reload and we got the 404 and it is html now i would have to use postman or something else to ex try out the json file or possibly text as well we would change the headers for that and i'm just going to let you trust me that that will work for now instead of breaking out postman or anything to just try out those two other routes but overall that is what you can do to customize a 404 with app all and i hope you understand at least a little bit of the difference between app.use which is for middleware and does not accept regex and app.all which is more for routing and it will apply to all http methods at once today we're going to talk about creating routers in the express js framework and we're going to start out with the code repository from the last tutorial but if you don't have it you should be able to easily follow along or you can download or clone the starter source code from the link i'm providing in the description below alright in visual studio code we've got our server.js file and from the previous tutorial we've got a lot of code in here and really what we can do is break these routes out into individual routers that are essentially mini servers for each specific route or many apps as we create our app with express here these will be mini apps and we'll for refer to them as routers so over in the file tree let's create a new directory and let's call this directory routes and now inside the routes we can create routers for each route that we are handling so let's create a new file here and let's call this subdur.js because we have a subdir directory in our views folder that we haven't handled at all yet now in the subdir dot js we need to start out with a few requirements once again and the first would be express just like we did in the regular app or server.js if you will so we have require express and then after that just like we have before we have applied express however now we'll define a router instead of an app and we'll set this equal to express dot router with a capital r and then we're going to go ahead and need the path module as well from common core module in node.js so we'll require path after that let's just go ahead and put our module dot exports and set that equal to router because that's what we'll always do when we create a router and then we can import that back in the server.js when we need it now we're ready to just pull our routes in so let's look at the server.js and the routes that we had or did not have at this point for the subdirectory and i don't believe we had any yet we were just routing to our specific views for index and the new page and of course we were redirecting the old page so we hadn't handled anything for the subdirectory yet it has its own index and it has a file called test html so i'm going to copy how we handled the index for the root and then we can just modify that in the subdirectory and instead of app.get we now have a router so let's replace app with router and now it's router.git and then we can handle this slash or index for the subdirectory the same way we did for our root and we have a request and response and we can get remove this commented line that we had in there before and then we are sending a file and we're sending the root directory we get the directory name here and then we want to have views but now we have to think about this because we are not inside the root so we can't just look directly into the views directory so we need to come up out of the routes directory we created and then into the views directory and then we're not only just looking for the index because that would be the root index now we need to specify the subdirectory that we have and then the index.html that's within that subdirectory file after that let's copy this down and i can press shift alt and the down arrow i'm using windows it may be different if you're on mac or linux and now we have another git route but this will be for the test dot html and so we can replace index with test and remove the initial slash we'll leave the html optional this is regex that we can use within the route and now we're sending a file once again but instead of sending index we're sending test not text dot html and we can save that now that we've created the router file for the subdirectory we need to go back to server.js and underneath where we serve the static files and we set that we need to go ahead and provide a route and we do that with app.use in the server file and now let's provide the route that we are providing the router for and then we can go ahead and require the router that we have created and now this will be in dot slash routes slash and there's the sub directory and after we provide that we should be finished and now this will route any request coming for the subdirectory to the router instead of the routes that we are providing below through app.git such as index and new page so this will match in front of these and of course we can put all of these in a router and we will next but let's go ahead and start the dev server i'm going to press control on the backtick but you can go to the terminal menu and open a new terminal window and if you remember we type npm run dev and this will start our local dev server with nodemon which will listen for any changes and it's on port 3500 so let's go to chrome and i'll go to my blank page i'll type local host port 3500 and there we've got our index file and that's fine but we want to go to the sub directory and see if this is working so we've got sub dur and yes we've got our subdirectory index page and let's go ahead and see if the test index page in the subdirectory is also working i said index test.html actually and there's our test page in the subdirectory as well okay now let's ask for a page that does not exist in this sub directory and let's see what we get well we've got our 404 page but there's something important to notice here in the past when we've got our 404 page it had css supplied for it now we didn't put css on the previous subdirectory pages that was not included anyway but if we requested a 404 on any other page that was not in the subdirectory it does have css applied so why is the css not working for our subdirectory well it's because we haven't told express to use the public folder or public directory if you will for the subdirectory so let's copy this line down with shift alt and the down arrow once again and now we can specify the subdirectory here and tell express to use that public directory before we didn't supply a directory but the default is the slash anyway and so that's essentially what we were doing but we can save these and now we should be able to go back and request our 404 basically any page that doesn't exist in the subdirectory and probably get the formatted 404 yes now even though we're in the subdirectory and i requested a page named dave that doesn't exist we got a 404 that actually has the css supplied you can even see the request coming through down here for the css in the sub directory and it now works now i'd like to make one quick correction from the last tutorial that i did provide information that was correct in older versions however in newer versions of express express does support regex inside of app.use and i said it didn't when i compared app.use to app.all but now you can have regex there and so if we are to require a router and we put a slash with an asterisk here this would supersede the subdirectory router in other words all routes would go to this router if we supplied that of course we don't want to do that so we want to specifically state just the slash or we could even get more specific and we could say hey it must start with the slash and it must end with the slash and then of course we would only be providing that for the slash right here but that is because it supports regex and in previous older versions express did not support regex inside of app.use but in the route it now does let's go ahead and create a router for this root directory here so let's say dot slash routes slash root and now add the semicolon one more over and save and now we need to go ahead and create this route because right now it doesn't exist so let's go over here to the file tree i'll collapse the views folder we don't need to see what's open there but inside of routes let's go ahead and create this root dot js and now inside of the js file let's go back to server and grab the routes that we were using for the root and we have our index page our new page and a redirect for an old page and control x will cut those out and we can paste those inside of the root but we also need those imports and basically everything you would normally start out with for a router these three imports at the top express router and path so we'll put those at the top of root as well and then at the bottom once again you want to have module dot exports and set that equal to the router now what haven't we changed yet is the keyword app here that we were using in the server.js we need to switch to router as well we can once again get rid of this commented file and we have to once again consider the route that we're providing because now we're in the routes folder so yes we have the directory name value but then we need to come up out of the routes folder and then look in the views folder now this will be correct now we're not looking in a subdirectory so we no longer have to provide it there let's go ahead and copy this and paste it into the route for the new page as well however the route for the old page is a redirect and this will be okay to leave it as it is so let's save the root and let's go back to the server we can also get rid of some of these examples of route handlers that we had such as the hello right here and the chaining the route handlers that i had previously provided for the chain route let's just delete all of that to clean it up a little bit and save our server.js it's now restarted so let's see if these routes are now working with the new router and we'll come back and just go to the root and yes we got the root page let's go to slash new dash page html should be optional and there's our new page and our image is working which means we're getting our static file routed correctly to the public directory where the image is stored and now let's go to old page and see if the redirect still works and yes we redirected back to the new page let's go ahead and type in index instead of just the slash and yes we still get the index page everything in the new router for the root is working correctly with our routes working correctly let's talk about how we would set up an api or a rest api if you will and that's what is more important when we're working with say the mern stack as say express node and of course react on the front end or you could substitute any database technology for but we've got node and express here and we want to organize a api which is what we would more than likely create with node and express say compared to a static server for web pages although you can do that it's much more likely that you'll create an api and that's what we'll focus on here so underneath these routes we're going to create one more route and this will be to employees and then inside of routes it's going to be in a subfolder named api and then the employees and notice this will just be routed by the user going to employees they will not have to type api so let's go ahead and save this and then let's start creating that route inside of routes we want to create another directory and that's api and then inside of the api we want to create our employees router and that's employees.js now up here inside the data folder we've already got a file named data.json let's go ahead and rename this file and let's call it employees.json and let's give each employee inside of this file an id and we'll just make these chronological so we've got one and an id of two and now that we got that we can just go ahead and save our small employees data file and remember that's employees.json inside the data folder and we've created the route here inside of server using app use now it does not need to have any static files as we'll just be delivering json data from our api so we wouldn't typically have any static files like we would with a web page so now let's go back to our employees.js route let's start out our route just like we did the others so we want to define express we'll set this equal to requiring express and then we want to go ahead and define our router once again and we'll set this equal to express dot router with a capital r and call router into action and we'll once again need the path common core module from node.js so we can require path and after path let's go ahead and define an empty object named data and from there let's set data dot employees equal to require and now let's get that json file so we need to go up out of the api folder and then we need to go up out of the routes folder then into the data folder and then to get employees.json and so this is kind of like connecting to a database this is just what we're doing for this tutorial and and dev of course in the future we'll work on connecting to and of course you could replace that with your database technology of choice but once again just for this tutorial just for dev we're just going to import some json to simply work with here so now let's go ahead and create our module.exports and set that equal to router again as we always do with a router and now we can set up our routes now instead of just saying router.git and creating anotherrouter.post and another router dot put and of course putting those paths in there like we could one thing we can do is say router dot route and then provide the route and then we can chain the different http methods that we want to provide for this same route as a get request and a post request can both go to the same route but there can be a different result for each so let's handle the get request first and here's a request and a response and now inside the handler of the get request let's just return json and let's return all the employees so that will be data.employees now for the post request we can just come down here and say dot post and once again we can have a request and a response we can handle this completely differently for the http method post than we do for git and now with the post we'll get parameters coming in to the request and we can refer to those parameters with request dot body and then dot whatever the name of the parameter is and we had a first name and a last name and a post request would be posting a new employee so what we want to do i'm not going to put in the full code that we would have in an api at this moment because it's not really about coding an api right now we're handling routes so we just want to see how each one of these would work so let's say the first name that we return in the json will return what is sent and that's request dot body dot first name and then let's go ahead and return the last name as well that's request dot body dot last name once again not writing out all the code for an api at this point just showing how we can get the parameters from a post request and then we're just sending those parameters back but this is how we could handle each route in an api now let's go ahead and do the same thing with a put request i have a request and a response and this would be the http method that you would use when you're updating an employee for example but we could do the same thing we could get the res.json here and as a matter of fact i can just copy this down and of course the code would be different if you were writing an actual api because you would be updating at that point and we'll do that in the near future just not going to do it yet and then let's get a delete now a delete would be different we wouldn't be getting the first name and the last name we would be getting the id so we'll just send the id back in this case and that would be response.json once again let's go ahead and send the id back here and this would be request.body dot id now you can see we've chained each http method together and we've got git post put and delete all coming into the same route on our router they're just different request methods and of course this being the last one we'll go ahead and stop right there and i'm going to save this but we're going to add one more route we have the route coming in with just the slash just the root but then also we could have router dot route and then a slash but we could have a parameter directly in the url and that's what we're showing here is a parameter and this would be a get request that has a parameter inside of the url so now down here and of course you could do that with other requests too we're going to use a get request so let's go ahead and put the handler for our get request here we have our request and response and now inside the handler will once again respond with json and we'll just say here's the id requested and now this is different instead of request.body it's request.params.id and that's because we're pulling the parameter it's a named parameter actually and we're pulling it directly out of the url so here we're responding once again with just what we received just as an example now i'll put in p future code will go ahead and actually code out an api right now handling the routes and so all of this is inside the router and i guess we didn't need path right here at this moment so we can get rid of that but all of this is inside the router for employees let's go ahead and save this and we can test it out and our server is still running below so we can now check these routes with thunderclient thunderclient is an extension in the past i've used postman which is a separate program to test apis let's go ahead and try this extension out you can find it under extension search for thunder client and it allows you to save different routes you want to test so right here i'm going to go ahead and choose the get route that i created first there it is for all employees which of course there's only two and you can see here is our http method and here is the route and now i'll click send and here's the response i can just make the response full screen but we've got both of our employees returned and that's exactly what we expected so now after testing the get route let's go ahead and test the post route so i'll choose that from our list well let me go to collections i believe i saved everything there there we go let's choose post and now we're once again going to the employees route but it's got post let's look at the parameters and see if those were saved and it should be under body actually there we go and i'm posting a new employee named john doe so let's see if we get that in return we'll send that and let's look at what was returned yes we got john doe sent back to us and that's all we're going for today once again as we're not writing out the actual code to add the employee or update the employee and things like that in the near future yes i will okay put should be the next one to test so now it's a put method at the same url and once again we are sending some john doe oh actually sending just the id and the first name of what we wanted to update and of course i think i had the put request just sending back the first name and last name so maybe we'll just get the first name back let's see what we get when we test put and yes we just got the first name back and that's what i expected so that works also now let's test the delete route of course it won't actually delete the employee this time around and looks like we're sending just the id and we should get that id back expand and yes in return we've got the id back so that route is also working now there's one more git route where we could get a specific employee and let's see if that one's here or here here we go so this is our route with employees but then it has slash and the number one where we're requesting just one employee not both so let's go ahead and send that and see what we get in return and we returned the id of one so that route is also working and again this extension is called thunder client if you want to check it out for testing the routes in your api now as a challenge before my next tutorial you could go ahead and write out the code to update the json that we were receiving and of course just hold it in memory don't really update the file but you could test out what you want to do here for each of these routes and you could handle each one of those and i'll come back with some code for that in the next tutorial and what i really also want to talk about in the next tutorial is organizing the rest of this api including the server file and setting it up because after that we'll pretty much be ready to connect everything to whichever database technology we would want to so we'll organize this with an mvc pattern that is model view controller and of course i can come back and add some extra code here to handle the api data just for the json as an extra test it's not really anything to do with specifically express that's just javascript in handling how you would basically do crud operations create read update and delete today we will organize our node.js and express api server with the model view controller design pattern you may have also heard this design pattern referred to as mvc that said remember express is by definition an unopinionated framework and you can organize your project however you would like i'm just demonstrating mbc because it's a popular pattern we're going to start with the code repository from the last tutorial but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link i'm providing in the description below okay we're right here in visual studio code and we've got our server.js file and we want to use the correct terminology so we were keeping our data inside of a data folder and you can see i've renamed it to model it still has the employees.json file in there and we're just emulating a database here with a employees.json file instead of connecting to one at this point because you might have my sequel or in mind or whatever later on in the series i plan to show however right now we're just going to simulate that connection to a database and now besides that we have a views folder and really with a restful api we won't have many views if hardly one maybe we would have a welcome page that gives some directions about the api but that's about it we're not really serving a bunch of static pages or resources what we will have though is a controller folder so let's go ahead and create that when i said controller and really i should make this plural because it could host more than one so let's go ahead and call this controllers and it will hold controller files so inside of here let's go ahead and create an employees controller dot js file now currently we have all of our logic really inside of our routes so if we open up routes and the api directory and then look at employees js our logic is essentially the route handlers so for router dot route and then we come to the get http method we've got this handler that returns all of the employees so what we would want to do would be remove that logic from here and take it to the controller so we could name this something like get all employees and then we can just assign that route handler as a function so now we have a get all employees function that is part of the controller so let's save that but what we also need here is the data so the data that we were pulling in to the employees js route inside the api is actually will need to be inside of the controller at this point instead of the route we're breaking that out and so we'll put that at the top of this file as well so these functions can work with that data so i'll save this again and now back inside of employees let's pull out the logic from the post and here we go with that logic and now we'll call this function a different name we've got create new employee and we'll set it equal to that action and then the next function will go ahead and name as well and that will be update employee we'll set it equal to what we find here in the put portion of this route and now we'll come back and assign that to update employee and finally as you might guess we'll have delete employee and we'll set that equal to the handler for delete not copy but cut there we go and we can paste that in here as well now i'll go ahead and save that now we're not finished with the controller by any means but we have the first actions in here for these routes and we haven't put anything back in here yet but we will but there's one more function to create here and this would be called just git employee instead of get all employees so let's go ahead and get this action as well or route handlers what we could refer to those as still and let's say git employee and now we have all of these different functions defined inside of our employees controller and of course we're pulling in the data here at the top but as you might expect we need to export these as well so we'll have module dot exports let's set this equal to an object now and so we had get all employees and then we had create new employee and we had update employee and delete employee and then we had get employee and so we're exporting all of these functions now let's go back to the employees js routes and let's import our controller so let's call this employees controller and we'll set it equal to require and then we have to consider where we are so we go up a folder and then up another folder and once we're there now we can select the controllers folder and inside there we find our employees controller now we could deconstruct those functions here as we import those in but i think i'll leave the name employees controller because we're emphasizing creating a controller here and then we'll just put in the functions and in visual studio code i believe if i start typing the functions it's going to import the part that says employees controller for me sure enough it does so now we can have create new employee and select that and here we're going to have update employee and finally we should have delete employee not this delete we didn't quite get that right delete employee there it is and so all of these actions are coming from the controller or route handlers we could say and this still doesn't look right we didn't get we've got a d in front of there employees controller dot delete employee that's what we should have and now here we should have git employee with the employees controller so this definitely cleaned up our route file here quite a bit and we've separated the logic into our controller and that's really what the model view controller pattern is all about and so we could do that with other routes if we had other routes as well but now we've really cleaned up our whole project let's go back and do just a little more cleanup in the server.js and we can get rid of some of these views that we're no longer going to use one other thing i'd like to do is you see we're pulling some things into the server file right at the beginning and we're starting to use the logger right away but we're taking up a lot of space here with cores and we don't have any kind of configuration folder over here in the file tree yet so let's go ahead and create a config folder not js just config folder and now we can go ahead and create a course options dot js file right there and back in the server let's go ahead and take our white list and cores options and cut those out of here and paste them into our cores options js here and i'm going to put each one of the urls on its own line just so it's easier to read and after we define the white list at the top we have our cores options and as you might guess we need to do module dot exports set this equal to cores options and now we'll need to import this back inside of the server so at the top of the server here we could just put it right under cores and we'll say const cores options and set this equal to require dot slash dot slash there we go config and now inside of the config folder we have our course options we can save that let's see if there's anything else we can clean up i've got some extra comments in here of course this being a tutorial that kind of makes sense let's make them a little bit smaller let's put form data besides that and the routes look good and we have our catch all 404 here and we have our error handler and we have made our server.js much smaller we're down to 44 lines of code including some spaces here and we have pulled that logic out into a controller so that has really helped clean up but we're really not going to need these example of a subdirectory anymore so let's go ahead and get rid of that and that means we can get rid of the app used for the static files in the subdirectory as well and save that once again and that means we can delete the subdirectory route from the tree and we can also go ahead and delete the subdirectory over here in the views and let's go ahead and delete the new page and that means we can go into our root routes and we will not be routing to a new page or an old page any longer either and get rid of both of those and now that's quite a bit of cleanup but at least we still have our splash page for the index if we wanted to put some directions for our api there and so we're handling that inside of the root route and that's in our routes folder and then we have our api directory and that handles the employees routes here okay with everything cleaned up in the last tutorial i promised to go ahead and provide the javascript code this is not so much just dealing with express or node but the code if you were to have an api that was going to update not the json file but just in memory and kind of emulate an api before we've connected it to a database so at this point i can go ahead and provide that code and if you had went ahead and worked on the challenge that i said at the end of the last tutorial you can compare your code to what i did i'm just noticing i didn't change the path to the data folder here either for the employees because really it didn't need to come up to anymore so you would just come up out of the controller folder and then you're not even going into a data folder at this point you're going into a model folder but i'm going to change this all of this now but i wanted to say that correction about the path and let's have the data object set like this and if you work with react i'm thinking in more of a reactive way when i do this but i've got the employees data set still pulling it in and just setting it directly to the employees property of the data object but then i've got a set employees function here as well that i'll use inside of these other functions now as you might expect get all employees doesn't really need any extra work we're just returning all of the employees by referencing data dot employees and that's fine now to create a new employee i'll paste in my code and we can review it there's a little bit more work there so when we get a new employee we want to create the new id and instead of importing a package like uuid or something like that i'm just grabbing the last employee in the json array and i'm adding one to the id that exists there whatever the last one is so of course i need to make sure they're in chronological order which will come into play later but that's what i'm doing here other than that first name and last name assigned to the parameters we're getting from request.body and then of course it's first name and last name after that we're making sure that a first name and last name are sent and if not we're sending a response 400 saying hey we didn't get the required data after that i'm using the set employees function to go ahead and set the employees to the new information and of course the new employee as it at the end of the array and i'm just realizing here i didn't send a different status when we send the employees back and i'm sending all of the employees instead of just the new ones so we could see the update but here we could also send a status of 201 which means it created the new record and we'll go ahead and save that okay update employee gets a little more complicated but it's not too bad so let's go ahead and paste this code in and review it so here we grab the employee if we received an id as a parameter and we should because we're updating an existing employee and if the employee does not exist we're returning a response status 400 meaning we did not get good data to update we have the message here as well employee id is not found and that would be the end of it if we didn't get an id but then if we did then we're checking to see if we got a first name go ahead and set the employee that we found to the new parameter value and the same for last name and of course to that parameter value as well and then we filter the array and we remove the existing employee record from it so then we have an array with the existing or i mean without the existing employee id and then we have the new employee data that we've updated here so we go ahead and create an unsorted array and we need to remember it's unsorted because we do need this array in chronological order by id and so when i call the set employees function from our data object i go ahead and sort the array by that id column and this is a chain ternary statement this is where it could look a little complicated if you have not worked with sorting arrays before so we start out with the ternary statement here same pretty much if the one element of the array dot id is greater than the other than return one and normally if we were just doing that then if not it would be returning a negative one but we need to have a zero if they're even as well so then we chain this into another ternary and there it returns a minus one or the zero at the end of that and then of course we send the employees after they've been updated by set employees and that puts the array the json array back in the order we need it right there okay scrolling up to get a little room to put in the code for the delete employee we paste this in it looks very similar we find that employee but if we didn't get the id we send the 400 response just like above we also create a filtered ray a filtered array just like above we did in the update but then at this point we've deleted the employee so all we need to do is set the employees to the filtered array and then we once again return the employees and finally the get employee and of course this is handling a request for the data of just one employee so we find out who that employee is and once again if the employee doesn't exist we send that same response that we did not get good data but if the employee exists all we need to do is return that specific employee and then we're down here to the exports so i will include all of this code inside of the git hub repository for the end this will not be the starter code but the beginning and then you can see this and compare to years if any of my explanation did not make sense and it looks like i've got an error here in the code i think i missed the ending curly brace there it is they should be yellow at least the way i have my visual studio code set up tab that over and save and all looks good now i think i still have an issue here the delete employee did not close out if i close that out then i can remove that there we go almost had a bigger mistake that would have taken me longer to figure out so save that and now it looks like get employee delete employee update employee create new employee get all employees that all looks like they're defined correctly and there's no more error here in the file getting rid of the extra space and let's go to thunder client but we also need to go ahead and start the server up because i don't think we have done that yet and with the dev server open type in i mean the terminal open we'll type npm run dev there we go and start the dev server and then we'll be able to test out our api running on port 3500 that's what we needed we'll open that employees api collection that i'd created in thunder client and now this you'll have to create yourself of course if you haven't but let's test get employees and see what we start with there so we've got a get request and we're going to the employees route see the results and we've got the two starter employees dave gray and john smith okay now let's go to post and let's post a new employee and if we go to body you can see i'm sending some raw json here we're posting employee john doe we'll send that post request there's a 201 created response like we wanted to send and now we have john doe here and he has an id of three as we expected him too so now let's go to the put employee and same route with a put request we'll go to the body and see what i'm sending in the json and let's change this let's update the second employee so it's right in the middle and change his name to david now let's go ahead and send and now let's look at our employees that were sent back and yes second employee is now david smith and they're still in the correct order he did not get inserted at the end it's not out of order and so that all worked as we wanted it to now let's try the delete employee and let's look at the body once again what's being sent in the request and we're going to delete employee number three so let's go ahead and do that and now if we look all the employees were sent back now we only have two employees once again and now let's finally request an employee this is get an employee we're going to request employee number one send that request and it looks like we received the information back for employee number one so all of our routes are working as expected once again i'll include everything that you saw today in the employee controller if you're curious about the api code i'll include that and more in the github link that i'm going to put in and don't mistake the final code or the starter source code i will have a link to both today we will add user authorization to our express api we're going to start with the code repository from the last tutorial but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link that i've provided in the description below we're going to get started by simulating a user's database table in our model directory with the user's json file so let's open the model directory and let's create a new file and name it users.json and now we really don't need to put anything in here but i'll go ahead and just put in an empty array as if it would hold json but it's not right now because we're going to write over this really now user authorization requires two routes a registration route to register a new user account and an authorization route to authorize the user after they have created an account but we're going to start in the controllers folder because that's where we'll really handle the routes and what we do with them so let's go ahead and create a new controller and let's call this register controller.js okay in the register controller let's start out by pulling in our users from the users database that we're simulating with that json file i'm going to create an object and set this up much like you would see with use state and react where we have our users state and we'll go ahead and require those users and this will be slash model slash users.json and after we do that let's go ahead and have a set user's method for this object as well and here we can say function pass in the data and now oops i'm so used to writing an arrow function but this will not have an arrow and it's users equals data there we go and now that we've got our set users function and then our users pulled in so we'll have our users database object that contains both of these just a quick way to simulate that so if you're used to working with react this should look kind of familiar even though it's not really the use state and if you're not i hope you're familiar enough with javascript to understand how this will be the users and of course we'll set the users using our setter function right here okay now we need some other things because we're going to work with that json file so let's go ahead and pull in fs promises and that's the file system so we require fs but then after it we put dot promises and then we're also going to need path so let's require path well there we go if i can type path we'll get it and now we're going to need to install a package called bcrypt and bcrypt will help us hash and salt the passwords that we come in so we can securely and safely store them in our database so let's go ahead and open a terminal window i press control back tick here in windows to open my terminal window you could also go to the terminal menu and choose new terminal but here we're going to type npm i and then b crypt that's b c r y p t and we'll go ahead and install this package it shouldn't take long and when it's complete we'll check our package.json file to ensure that it has been added to our project and it looks like we're about ready to do that now so let's see we've got it installed scroll down here and i'll choose package.json and yes bcrypt has been added to our package json file so go ahead and close that out now we can require bcrypt at the top of our file with our other requirements so set that equal to require and pull in bcrypt okay now that we've done that let's go ahead and define our handler for the new user information that we'll receive at this register route so i'm going to call this handle new user and this is going to receive a request and a response now what i forgot to do was make this an async function which we need to do we can use async await with bcrypt and we might need it somewhere else too now when we first pull this information in the request is going to have a user and a password so let's destructure that from the request body so we'll get the user and the password set this equal to the request.body and now we can say if there's no user or there's no password we'll go ahead and return right here with the response the status will be 400 which stands for bad request that's an http status code and then json will go ahead and send a message down and we'll say message and now we'll say username and password are required and i'm noticing that we're not wrapping lines so i'm going to press alt z in windows that's what goes ahead and tells visual studio code to wrap the lines of code it may be different if you're on mac or linux okay so we're sending that response if we did not receive the user password but now at this point we'll know we have received both the user and password and this is where we would let me go ahead and put a comment here check for duplicate usernames in the database and now since we're connecting to our json file to use as our database just as a simulation for this tutorial we can go ahead and check for a duplicate in that json by doing this let's go ahead and define duplicate and then we'll set that equal to usersdb dot users which will pull in the users then we can use find and now out of each user let's go ahead and call this person so it just doesn't get confusing by too many users or using the word user over and over this will be person and then we're seeing if the person dot username from our user database is equal to the user that has been submitted the username that's been submitted by the user and therefore we can see if we get a result as duplicate and then we can say if we have a duplicate then we want to return a response it's response dot send status and it's 409 and that is a conflict is what that http status code stands for but if not we're going to start a try catch now so here's our try and of course we have a catch afterwards where we would catch an error and now let's go ahead and fill out that error block first so if we get an error here we're going to send a response with a status of 500 which would be a server error we'll have json and let's go ahead and send a message here as well and we can just pass in the error dot message that is received okay but in our try block now we need to go ahead and create our new user and of course also use bcrypt to hash the password okay i'll put a comment right here that we're going to encrypt the password with the next line and this is where we'll use bcrypt so let's define our hashed password and we'll set that equal to a weight and then use bcrypt and now oops i'm sorry we don't want compare we want hash and inside of that we pass in the password that we've received from the user we're going to hash it and here we determine the salt rounds so it not only hashes the password but it adds a salt to it and that really helps protect the password if your database is somehow compromised because at that point if a hacker were able to figure out the hash they could crack all of the passwords in the database but adding the individual salts makes that much more difficult and unique for each one so here we'll pass in 10 salt rounds which is essentially the default or the standard there and that will add the salt and the hash all at once and bcrip does a great job of storing those together at the same time so that's really all we have to do there now that we've got the hashed password we're going to go ahead and store i'll put store the new user and this remember is just going to our simulated user table that we're using in the json so here i'm going to say new user and define the new user object first we'll set this equal to username we'll pass in the user and then we'll have a password that we're going to store and this will be our hashed password that we've created now let's set the new data with usersdb dot set users and here we'll pass in all of the data that we have so we're working with immutable data instead of adding to the existing array we're going to create a brand new array and then set all of that in the database very similar to using state and react here so this will be dot dot users db dot users and then we'll also add the new user all in this new array that we are setting as the new users or the new users data okay now that we've set that let's go ahead and write it to our json file which is our database in this simulation so we'll have fs promises dot write file and now i'm going to break this out into separate lines just so we can see everything better i'll go ahead and close our terminal window too so now on the first line i'm going to use path dot join and we're going to pull in the directory name and after that we need to go up out of the controllers directory and then we need to go down into the model directory and then we need to go ahead and write our users.json file so this will overwrite any existing file there and once we've done that we need to specify the data we're sending and this will say json.stringify and we're going to pass in our usersdb.users okay from there let's just log to the console so we can see all of the users or at least the one user that we add but we'll log all in case we go ahead and test it more than once and add more than one user log those to the console and then we need to send a status and that status is 201 to say the new user was created and let's go ahead and send some json again with a success you could put message here or whatever you want but we'll put new user and then we'll pass in the user so we get the username and we'll say created and i needed to make this a template literal instead of using single quotes we need backticks and that way we can pass the user straight into the string that we're sending back so we've created the new user and there's the response and that's basically it except at the very bottom now we need to use module dot exports and let's go ahead and put this in an object so we can pull in the full name of the controller when we import it just like we have previously done with the employees controller and there were finished with the register controller so now let's go to the routes folder and we'll need to create a new route for this let's just call this register.js and now at the top of register js we need to pull in express again and this will be equal to require express and then we need to define our router so we'll set the router equal to express.router and then we'll need to go ahead and pull in the controller so let's call this register controller and we'll set it equal to require and then we need to come up out of the routes folder and then we'll go into the controllers folder and from there we'll choose the register controller okay now that we've got that let's define our router or our route that we're looking for here and it's a post and this will come in at the slash just the root and then we'll pull in our register controller dot handle new user and after that we can use module exports on it i can spell module we'll set this equal to router as we do with our routes and now finally in the server.js at the very bottom of our file tree we want to go ahead and add this route with the other routes so i'll just copy this down to start off we have this slash and this will be app use and now we're going to use the register route and we're going to require routes slash register and we can save that i'm going to collapse this open editor so we can see all the file tree at once and if you remember in our package json we have nodemon installed as a dev dependency and that will help us go ahead and start this dev server so i'm going to press ctrl backtick once again to launch a new terminal window again you can do that from the terminal menu as well and now i'm going to type npm run dev to launch our server and we should get a message here saying what port it's running on and it looks like we've got an error let's see where the error is cannot find module model user json oh and that's because i named it users json so we didn't import that correctly let's go back to our register controller and change that to users.json and we'll save and now we should see nodemon restart and we're running on port 3500. okay now we can check our route and i'm going to use an extension called thunderclient to do that you see thunderclient up here in the top left if you don't have thunderclient installed you can do that or you can use something else like the app postman would be a good one that is normally used to check api routes with but you can find thunderclient in vs code extensions and i've found it's pretty good to check apa api routes with in a dev environment so here it is on the left i've got the circle with the lightning bolt and we can go ahead and create a new request and you can also save collections and i've got a collection here already with the request that i want to make so i'll look at this first one and you can see it's a post request and it's going to http colon slash port 3500 and this goes to auth i don't want the auth we created the register one let me find that there's the register one okay now if i click on thunder client or the file tree or anything else it will hide this and i've noticed that thunder client has a much better appearance when we hide that bar over here so now we have the request on the left we'll get the response on the right and i can still see the node.js console down here at the bottom so with the register route in here and it's a post route i need to check the body and make sure i'm sending something i'm going to send user walt 3 i believe i'll just create walt 1 this time around and here's a password and of course it's unencrypted right now but we'll see what we get in the node.js console because remember we're going to log to the console the users and that should also include the password if i remember correctly and of course we'll get the response over here that the client would get so i'll click send and on the right we've got success new user walt one created now here at the bottom it's got just a little more information so we need to pull this up so we can see more and there you see our user's json and it created wall one and here is the encrypted password that is both hashed and salted that bcrypt helped us create from the password that we passed in so now let's go ahead and pull this down and let's create one more user let's just create walt 2 and we'll send this success new user walt 2 created and now let's once again look at the node console and you can see now both users were logged to the console here in node and they have different passwords as well that are encrypted and of course we could break all that down but i'll let you look at the link to be crypt and i've got another good article on that as well i'll link to both of those in the description below so make sure you do that okay we have tested and handled the registration but of course now we need to go ahead and handle the authorization as well i'm going to close the terminal again and i'm going to copy the import of usersdb with users in set users and i'll go ahead and create an auth controller now in the controllers directory so we'll call this authcontroller.js and now the first thing i'll do is paste in the user's db where we import in our users json that simulates our users database table and we're also going to need bcrypt again so let's set this equal to require and be crypt and now we can begin constructing our function let's call this handle login and let's set it equal to an async function that has a request and a response now inside the function will start out just like we did inside the register controller where we expect to get a user and a password parameter both sent to us and if we don't we'll send back that 400 http status code that says it is a bad request so we can paste those right in i'll press alt z again so the code wraps so they start out the same way but after that there are definitely some differences and what we need to do now is try to find the user that's sent in before we even concern ourselves with the password let's just see if the username exists so i'm going to call this found user and set it equal to usersdb.users.find and then we'll look at each person in the users table and we'll say person.username equal to user and find works this way until it actually finds somebody and then if it finds somebody it will return that value and if not of course it will be false or undefined at that point so now we could log this and take a look but let's just say if we do not find a user if we do not have a found user we'll go ahead and return the response dot send status and we're going to send a 401 which means unauthorized and i could put a link to mdn that lists all of the http status codes in the description below as well i think i will do that so there if we do not find the user we know hey that's it there's no need to look any further this is unauthorized and so it won't work but now if we do find a user we need to go ahead and let me put a note here just say evaluate now if i could spell evaluate there we go evaluate password and we'll use b to do that so let's say match is what we're going to define and we can just say await bcrypt dot compare let's pass in the password that we receive with the request and we're going to compare it to the user that we've found and the password that exists for that user and now if we do have a match if the passwords match we can reply with the json and once again we could send a success message and we'll just say oh back ticks again and we'll say user and pass in the user value and from there we'll say is logged in but we could also have an else there and if we do not have a match at this point then we'll say response send status and once again this will be a 401 unauthorized and we can save that and we're essentially finished with the function except for adding the module.exports here once again and we'll put it in an object again and we'll say handle login but the other note that i want to add to this and we're not doing it in this tutorial but we will in the next is this is where we would create a jwt to send to use with the other routes that we want protected in our api so we'd actually create and send a couple of jwts which would be a normal token and then the refresh token so let's put create jwts that would be right here in this spot and we'll just leave this note here for the next tutorial but now we've created our handle login in our auth controller so we once again need to create here we go scrolling the tree we need to create a route for auth so we'll just put auth.js right here and we can copy most everything we have in the register and just change this over in auth so at the top we need express and router just the same but instead of register this is the auth controller we can select all of those with control d and change them to auth and after that instead of handle new user it is handle login that we want from the auth controller and save and our auth route is complete now let's go back to the server once again and let's add the auth route as well so let's just copy down i press shift alt and the down arrow to copy a line down in windows and i'm going to put in the auth route here i'll press ctrl d to select both and just put off and save that as well with that complete let's go back to thunder client and we'll look at our auth collection there it is and let's see if we can pull up the correct route this is the auth route that's great so i'll hide the rest and we get a better look here i want to see that terminal again so i'm going to press control and back tick to pull up the node terminal and here we are in port 3500 so we're sending another post this is going to localhost port 3500 and the auth route right here so let's look at what we're sending in the body and we want to log in with walt 1 and the password that we had previously submitted as well so we'll see the client what the client receives here on the right and we'll see if anything is logged i can't remember if we logged anything to the console this time around let's go ahead and send this well we at least log what route we hit here in the console but now this says user wall 1 is logged in let's go ahead and try to log in with the user we don't have like walt 3 and now we get our 401 unauthorized which is exactly what we wanted and i'm just thinking now earlier we didn't send something to register that already existed so let's try to register a name that we've already registered we registered walt 2 last time this is going to the register route so now let's try to register and we got a 409 conflict that's exactly what we expected there as well so it appears our routes are working correctly and everything seems good so this is handling authorization with username and a password on the back end and we have simulated a database by using users.json but in the future we could connect this to mongodb mysql or some type of database technology and you really wouldn't use just a json file in production or at least i wouldn't recommend it but we will come back in the next tutorial and learn how to protect routes with json web tokens today we will add protected routes to our express api by using jwts let's discuss the jwt strategy we're going to implement today so what are jwts what is the acronym jwt and abbreviation for well i'm very excited about the upcoming launch of the james webb telescope but in this case that is not the correct answer concerning our node and express rest api jwt is an abbreviation for json web tokens jwts can be considered to be a form of user identification that is issued after the initial user authentication takes place when a user completes their login process and they are authenticated our rest api will issue the client application an access token and a refresh token the access token is given a short time before it expires for example 5 to 15 minutes and the refresh token is given a longer duration before it expires possibly several hours a day or even days while no security measures are perfect we do want to consider the risks of cross-site scripting and cross-site request forgery i will provide links about both in the description below our api will send and receive access tokens as json data to avoid the previously mentioned risks it is recommended for front-end client applications to only store access tokens in memory so they will be automatically lost when the app is closed they should not be stored in local storage or in a cookie essentially if you can store it somewhere with javascript a hacker can also retrieve it with javascript just keep access tokens in memory which you might also refer to as the current application state our api will issue refresh tokens in an http only cookie this type of cookie is not accessible with javascript refresh tokens do need to have an expiration which will then require users to log in again refresh tokens should not have the ability to issue new refresh tokens because that essentially grants indefinite access if a refresh token falls into the wrong hands so the overall access token process involves issuing an access token during user authorization the user's application can then access our rest api's protected routes with the access token until it expires our api will verify the access token with middleware every time the access token is used to make a request when the access token does expire the user's application will need to send their refresh token to our api's refresh endpoint to get a new access token of course the refresh token is also issued during user authorization our rest api's refresh endpoint will verify the token and cross-reference the refresh token in our database too storing a reference to the refresh token in the database will allow refresh tokens to be terminated early if the user decides to log out and again refresh tokens need to be allowed to expire so indefinite access cannot be gained we're going to start with the code repository from the last tutorial but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link that i've provided in the description below let's get started today by installing the node packages that we're going to need so i'm going to press ctrl and the back tick you could also go to the terminal menu and open a new terminal window from there i'm going to type npm i and then we can add all of the packages that we need all on one line so the first one is dot env the next one is json web token no spaces there and then the last one is cookie dash parser and we'll press enter and all of those packages will install and then we'll check our package json just to make sure the dependencies have all been added and that was fairly quick let's go ahead and look at the package.json and we can see under our dependencies we've got the cookie parser we've got dot env and we've got the json web token package with that complete i'm going to close the terminal window and over in the file tree i'm going to create a new file at the root level and i'm going to name this dot env just like that and now we can put our environment variables in here i'm going to use all caps and type access underscore token underscore secret and set that to an equals and then we'll get the value in a second and then i'm just going to copy that down and change the word access to refresh because we're going to create an access token and a refresh token so let's save this much for now open the terminal window back up and now we can type node in the terminal to go into node and now we're running node at the command line interface node has a common core module called crypto so right here at the command line we can type require and now we can put crypto in here and from there we can add random bytes with camelcase with a capital b the number 64 and then dot to string and we'll say hex and this will give us a random crypto bytes string that we can use as our access token secret so i'll press enter and now i'm going to copy this and we don't need the quotes at all inside of our dot enb now ctrl c to copy and i'll just paste this in here as our access token secret now i can press alt z in visual studio code to get that to wrap so it doesn't go beyond the edge of the screen so that is our full crypto line that we just created there now let's go ahead and create one more i can press the up arrow in the command line just to pull that command back up press enter and it generates another random crypto line here that we can copy and paste right into our dot env file and with that i'm going to press control s to save and close the terminal actually i'm going to open the terminal back up real quick because we didn't exit node we press control c and then it says press control c again so we press it again and now we have exited node at the command line now i'll close the terminal window one other thing we want to do with the dot env file is make sure it has been added to our get ignore file you do not want to send your environment variable values that you're storing in the dot env file or you could just say you do not want to send your env file to github you want to keep this in your dev environment and then when you host somewhere whichever host you have they should have a way to put the environment variables into their hosting service then you can pull those out now we need to go to our controllers folder and open up our auth controller that we've created in the last tutorial and we left a note for ourselves that this is where we want to create the jwts on line 15. before we get started on line 15 let's go ahead and pull in everything we will require today so let's define jwt set that equal to require and then pull in our json web token package after that we need to go ahead and require dot env and then we need dot config after that and after that we need our fs promises because we have not integrated or any other database technology yet so we are still working with simple files and json values so we need this fs promises and we'll set that equal to the fs module and after that we need dot promises and then finally we need the path module we'll set that equal to path now let's scroll down so we have just a little more room to work on the screen and we're back here and now line 15 turned into line 20 where we're creating our jwts and let's define our access token we use camelcase with a capital t on token and we'll set this equal to jwt dot sign the first thing we need to pass into the jwt is a payload so what we're going to use is our username object you don't want to pass in anything like a password or anything that would otherwise hurt your security because this is available to all if they get a hold of your token so what we want to pass in is just the username i'm going to do this on a separate line and so we'll create this object with username and here above we had a found user and then we can say username now this is coming from up here where we found the user that was logging in after that the second thing we need to create our access token is our secret that we defined in the dot env file so we access this by process dot env dot access token underscore secret and then finally what we need is an options value here and we can say when this token expires and this is camelcase expires in and we're going to make this very short for this tutorial that will allow me to show the token expiring and see what happens but what you might want to do in production would be maybe 5 minutes or 15 minutes some small window of time but 30 seconds might be too short it is all a preference though and with that defined let's go ahead and highlight all of this and then i'll just press shift alt and the down arrow to copy it all down and we'll just make a few changes to go ahead and create our refresh token as well so i'm going to type refresh here instead of access we're once again going to pass in the username but then we need the refresh token secret now a refresh token needs to last much longer than the access token but you do want it to expire at some point and so i'm going to make this one day and i'm going to give a link to the package the json web token package on npm js and there you can see another link and more documentation on the different values you could put in here but one day is what we're going for and then we want it to expire and we want our users to have to log back in you could make an indefinite refresh token but that means if someone gets a hold of it and they're not the correct person they will always have access and you do not want that with both tokens created i'm going to scroll up for a little more room again and we want to save our refresh token in the database which will also allow us to create a logout route in the future that will allow us to invalidate the refresh token when a user logs out so let's start by doing that and once again we're just working with our json files for now and we haven't connected this to an actual database that we will do in future tutorials but of course that lets us modulize these tutorials and then we can attack say or go over to postgres or anything we want to in separate tutorials so for now just the json file and i'm going to define other users we had a found user so now we'll set other users equal to the users db dot users dot filter and now for each person that we have we're going to say person dot username not equal to and now let's have that not equal to i believe it was the user that we came in with the request right here however we also have our found user dot user name and i believe i'd like to use that since we have found it so let's say found user dot username and now that creates an array of the other users that are not the username that is logged in and now let's create a current user we're going to set this current user equal to the found user and then we're also going to add in the refresh token that will be saved with this current user and now let's set our users once again and we can say users db dot set users and in this new array we'll go ahead and add the other users and then we'll add the current user that we just created i really don't know why i'm putting spaces there really don't usually do that in an array and okay let's go ahead and put the semicolon and let's write our new users file this would be await and then fs promises dot write file i'll go down to a separate line i'm going to scroll up once again just to put that in the middle say path dot join we'll pull in the directory name then we need to go up one directory and then we need to go into the model directory and then we need to go ahead and name this users.json as our users file is after that what we want to put in we need to json stringify and pass in usersdb dot users which will write our new users file and so i should have put a little comment here at the top this is saving refresh token with current user which again doing this will allow us to invalidate that refresh token as the current user logs out if they log out before their one day has expired so as a quick review we have created the jwts once we have authorized the login which was with bcrypt in the previous tutorial but now that we authorize the login we create the jwts we have a refresh token that's been saved into the online database and an access token and yet we still need to send both the refresh token and the access token to the user the easy part of this is to just remove what we were sending in our json and instead send the access token we can send that as json and on the front end the front end developer or as a full stack developer if you're developing the back end and the front end you really want to store this access token in memory it's not secure in local storage and any cookie that you can access with a javascript could also be accessed so anything that really that javascript can access where you would store it it's not really that secure so if you store the access token in memory which has a very short life span we only gave it 30 seconds here but like i said maybe you'd give it 15 minutes by keeping that in memory you're not storing it anywhere vulnerable after that the refresh token well what we're going to do i've definitely seen tutorials that also just send it along in the json but that kind of creates a dilemma for the front end developer or as you develop the front end because you do need to store the refresh token we want to send it as a cookie and i know i said a cookie could be vulnerable to javascript but if we set the cookie as http only it is not available to javascript so that's what we want to do so let's say res.cookie and now here we can name the cookie i'll just name it jwt from there we want to pass in our refresh token and after that we want to give options and the first option i'll give a space here http only set that to true and after that we want to set a max age here we go and now i'm going to set this to 24 which would be 24 hours 60 times 60 times 1000 and this is in milliseconds here so what we're really getting is one day because that's what that is equal to as we set the max age of the cookie and i'll go ahead and cap that off here you could set it for longer as well now cookie is always sent with every request but the nice thing about an http only cookie is that it is not available to javascript and while it's not a hundred percent secure it's much more secure than storing your refresh token in local storage or in another cookie that is available to javascript so let's save this and now we know we are sending our refresh cookie that is http only to the user we're also sending the access token oh here we're sending our refresh token is what i meant to say in a cookie that is http only we're also sending the access token as json that the front end developer can grab and we're also storing this same refresh token in a database here that can be cross-referenced when it is sent back to create another access token with our auth controller complete let's now go look at the middleware folder and we need to create a new middleware file here and let's call this verify jwt dot js and we're going to need jwt and dot env once again in this file so i'm back in the auth controller just long enough to copy these two and then go back to the verify jwt dot js and i'll paste in our required packages right at the top after that i'm going to create verify jwt set this equal to a function that has a request response and next as middleware should and now let's define the auth header at the very top and this is going to be equal to request dot headers oh and then we need a bracket not a dot and then authorization and of course we need to check to see if that is actually received so now we can say if no auth header we're going to send a response which we need to return and then just send the status 401 which stands for unauthorized after that i'm going to go ahead and put a console log statement to just go ahead and log the auth header for when we test this we'll be able to see that in the console you'll see a line that looks like this and it will say bearer and there will be a space and then there will be the token after that so we can define our token now and we can set this equal to the auth header and then we can call split on that space that i just described and we'll put the space in here on the split and then we need the token so it wouldn't be in the zero position it's in the one position after that and now we can verify the token with the jwt dot verify and here we'll pass in the token first after the token we'll pull back in our secret and this will be the access token secret because that's what we'll verify with this middleware and after the access token secret there will be a callback that gets an error and then we'll call this you could call it token if you want we'll call it decoded because it will have decoded information from the jwt and now we'll say if we have an error let's go ahead and return and send a status once again this status will be 403 forbidden because at this point we'll know we received a token but something about it wasn't right in other words it may have been tampered with and so this means we have a invalid token so we'll send a 403 instead of a 401 which means you are forbidden from accessing this and then we'll set the user equal to decoded dot username remember we passed in the username to the jwt so now it's been decoded and we can read that and then we'll call next from our middleware and that pretty much wraps up that whole middleware function right there except we need to remember to export it so we'll say module.exports set that equal to verify jwt and save with the middleware now complete we can add it to a route or routes that we want to protect so let's open up routes and api and go to our employees js file that has all of the employee routes in it and we need to import that middleware here so we'll say const verify jwt equals require and now we need to go up out of the api folder up out of the next folder the routes folder and then go to middleware and then choose verify jwt and once we have that we can just put it let's say in our git route if we only wanted it in the get route before we call the controller and so it will go through the middleware first and then go to the employees controller here so let's save this and now let's test this with thunderclient so over here to the left i'll open up thunderclient and we're going to need to log in first so i'll go to our collections and i have an auth collection that i created and i want to go to the auth route i'll click this and now i'm going to click over here again to hide the tree so we can see better and i'm also going to press control and backtick to open our terminal window we haven't started the server yet so that's something else we need so we need to type npm run dev to go ahead and start our server and it's running on port 3500 and so you can see the route we're going to go to is a post route it's localhost 3500 auth that we had previously set up to log in with the password so in the body we're sending wall 1 and password and the password that we had in there previously and this is in the users file that i have if you haven't done this you need to go ahead and either create this in the file or use the register route that we previously created and create a new user and then this will work but we're right now we're going to log in with user walt 1 and this password using this route so i'll go ahead and send and you can see over here on the right the response we get is a 200 and we get this access token this access token will only be good for 30 seconds though so let's see if i'm fast enough to come back here to our collections open the employees api and now let's look at this and i need to go ahead and in auth i need to send a new access token now we can send and we got our employees back but this will expire and notice down here we also got the console log statement i put in here's bear and then the space and then the token so now if i send this again the token should have expired and now we get the 403 forbidden because the access token that we sent was only good for 30 seconds now let's look at the employees.js file again and i will go ahead and click the file tree so we can see our files also we're only applying this verify jwt middleware to the get route right now and this is a good way to do this if you have select routes that you want to protect or verify but not all of them however if you know you want to protect all of the routes in your api there is an easier way to do this so let's go ahead and remove this and we'll pull this out of here as well and i don't think we'll just retype it in the server file because that's where we're headed next so we've removed the verify jwt from the employees js file all together let's go to server js our main file and here we can just pull this middleware in so i'm going to do it right underneath the error handler that we had middleware for so we'll say verify jwt set this equal to require and here we want to go into we don't need to go up at all actually we just want to go into dot slash middleware slash verify jwt and now that we have that we can use this just like we've used other middleware in our file but we probably don't want to use this verified jwt middleware for all the routes probably not the root route that we have here definitely not to register a new user or we'd never be able to register in the first place and not even to auth because they have to visit auth first to get the token but we do want to put it before the employees route so i'll put an extra line there and then right here we'll say use verify jwt and if you remember this works like a waterfall so in this order everything after this line will use the verified jwt middleware so any route we do not want to have verified with the jwt we need to have above this line right here so let's go ahead and save this once again and now we can go back and let's log in again and get another well we close up the api there there we go here's our offline let's log in and get another 30 second access token here we are okay now let's go back to the employees and once again we can just use the get route before it was forbidden because it expired but now let's go to the auth tab here in thunder client select all delete that paste in the new token and submit and we've got our employees list once again but if i continue to submit it will expire as soon as the 30 seconds is up and there is our 403 and just to show that this is on all routes now let's go back to our employees api to the post route for posting an employee here in the body we've got john doe so that looks like we could go ahead and post to the employees for john doe let's see if we can send this and we get unauthorized so our verify jwt middleware is working on all routes okay let's go back to the file tree we can close the terminal once again we can close out of thunderclient for now and let's close up the middleware what we do want is to go back to the controllers and we're going to create a new controller here called refresh token controller.js because we're going to have a refresh token route and before we get started on our refresh token controller because we're going to need it let's go back to the server.js quickly and at the top of the server.js we pulled in the verified jwt we also need to go ahead and define cookie parser the other package that we had required at the beginning of the tutorial and let's require cookie dash parser there we go but we'll define it with cookie parser capital p camel case right here so i can go ahead and copy that now much like where we used the express.json and express.url encoded that we use for form data and of course express.json is for json data we just want to add middleware or cookies right here so we'll say app.use and now we'll pass in cookie parser and we want to call that into action right there and save our server.js file now we're ready to go right back to that refresh token controller and we'll begin by copying the auth controller control c i'll just copy everything and paste it in but we will make some modifications so we need the user's db we will not need bcrypt because we are not doing user password authentication there we do need jwt and dot env but we won't need fs promises or the path in this either so we can remove those dependencies now instead of handle login let's call this handle refresh token and this does not need to be async so we'll just have the request and response here after that we won't be looking for a password but we will be looking for a cookie so let's say const cookies and set this equal to request dot cookies and so we will have a similar if statement here at the beginning but we'll be checking for a couple of things one is to make sure that we have cookies but now let's use optional chaining with a question mark and a dot the optional chaining operator and put jwt after it so we're checking to see if we have cookies and then if we do have the cookies we're also checking to see if there is a jwt property and this is saying of course if these do not exist then we're going to return something here and we're going to return a 401 and we do not need a json message after that so i'll just eliminate that portion of it and save this it looks like i may need to go ahead and press alt z to wrap any lines that exceed the edge of the screen so there we've got a 401 if the cookies do not exist and maybe we have cookies but no jwt either way that gets a 401 which is unauthorized now let's go ahead after we've confirmed that at least and let's log to the console cookies.jw so when we run this you'll be able to see what values we get from that and likewise let's go ahead and define the refresh token now that we've received now that we know it exists within the cookie and we'll set that equal to cookies.jwt and once again we do want to find a user but now we're receiving a refresh token and not a username or password for this so we'll say person and there is a refresh token that should be saved with each user if they have created one and so here we'll just match that to the refresh token that we have now defined here so this would be our found user then if that user exists and once again we can say if we do not find a user let's now send the status forbidden here and i'll just highlight that okay we're not evaluating a password here we are evaluating a jwt though so these lines will change as well so we can get rid of the const match line and instead well we can even get rid of the if match here as well and instead of that we'll type jwt dot verify and now we'll pass in the refresh token that was received now we'll say process dot env dot refresh token secret and then we'll have an anonymous function that once again has error and decoded its callback function and before i type the rest i think i'm just going to get rid of this because it doesn't need to be there at this point either so let's just go ahead and clear it out now and with that cleared out we can finish our function here for the token verification and if we do not have a valid token we can say if we have an error or we can also check the found user dot username because we did have the username encoded in the token so if it's not equal to the decoded dot username in other words maybe it was tampered with again then we can return a response with a send status and say 403 once again otherwise everything is good and we're ready to create a new access token descend because the refresh token has verified so we'll set this access token equal to jwt dot sign and then inside of the access token will once again have a username and this username will be the dot username because it should be the same username that was verified before and after that we can say process dot env dot access token secret if we can find that access token secret there we go and now we need to put an expires in once again let's put expires in and let's set this to 30 seconds as well however remember you might want to set this longer in your production app this is just for the demonstration of this tutorial so i can show it expire and then of course after we've created this access token we need to go ahead and send the access token so we'll send this json down and it'll say access token and once we've created that much all we need to do is export it so now instead of handle login we once again have handle i believe it was refresh token yep and we should be able to save that and i don't know why i put a semicolon there it's not really needed so once we have saved that we should be good to go with our refresh token controller and we can create the refresh token route okay in our routes file now we can open that up and we can look at our auth route i'll just highlight all and copy and we'll create a new route called refresh dot js i'll go ahead and paste that in but instead of the auth controller we need the refresh token controller so we'll spell all of that out and instead of handle login we need handle refresh token and before we're finished with our refresh route let's change the http method from post to git as well so this is now a get route for refresh okay now we need to insert this route into the server along with the other routes so we'll go to the server.js file and you can see we've got root register auth and of course we want this to also be before we verify the jwt because the refresh route actually issues a new access token and that's what verified jwt verifies so what we want to do now is just copy a line down i pressed shift alt and the down arrow in windows to do that and i'm going to change off to refresh and now the refresh endpoint will receive the cookie that has the refresh token and then that will issue a new access token once the access token has expired so we'll save this and we should be ready to try it out so i need to open up the terminal window again and we can see our server is running on port 3500 now let's open up thunder client and we're ready to check out the refresh route but first we need to go to the auth route and here it looks like the off path i'll hide the tree over there and so now we're going to localhost 3500 auth we're once again going to authorize walt here with his password so let's send this and we got a new access token but what we also get from our auth route is a cookie and this cookie has a refresh token and here's the jwt name for the cookie and here's the refresh token now a cookie is sent every time we don't need to paste it in in an auth area like we did with our access token the jwt cookie is sent every time we make a request to the domain that it's associated with so we'll go back over here to thunder client we'll come down to our refresh route and i'll hide that tree now we're going to localhost 3500 refresh and you can see we don't need to post anything in the body we don't need to post anything in the auth because we have the cookie that we're going to send so let's send this cookie and now we got a new access token and you can see we also logged our information as we set it up in our path to log the refresh token that we received from the cookie down here so we've got a new access token and our refresh token is used to do that so now every time we hit this refresh route and we send our cookie with the refresh token we should get a new access token and you can see every time we're getting a different access token over there so that is what refreshes our access and that's why it's called a refresh token and so now we have a new limited time access token to use again in production you might want to set it to 5 minutes or 15 minutes instead of 30 seconds or something like that but then our refresh token has the longer duration that we store in an http only cookie and that's because we don't want it to be available via javascript so it increases our security nothing's 100 perfect but it's the best way to go i believe for that so we're sending the http only cookie that has the refresh token and that issues us the new access token now that we've finished testing the refresh route one extra measure of security or one extra step we can take is to offer a log out route and with the log out route we could actually then delete the refresh token and not let it last for the full duration and that just gives our users the opportunity to log out and of course delete any existing tokens and of course the access token should also be erased on the front end when the login or log out link or button is clicked as well of course we're working on the back end so we won't be doing that today but let's go ahead and add this new controller for the logout so we'll have logout controller.js and now that we have that let's go ahead and copy our refresh token controller and we will just make some modifications to handle the logout because we need the same requirements at the top we've pulling in the users so we can check our database we've got the jwt requirement and we've also got dot env i'm going to close the terminal window and now i said we had the same requirements we don't quite have the same requirements i'm sorry we don't need the jwt or the dot emv what we do need is the fs promises that goes with accessing our database because we're just using a json file so we'll require fs dot promises and we once again need path so we'll require the path and again these are only to access the current json file we're using for our users database this is a mock database this will be replaced of course with or postgres or whichever database technology we work on in a tutorial in the future so we've got this down for the requirements and let's move forward with the log out so instead of handle refresh token now we're going to handle the logout and we'll have a request and response and then let's just add a note here for the front end if you're doing full stack development like on client also delete the access token we can't do that here on the back end you need to do that in the memory of the client application just zero it out or set it to blank or whatever when that log out button is clicked what we can do though is take care of the refresh token so here once again we need to get the cookies as they come in now let's erase our logs here we were doing for the cookies and the cookies jwt before if you wanted to see those in the console and we'll once again verify that we have got cookies and then that we also have a jwt in the cookies and if we don't well that's okay because we were just going to erase it anyway so let's send a status 204 that means it's successful and there's essentially no content to send back that's what that status is so you've had a successful request and we're not sending any content and this needs to be send status instead of just status there we go response.send status got that now let's go ahead and define our refresh token and we'll do that in the same way setting it equal to cookies.jwt now let's see if we have that refresh token in the database so that's what we're checking here is refresh token in db so once again we try to find a user that has this token so setting this equal to the refresh token just as we did in the previous refresh token controller is exactly what we need and if we don't have a found user at this point we can go ahead and clear the cookie so we're going to do something just a little different here and it won't be forbidden either so we'll get rid of that and let's go ahead and look at how we clear the cookie first so if we don't have a found user but we did have a cookie to get to this point we can just go ahead and erase the cookie that was sent and that's going to be with response dot clear cookie and then inside there we'll look for the jwt cookie and then you have to pass in the same options that it was set with so once again we'll say http only set that to true and that should be all we need to do there except for sending the proper status so once again we're going to return and send the status not a 403 but of 204 which once again means this was successful but no content okay i'm going to scroll up just a little bit and now we can pretty much erase everything here and we're going to create some new content below because if we've reached this point that means we did find the same refresh token in the database so now we need to delete the refresh token in the database right here and we're using file system of course for that instead of or postgres at this point but we will change that in the future right now let's define other users which would be all of the other users that are not the user that we found and set that equal to users db dot users dot filter and we'll just filter this out we'll pass in a person and now the person dot refresh token is not equal to our found user dot refresh token as well there we go okay so i'm going to press alt z to wrap that line of code so we can see all of it and that's all the other users so now our current user [Music] is going to be equal to our found user and then we're going to set the refresh token to blank so we'll leave the refresh token property but now we're just erasing it from the user and now we can update our users db with our set users and we'll go ahead and pass in our other users and then we'll pass in our found user oh and i'm sorry that's not found user that should be the current user that we just defined there we go so found user was before we erased the fresh token now the current user has the updated refresh token that is zeroed out or blank if you will now let's just write this to the file so we'll await fs promises dot write file and now on a separate line here i'm going to say path dot join pass in the directory name after that we'll need to come up one folder and then we'll say in the model folder and then we'll name the users.json file okay then we need to go ahead and use json.stringify and write in the usersdb dot users and that should update our users file and so after that we need to go ahead and delete the cookie which we saw how to do before as well so we use clear cookie and we reference a jwt and we need to pass in the same options as well http only set to true now i will add in production both when we send the cookie and when we delete the cookie you also want to add the flag secure true and that will make it only serve so it only serves on https we're just using a dev server that uses http but you want a secure connection with https so we don't add this in development but we would in production the option of secure and set that to true okay and after that we want to send our status again which once again is a 204 all as well but we have no content to send back and after that we need to change our export from handle refresh token to handle logout and save okay with the controller complete let's create our route file and we can just go here to the refresh file we created select all and copy and now i'm going to create a new file in the routes called logout.js and now i'll just paste everything in from the refresh route and we'll change that so we need express we need the router but instead of refresh token controller we'll select all three of those with control d and i'll just type log out and this will be a get route again and the export to router is correct but we do not have handle refresh token here we also have handle logout as the function for the controller and with that complete now we can go to the server and add that route as well we won't need to verify a jwt to log out so i will just once again shift alt and the down arrow to copy a line down and i'll change refresh to log out and save now let's open a terminal window again oh and we've got an error so let's see what our error is here in node a weight is only valid in an async function ah we did not do that in our controller let's go back to the logout controller and we used await when we used fs promises so let's make the handle logout an async function and save and let's see if node restarts and yes the server is running on 3500 all looks good there so now we can go to thunder client and we'll hit our auth route to make sure everything is logged in we're going to log in our user walt one and we've got an access token and we've got a cookie so now let's go back to thunder client and i have a log out route that is a get route as well so we have get localhost 3500 log out you don't need to pass anything in the body or the auth when we log out but let's go ahead and do that and we hit log out and everything seems to be fine we can see our cookie has now been erased so now if we go to any of the other routes like refresh that would use our refresh token cookie we don't have a cookie to refresh with so now let's try localhost 3500 refresh and it's a git route and see what we get well we can see in the console we logged or attempted to log a cookie but it didn't exist here and we're not getting a response so let's look at that i can cancel this here in thunder client let's go ahead and look at our refresh controller and see what's going on there so refresh token controller and here is where we're logging the cookies we can get rid of these lines actually now so we don't need those but let's see if we can figure out what is going on and yes here's the error i said response dot status 401 it needs to be response dot send status 401 just like we had down here with send status 403 so if i've typoed any of those others throughout this code it looks like i had send status everywhere else but just in case you see that to actually send the status it needs to be send status instead of just status status is chainable if we're sending a response after that but now this should work so let's once again go back to thunderclient and we'll hit our refresh token route although we don't have a cookie and we'll see what happens ah we immediately got our 401 unauthorized because now it sends the status so that's correct let's go back and log in again with our auth route localhost 3500 auth send that we have an access token we have a cookie and everything seems good so all routes are working as expected okay i thought i was at the end of the tutorial but after playing around with some front end code there were a few things i thought i needed to go ahead and clear up or include one is here this is front end code by the way this is not what we were working on in express if you use fetch to access what we had set up say our auth route well you're going to need to include a credentials option again on the front end to have fetch send the cookie now if you use axios i believe there is a with credentials flag that needs to be set as well and we could do that in a future tutorial but right now just looking at credentials for use with fetch so you have to set that to include but that sets off a chain of events so even though this is required here to send the cookie then what happens is i'll pull up chrome here we get a course error and you will be blocked by cores because the value of access control allow credentials in the header of the response is blank and it needs to be set to true so cores will block this if you don't have that set before you reach the course check now what is happening is a pre-flight options check it's an options http method request but then you also need to have the same access control allow credentials set to true when you do send the cookie back as well because that's what's expected with fetch so there's a way to fix that of course and now let's look at some of our back end code and let's start in the config folder and i went to coors options first and we did have what was called a white list in here which that's traditionally what it's called and i've seen that in articles as well i don't like the name so much either just maybe in modern day it sounds a little racist or something so we've switched that to allowed origins which is what it is it's a list of allowed origins and i put it in its own file because we're going to use it in middleware also but i only want to update it in one place so we have our allowed origins formerly called the white list in the tutorial and we're exporting allowed origins so we import that into our cores options and use it here but then we also create middleware called credentials and now this credentials middleware of course has a request response and next and we import allowed origins here also all we're really doing is to say if the origin that is sending the request is in our allowed origins list so it's just a little bit of extra security if that is the case go ahead and set this header on the response because that's what cores is looking for access control allow credentials and we set that to true so now that we have the middleware created we go to the server file and we pull that middleware in and then you want to use the middleware we're using credentials right here and of course i'm importing it right up here above you want to use that before cores because of course sees that that response header is not set it throws that error so that will fix that issue and i would hope that would be the end of the issues but no there was one other issue and let's take a look at what that was i'm going to open chrome again and i had to do a screen capture now i was in the dev tools in the network tab and i was looking at the auth request and then i could pull up the cookie and then there was this little triangle and the reason i had to do this screen capture is because i had to mouse over the triangle for this message to pop up in this very small print i'm zoomed in quite a bit already just to see this and it said the set cookie header didn't specify a same site attribute so that defaulted to same site equals lacks and then it was blocked because it came from a cross site response which means our front end application was not on the same domain as our back end api and that's often the case so there's nothing wrong with that it's just that's why they blocked it says the set cookie had to have been set with same site equals none to enable cross site usage so that tells us something else another option we need to go and put in our set cookie response so let's look back at the back end code here and then where did we set the cookies well let's look at the controllers that's where the cookies were being set and i believe the auth controller is what sets the cookie specifically and so not only do we have http only true but then we went ahead and set same site to none as they request here and then after you do that they give you another message in the same spot and that says secure must be set to true now previously i didn't have secure set to true there because i thought you could only use it with https even during development but no it's working in the dev server even though we're just using http then after that i went ahead i've got the code wrapping by the way because down here on the next line you still have the max age option now when you delete a cookie you need to set the same options however and i'll put a link to the documentation in the description below however max age actually does not need to be set or in there when you delete the cookie it's one of only a couple like the expiration and max age are the only two options that don't need to be identical when you delete the cookie so when we go to the log out controller and we have our res.clear cookie we need to have http only same site and secure all set as before but max age does not need to be in here and we've got that in here a couple of times in the log out controller as well so we did make those changes but after you do that everything should work as intended so it's just a couple of things i discovered as i was working with this front end code and of course it is good to test it out with actual code and a browser besides using an extension like thunder client because thunder client showed everything was working as we expected it to but of course we ran into a few issues with chrome and now i've walked you through how to fix those as well since creating the last tutorial i realized there's a lot of confusion concerning the concepts of authentication and authorization they're often used interchangeably or simply abbreviated as off but they are not the same things authentication refers to the process of verifying who someone is authorization is the process of verifying what specific resources a user has access to when we log in with the username and password we are verifying who we are and that is considered to be authentication after logging in our express api issues users jwt tokens jwt stands for json web tokens while it's true that the tokens confirm the authentication process has already taken place these tokens also allow access to our api endpoints which provide our api data this is authorization a hint towards this fact is that a jwt token uses the authorization header today we will expand the authorization process by adding user roles with specific permissions to our api authorization process we're going to start with the code repository from the last tutorial but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link i've provided in the description below we're going to start by going to the config folder in the file tree and creating a new file and we'll call this file roles underscore list dot js in the roles list we're going to create the user roles now this could be in a data table in a database this is just how we're going to do this and you'll find that user permissions can be constructed in an assortment of ways and we're going to apply a fairly simple structure today with three different user roles so we'll start out with our roles list constant and we're going to set this equal to an object and the keys will actually be the names of the roles so we'll have admin and then we'll have a code that identifies the role and then after that let's create an editor role and we'll call this 1984 and then let's have just a user role and we'll give that 2001. okay now that we've created our roles list object all we need to do here is module.exports and set that equal to roles underscore list okay we've saved that now we're ready to go ahead and modify our users model that we have in the users.json file and you might find that once it has been written by the read and write file process that we use in node we're using this user jsons file it might all be in one line but i believe if we go ahead and just put a return and edit and then save in visual studio code it should go ahead and format that file for you so it's a little easier to read now this is what we had after the last tutorial we have a username walt1 and a username walt2 they all have their own passwords and of course we're tracking the refresh tokens i'm going to copy in the file i've created it adds one more user and so you can copy this file out of the completed source code that i'm going to link to there's a starter source code link and then a completed source code link or you can go ahead and use the register route create your own new user and you can see i've added dave one as well as our walt one and walt ii dave one just has the role of user while walt 2 has the roles of user and editor and walt 1 is not only a user but also an editor and admin so you can see we're going to support multiple roles i'll go ahead and save this file once again you can copy it from the completed source code or just create your own third user if you want to and we'll just edit these manually now there could be a admin area for whatever service you were creating and that is where these additional roles could be created but what we will do is just ensure when everyone registers they're given the user role and then of course later on you'd think an admin that was in charge could add the additional roles if those roles were to be granted to other users so now we can collapse the model folder and the config folder but let's look inside the controller folder and let's look at that register controller that we have what we want to do is add that role of user with the 2001 code when any user registers you can see we're creating our new user right here on line 19 and we have the username and the hashed password so let's just go ahead and add this extra roll i'll break this out on separate lines and that way we can see the new part that we add and what we want to do is just in between username and password add roles let's keep that lowercase and after that let's put this in an object so then we have user and then we have the code 2001 and then remember to put a comma after roles so it goes before the password and save now let's go to the auth controller and when we authorize and create the access token we will want to send this information in the access token so we're going to change our payload for the jwts now first when we know we have a match and we have verified our user so everything is good we want to go ahead and grab the roles that we put in our users json file so let's go ahead and define roles and set this equal to object dot values and then we can pass in the found user that we have above and we want found user dot roles and so now we'll get those values inside of roles and now let's change our access token payload just a little bit since we're not just going to send the username let's create a new namespace here with user info and then this will be an object and inside this object we'll have username let me go ahead and add the closing curly brace for the object here so we'll have the username but then oh we don't need that closing curly brace but then we also want to add some more information here inside of the user info object and the next one will be roles with quote and we'll just pass the rolls that we've created it looks like i actually did need that extra curly brace or at least we need to indent here and then we're going to need to close out our payload that looks correct i believe and if you want to break this onto another line you can do that as well go ahead and save and there we go it gets formatted a little bit better already so we're using this user info as a different name space and that's good because this is considered to be a private jwt claim because there are some res reserved abbreviations and words for public jwt claims and you can find out more about that at jwt dot io i believe i'll confirm that and leave a link in the description below so you can check out more information on the jwt claims if you're interested now there is no reason to send the roles in the refresh token and ideally the access token will only be stored in memory on the front end but we don't have control over that so when we do send the roles we're just sending the codes and not actually the word admin or editor or anything like that so we just are kind of hiding what each one is by using codes but at the same time ideally that access token would only be stored in memory anyway but there is no need whatsoever to send the roles in the refresh token refresh token is only there to verify that you can get a new access token okay now speaking of the refresh token we need to go to the refresh token controller and add some of the same code because that refresh token does issue a new access token so right underneath where we have verified the or we've actually decoded the refresh token here and we have the decoded and now we have no error and everything is good so we want to come down to this line right before we create the token and here once again let's define roles and set equal to object dot values and we'll pass in our found user once again and the roles that are associated with that user and now we can use the name new namespace as well so we'll use user info again and then we'll create an object and inside this object we'll have the username which is the decoded username but then we'll also want to put the roles once again so now we'll have roles and here we can just pass in roles once again i need a comma it looks like and now let's save and it will format a little bit better and that looks correct so we have user info with username and roles now that we've updated our tokens to include the roles our access token specifically we're ready to go to middleware because we're going to have to create some new middleware to verify those roles but first let's look at the verified jwt file that we already have i'd like to make a couple of quick updates one is when we define the auth header this works and especially when we have control of the front end as well and we know we would define authorization with a lower case a however it can also come in with an upper case so instead of this let's go ahead and just say dot authorization which is essentially the same thing that we had but then we can also say or and then we could have request dot headers dot authorization with a capital a as well just in case it comes in with a capital now we know we're going to grab it either way after that let's go ahead and change our if auth header as well and let's look for an optional chaining method here so we say if we have or if we do not have the auth header actually are saying and also starts with and here we want to have bearer and this is supposed to be a capital b by the standard so we don't really have to look for lowercase and uppercase like we were here so we're verifying that first of all if we do have an off header or if it starts with this and we're actually looking to say if we don't have an auth header and then this optional chaining says okay well even if we do have an auth header if it doesn't start with bearer with a capital b and then the space after bear then we're going to return a 401 because it is not a correctly formed authorization header that starts with bearer and then the token as it's supposed to it looks like we left in a console log from the last tutorial let's go ahead and take that out where we were just viewing the bearer token in the console and now after we decode this token when we're verifying the jwt we also want to set the roles here not just the user on the request so let's have request dot roles and we'll set this equal to decoded and now we've got a different namespace so it's dot user info dot roles and we need to make the same change up here when we get the username because now it's decoded dot user info dot username and now we've got the correct namespace for both and we can save our verify jwt middleware and now it's time to create our new middleware i'm going to collapse the open editors so we have a little more room and in the same middleware folder let's create a new file and let's call this verify roles.js inside of verify roles we're going to create middleware named verify roles and it's going to accept a lot of parameters if we want it to it's however many roles we want to pass in and the way we do that is with the rest operator it looks just like the spread operator but it lets us pass in as many parameters as we wish and we're just going to call them allowed roles now from there we need to go ahead and have a middleware function and you know that takes a request response and next so what we need to do and this allows us to pass in the allowed roles by having this on the outside but we need to return a middleware function essentially an anonymous function here with request response and next and now inside of this function we'll have everything that our middleware would do so the first thing we need to do is say if we do not have a request which we should because our verified jwt will come before this but let's go ahead and do that just to be thorough and then let's use optional chaining to say okay even if we do have a request it needs to have roles or this should not be valid and if it's not valid we're just going to return a response and send the status 401 which is unauthorized now we need to define a roles array let's keep that lowercase camelcase actually rolls array and set this equal to the allowed roles that were passed in now we're spreading those into a new array here now that we have this let's go ahead and log this to the console these will be the different roles that we're passing in of course there will be the codes associated with the roles but let's go ahead and log roles array so when we go ahead and test this we can see everything that we expect to and we'll be comparing this to the request dot roles that we just set inside of the verified jwt that will be executed as middleware before the verifies roles middleware okay so we'll log both of those just so we can see what's going on but now we know we have an array of user roles that are coming from the jwt and then we have the roles that are passed in that will be allowed and that's what we're going to compare so we're comparing arrays and i'm going to define just a result here and let's set this equal to request dot dot map which map creates a new array and we'll have a role and for each role essentially we'll compare to the roles array and we'll see if the roles array includes the role that we're passing in and if it does it will return true that's what includes does and if not it will return false it's a boolean so we'll have a new array and we'll have a true or false for every thing that was in the request role so if we had three different roles here we'll have possibly true true true or true false true who knows for sure but that's what we'll have so we need to filter this array and all we need is one true to know that the role can access the route that we're verifying so what we want to do then is chain find and we can just say for each value the true and false in the new array that was mapped each value will check the value to see if it's equal to true and if it is it will return if it finds a match it will return the very first one it finds or if it finds no matches then we won't have a result and so that's how this works i'm using two higher order functions here essentially so we're mapping over the roles that are sent from the jwt and they're assigned in the verified jwt to request roles and we're mapping those comparing them getting true and false results back to the roles array that will be passed into this route so we'll pass in however many roles we want to this array could possibly only have one role or it might have three or four or however many we're checking for or want to allow to this route so once we compare those and get all the true false results we're just using find to say hey find the first true and if there is any truths it will be good and if there's not it won't and that's what we'll do next so we'll just say if there's no result essentially we did not find a true result we're going to return and then we'll say res send status and again we'll send a 401 unauthorized otherwise we'll just call next because everything's good and we're ready to move on and we're going to let the route be accessed so let's save our middleware and we'll know when it runs we'll see the arrays that we're comparing in the console and before i forget we also need to add module dot exports and set that equal to verify roles and save now let's collapse the middleware folder and open up the routes folder and then the api folder and let's go to our employees.js that has the different routes get post put and delete we have a couple of imports to make here so let's go ahead and define our roles list and set this equal to require and now we need to go up and up again and then we'll look in the config folder and then we'll find our roles list and after that we need to go ahead and define our verify roles middleware set this equal to up a folder up another folder middleware and now we're going to verify roles and i'll save just because i've completed the imports but now we need to add this to the different routes now let's just leave the get route open because any one could access that or if we wanted to put verify roles and at least verify their user but they already have to have the jwt because we required that ahead of time so they'll have to have the jwt to access the git route so kind of the user is the default but after that in the post route let's put in verify roles and now we can pass in the different roles list values that we want to let access this route so we'll type roles underscore list and now dot admin will work remember this is the key and then the code is the value so admin is the key and then we could also put in roles underscore list dot editor and that makes sense because you could have an editor that could post a new value as well okay then i'm going to copy the verify roles that we just added here and it's like maybe i'll put a space here and then input i'll do the same thing and add the space but now in delete let's say only an admin can delete anything from our database so we'll save that which gives it just a little bit of a change so now everyone can access the get route but the post route should be limited to any user that's an admin or an editor the same for the put route but then the delete route could only be used by an admin i think we're ready to test this out now so let's go ahead and open a new terminal window you can do that from the terminal menu or i'll just use control and backtick i'm on windows and i'll type npn run dev to get our dev server up and running with our api and then we'll test this out with thunder client okay i'm going to drag the terminal window up just a little give it some more room so we can see the console log notices that we get and from there i'm going to click on thunder client here on the left if you don't have thunder client installed you can get it through the extension over here and then just search for under client and there you see it and now that you have it or once you have it you'll be able to click on it over here on the left circle with the lightning bolt and you can create collections and of course we've done this in some previous tutorials if you have followed along in the series i've got an auth collection here and the very first thing we'll need to do is authenticate a user let's look at which user we're going to authenticate first let's just do dave one remember this user only has the user permissions it does not have an editor or an admin permission so i'll send and i get the access token i'll copy this access token and now when i go to the employees api and go to get employees i'll go to auth here paste in the new access token and send and everything is good but if i do this for post if i'm in time within the 30 seconds it was given and send i got a 401 unauthorized so that means our verify rolls is working as we look down here we've got the two different arrays logged to the console too so this is the array that has the roles that we were looking for that we passed in 5150 is the admin 1984 is the editor but you can see our user only had role 2001 which is just a user okay now let's go back to my auth collection here and the auth route and let's change who we're getting a token for so now this will be walt 2 he is an editor and also a user but he is not an admin so we can send this we get a new token i'll copy the token and now we can go back to the employees api and we can post a new employee or we should be able to we'll put in the new token here and send and yes we posted john doe so he's now number three has the id of three in the employees list but if we go to the delete route and go to auth i'll post in the same token and attempt to delete and oh we're out of time we got forbidden so let me go ahead and try to re-verify here we once again got walt 2 we get a new token and get that new token once again i didn't copy it right the first time there we go back to employees now we'll attempt to delete i'll pass in the auth token and send and we got a 401 unauthorized and that is because the role did not verify now you can see you had to have the 5150 code which is admin that was passed into the route but walt 2 only had the 2001 and the 1984 code in his roles list okay once again let's go back to the auth route now and we will change to where we are authorizing walt one walt one should be an admin as well as a user and an editor and so we'll send that get a new token and now we can go back to our employees delete route that was just denied to walt to paste in this new token and attempt to send the delete request and employee id 3 is not found that's because nodemon restarted i believe and of course employee id 3 isn't in there so let me go ahead and request another token and we'll see if we can create id3 again quickly and then delete it on the same so here's our new token for our admin user copy that go to the employees post route paste in the auth and created now let's go to delete paste in the new auth and we deleted with an okay so i just had to be quick enough to beat the 30 seconds with that token but here you can see the user our walt one user had 2001 1984 and 5150 in his roles and the api route needed the 5150 so when it matched everything was good hey just a quick note on testing with thunder client and i want to point this out in the controllers and then under the auth controller but when you're testing with thunder client it honors the cookie setting for secure true or not so if we were to set a cookie and then use the refresh token here you would need to remove this or the cookie would not work with thunder client however this is required as i noted in a previous tutorial when working with chrome so just a note if you're testing the refresh endpoint with a refresh cookie you'll have to comment this part out or at least take it out for testing purposes with thunder client but then when you work with chrome and in production you both want that secure true back in here when you create that refresh token that is saved in a cookie we did not use that today and the refresh token does not store any information about the user roles and it shouldn't however just wanted to note that for you in case you were testing out that refresh token with thunder client so there you have it we created our verify roles middleware and you can see both of those that we've been logging to the console i'll go ahead and delete those now before i commit it to github and get the console logs out of there there's our verify roles middleware and you of course saw how we applied it to the routes in our api for our employees and you can just pass in the different roles that you want to let access that given route mongodb is the m in the mern stack it represents the database in the stack the front end application of the mirn stack is handled by react along with nodejs and express mongodb completes the backend rest api traditional sql databases are built in a relational structure related tables reference each other with joins as data is queried these relational tables also normalize the data that means data is not duplicated in the tables that's the dry principle which stands for don't repeat yourself and that's applied to the structure however with no sql databases like mongodb you can throw all of that out mongodb stores data in collections the individual records in the collections are called documents the documents have a key value structure and look a lot like json a collection holds all of the data about a user for example instead of breaking it into related tables and likewise duplicating and distributing the data where deemed necessary in a nosql structure is permitted so why choose nosql databases and what are the advantages of using mongodb performance is key the speed at which a collection is queried is very fast flexibility it's very easy to make structural changes like adding a new field without wreaking havoc in your total structure it is much like adding a new property to an object scalability nosql can support large databases with high request rates at a very low latency and finally usability as you'll see today we can get up and running with mongodb in the cloud very fast let's get started by going to mongodb.com okay we're at mongodb.com and i already have an account so i'm going to choose sign in if you don't have an account you'll want to sign up for a free account so you can just click try free i'm going to click sign in and then it will take me to a page that probably uses my google id or allows me to log in with an email address yes there it is so you get those options i'm going to log in with my google email address or my google account and then we'll meet back up after you have your account or you've signed into your account okay i'm signed into my account and i'm on the projects page where i can create a new project and you see i already have one project here now if you're not on this page once you're signed in just click the little leaf in the top left and it says view the organization home because that's where this is so once you're there you'll want to create a new project and now you want to name the project i'm just going to name this one tuts short for tutorial and click next and then it asks you to go ahead and set permissions or members and it'll probably assign that to your default account to start out with as you can see i have project owner right here so i'm going to click create project with the project created you can see i now have tuts up here above database deployments we need to build a database and of course it gives you the big shiny button right in the middle to do so so please click that and then it gives you choices and we're just going to go with free today if you want to get one that you pay for that's fine i'm going to choose free over here on the right and then it will say create a shared cluster and right now i'm just going to keep all the defaults so free shared it has aws it has one of the usa regions for me because i'm in the u.s you may want to pick a different one if you're not and maybe it already defaults to something close to you and then it just has these other default settings and i'm going to go with all of that even the default name here cluster 0 and click create cluster at the bottom now it says new clusters take between 1 to 3 minutes to provision so i'll come back when this is finished my cluster 0 has now been created and we're given this screen so what we want to do is click browse collections we don't have any collections yet so we get this and it says load a sample data set or add my own data we're going to choose add my own data with that it asks for a database name and a collection name so let's just call this company db and then we can call the collection name let's go with employees and i'll just keep that all lowercase companydb is capital company and capitaldb at the end and i'll click create and with that has created our companydb database and our empty employees collection right here what we should do now is concern ourselves with database access so let's create a user that can access this new collection and database that we have so create a database user we click the big button that says add new database user and then it gives us password certificate and all of that we'll just stick with password and it put in some old information for me let's put in something different here let me go with tut once again and then for a password i'm just going to and we'll go ahead and show whatever the password is i'll go with testing one two three kind of like a mic check okay so we've got tut testing two testing123 i think we'll keep all of the default options here and we want the read and write to any database and of course i'll come back later and delete this user but for now we'll use it for the tutorial and we'll click add user and once we have the user we need to go back to our cluster so let's click tuts and that takes us back to our cluster and it says we are deploying your changes current action configuring mongodb so i'll give this just a second and then we're going to click connect with the configuration now complete let's go ahead and click the connect button it tells us we need to set up some security this part is required and what we're going to do is allow access from anywhere we don't really know where we're going to host our back end yet so this is good for development right now until we actually know what i p address we had so let's just add in the zeros and that means it's good from anywhere we already created a user so now let's click choose a connection method and we're going to connect our application this gives us a connection string and this is what we want notice it's already put in the tut user i created now i'm going to have to put in the password including getting rid of the less than and greater than around the password and then also i need to replace my first database with the companydb which was the name we gave the database so i'm going to copy this and we're ready to close out of this now and open up visual studio code we're going to start with the code repository from the last tutorial in the nodejs and express and now mongodb series but if you don't have it you should be able to easily follow along without it or you can download or clone the starter source code from the link that i'm providing in the description below so let's get started by going to our dot env file and inside the dot env file it looks like i need to go to the end of the line and hit return so we have another line i'm going to create a database underscore uri and set it equal to our connection string but now we just need to replace a few things in the connection string and i'm going to press alt z here i'm using windows and it will wrap the code in visual studio code it may be different for you on mac or linux if you have those okay so we're replacing the password and if you remember i put in testing lowercase one two three and then instead of my first database we named the database company db now we can save this file because we're using the process.env to pull this value out when we need it to connect and speaking of dot e and v we actually put it in about three different files before and really we could have just put it at the beginning of the project it's not like when we require other things like the jwt here that need to go in individual files as they're needed this can just go at the beginning of the server.js so i'm going to pull it out of our middleware verify dot jwt.js file and save that and i believe it's in a couple of controllers that we can remove it from as well but in the server.js file i'm going to put it at the very top you just want it in there as soon as you can get it and we'll save it and now i believe let's check these controllers real quick is it in the auth controller yes it is we can remove that and it's in one other controller if i remember right not the logout controller see if it's the refresh controller there it is and we can remove it from that as well and i think that will take care of it so let's close out of the controllers it didn't save the auth controller need to do that too okay close out of those and we're going to do some work here in the server well really before we do anything in the server we need to go to package json because we're going to install mongoose and i'm going to press control and the back tick you can also go to the terminal window or menu to open a new terminal window and here we need to install the mongoose package so it's npm i mongoose and return now mongoose.js is a library that makes working with much easier kind of like you could consider react makes working with javascript easier than vanilla javascript it's just a helpful library so let's take a look at their page real quick it's mon goose there we go js.com we bring up that page and you can see it says an elegant mongodb object modeling for node.js perfect exactly what we need and it has some great documentation as well so we can refer to this as we go today we'll be working with a connection let's go back to vs code and see if our package installed it looks like it has so let's check our dependencies and we see mongoose listed right here on line 20 so we are ready to begin working with mongoose so now let's go to the server.js file and underneath credentials let's go ahead and require mongoose so we define const mongoose and set it equal to require and then we just bring in mongoose and save now after that we need to go ahead and create a connection configuration so as you might guess we're going to do that in our config folder that we have up here so i'll highlight that and click create new file and i'm going to call this lowercase db and then uppercase con so it's camelcase really db con dot js now let's start this file by requiring mongoose as well so we'll once again bring in mongoose and require mongoose and now we need to create a function that we're going to export and let's call it connect db and set this equal to an async function mongoose is async let's go try and after try we'll have our catch with an error block here and we'll just console.error and pass in the air and then up above we need to go ahead and try to connect a mongoose so how we'll do that is a weight we've already got a sink above and then we use mongoose and we choose connect and from there we need to bring in that db uri that we defined back in our dot env so we can just refer to process dot env dot database underscore uri and then there is an object and what we need to do is pass in a couple of options that will just prevent warnings that we would get from mongodb otherwise one is use unified if i spelled that right topology and we set that to true and the other one is use new url parser and we'll set that to true as well and then we should be pretty much finished except we once again need to do module.exports as we have many times before four functions we've created and exported and it is connect db and we can save the file with our function created let's go back to server.js now and we need to import that so say const connect db is going to equal require and then we need to go into config and from there we need to pull in db con and save and now let's go ahead and connect to the db the very first thing if it fails we don't want to listen for any other connections anyway so this is connect to mongodb and all we do is call connect db right here and it's ready to connect however there is one issue to address here so let's scroll all the way down to where our app listens for requests now we don't want to listen for requests if we don't connect and so if our connection fails for whatever reason we need to avoid doing this and we can do that let's go back to the documentation for mongoose and where we had connections here in the documentation we also have connection events and let's look we can listen for the connected event and there's also the open event which is equivalent to connected so let's go back to our code and use that and we can do that with mongoose which is why we required it for this file in particular and we'll have mongoose dot connection and then we want wants instead of on because we'll just listen for this event one time and we'll listen for the open event it's a little shorter to type than connected and now we'll have an anonymous function and inside this we can console log first and inside there we'll just say connected to mongodb and after we've connected to mongodb let's just go ahead and cut and paste in our app listen and we'll put it right there and now we're only going to listen for requests if we have successfully connected because that is when the open event will be emitted by the connection and so then our console will let us know we've connected to mongodb and we're listening for requests on whatever port and of course here in development we are defaulting to port 3500 as set at the top okay all of that said i've left the terminal window open let's go ahead and type npm run dev and i'll drag it up so we have a little more room and let's see if we connect and we're connected to mongodb and the server is running on port 3500. okay in the next tutorial we'll create schemas and data models with mongoose and relate that back to our mongodb collections in the previous tutorial we went over what mongodb is and we used the mongoose js library to connect our app to mongodb today we're going to create mongoose schemas and data models that will allow us to perform crud operations on our mongodb data collections we're going to start with the code repository from the last tutorial but if you don't have it you can download or clone the starter source code from the link i've provided in the description below let's get started today at mongoosejs.com and from there we're going to click read the docs and it instantly takes us to the schemas in the docs and that is because as you see on the page all highlighted it says everything in mongoose starts with a schema each schema maps to a mongodb collection and defines the shape of the documents within that collection so you can see why they're very important and here you see an example schema they have a blog schema and they're declaring data types for the different fields inside of the documents that will be created with the data model and they also have some options here such as date they're not just saying it's a string for the body they're also saying it's going to be a date they can have default data and there's other options available as well and if we scroll down just a little bit further you can see the permitted schema types and here we have string number date buffer boolean and a few others object id is an important one that will be created automatically for us so we will not have to specify an id as you don't see one specified in their example either so now let's go to visual studio code and get started creating our schemas for both our employees data and our users data okay i'm in visual studio code and i've got the source code from the last tutorial it's linked to below as the starter source code if you want to download or clone that right now we're going to go to the model folder and we've got employees.json and users.json because we were just using the nodejs file system to write to both of these files and we're going to get rid of that eventually here as we replace everything with mongodb for now just keep those files and we'll create new files for our schemas and the first one will be called employee and i'll spell that with a capital e and then just js and that's a naming standard it won't really have an impact if you don't use the capital e however it's pretty much the consistent standard that i've seen so first let's define mongoose and require that there we go and now that we've got mongoose pulled in we also need a schema with a capital s and that's going to equal mongoose dot schema once again with a capital s now that we have that we can define our schema and let's call this employee schema and that can use camel case we'll set this equal to a new schema once again capital s on schema and now we can map out our data and if you remember our employee's data was very simple it just had a first name and a last name so that's what we'll declare here now remember uh we will automatically have an object id created for us so we don't need an id field here and now we can say first name is type string and then we can also say it's required and that accepts a boolean so we'll say true that is absolutely required and then we'll do the same for last name and know what we could just copy this down shift alt and the down arrow for me on windows and visual studio code and make that the last name and let's get rid of the comma there and that's basically our schema very simple we've got two string fields first name and last name now at the end of the file we need module dot exports and we're going to set this equal to mongoose dot model now we're creating a data model right here and we'll set this equal to employee and that is uppercase first letter and then not plural once again just like the name of the file employee and then we'll use the employee schema now by default mongoose when it creates this model will set this to lowercase and plural so it will look for an employee's collection in mongodb and the employees collection will be all lower case and once again it will be plural and we can see that if we go back to the docs and we go to the models link in the docs there we go it says this in bold right here mongoose automatically looks for the plural lowercase version of your model name so in the example they give they have the word tank they defined here for the model and they passed in the string tank with the capital t but it says for the example above the model tank is for the tanks collection in the mongodb database and that's all lowercase and plural all right back to visual studio code let's save this file and let's go ahead and create a user schema as well now our user data had just a little more to it so this will be a little more interesting than just the first name and last name that we had in the employee schema i'm just going to copy these imports here because we need the exact same thing at the beginning of basically every schema we create and now i'm going to say user schema camel case this is equal to new schema capital s on schema and now we have a username in our data and this is kind of like the first name last name in the previous schema it's type string and then required is true after the username we have roles now the roles data is a little bit different so we had user which was a possible role and now let's specify some data or some details about the user role here inside of an object and now we can set this to type number and we can put a default value so if not specified any user that's created will automatically be assigned the value of 2001 and that was our basic user value that we had previously applied and then the next role was editor and that had a number and then the next role was admin and that had a number notice we're not providing default values and we're not even saying they're required not everybody's an editor not everybody's an admin so these will only be added to the data that we decide to add them to as an admin could make those decisions okay now that we've defined the roles let's put in the password field this is much like we had before type will be string and required will be true and then after that if you remember we also store a refresh token and when a user is created they don't have a refresh token but after they're authenticated they get one so this is a string but it does not have a default value and it's not required because it's not always there so now we've created our schema for our users and let's go ahead and export this we'll say module.exports set it equal to mongoose.model so we're creating a data model and this will be user singular and then mongoose will once again look for users all lowercase plural but we'll match our file name so user and then we'll use the user schema that we just created okay we've created two basic schemas for our data user and employee and then we created models to be associated with those let's go ahead and implement the user schema and model and let's attach that to one of our controllers and let's do it with the register controller first that makes sense where we'd create a new user and now you'll see how much easier mongoose makes interacting with the mongodb collection than it is to write all of this stuff that we have been doing with the file system module and interacting with json files so let's simplify this file and just switch it over to using mongodb so we're going to get rid of the user db that we had up here and let's just bring in the user model so i'll define user with a capital u and set this equal to require and now we need to go up out of the controller folder and into the model folder and then we need the user model after we do that whoa i lost something there user model there we go after we do that we can really get rid of the fs promises and path we're not going to be right into a file anymore or need that we do still need to keep the bcrypt import and now let's start making changes as we handle the new user here and it'll start out the same we need the user and password to come in from the request and if we don't have those we're going to send the same information back that's a bad request but now when we check for duplicates we're interacting with a different database so now this will change just a little and we'll still define duplicate but how we get the duplicate is completely different notice we already have handled a user as an async function so right here we're going to await and then use our user model and call find one and now we'll pass in some information here we're looking for a username that matches the user that we defined from our request and after that we need to call exec here at the end now not every mongoose method needs that on the data model but this one in particular does and that is because we could pass in a callback afterwards like a error result for example but if you don't do that and you're using the async a weight pattern here then you need to put exec at the end of find one and you can check that in the documentation under find one to reference if you need that or when you use any method that you're not sure of and you're using async await you should check that but this is going to return any user that matches the user that was passed in and of course we don't want a duplicate so this is the same if there is a duplicate we need to send this 409 conflict there after that we need to handle the password in the same way but after the password is created our code is going to get much simpler let's go ahead and keep the new user even though we will define this a little bit differently but we're not going to use this or the fs promises we don't need that console log there let's go ahead and keep the status 201 though because that is what we want to send when we create the new user with mongoose we can create and store so i'll put create and store the new user all at once and so what we'll do instead of defining a new user here i'm going to define result and i'm going to set result equal to a weight then our user model dot create and now we are creating a new user and let's look inside to see what we're passing into the create to make sure we have everything we want or we don't want what we do want the username and then we don't really need the roles here because remember we have the default data in our schema so it will be added automatically so we can remove that and then we pass the password and an object id will be created automatically also so this is all we really need to send through our data model and the username and password will be sent by us and then a role will automatically be created a roll value and an id for the document will also be created now result will return the record that is created so we could go ahead and log the result just to view the record in the console and i'll save that i do want to discuss a couple of other ways a record could be created that you might see somewhere i prefer to do it this way because it happens all at once just the user create and it is created and we get the result back but you might also see something like const new user equals and then a new user with the model and then of course you could set new user dot i'm sorry user name there we go and set that equal to whatever data you had and use uh dot notation that way to set the values and at the end of all of that you would want to save so then you would say const result equals and then you would have your await new user and you would call save and that would also work however that's just a little bit longer process you might also see something like the new user being created and then passing that data in like we did inside of user create so instead of using dot notation you might see something like new user equals well here we define new user but then it's equal to a new user and you're passing in the values inside of the parentheses there and then you would still need to have the result equals await new user.save after you did this and so this happens all at once when i use user create and if i do it this other way and create a new user then you have to have another line to actually save the new user so i prefer the user.create let's go ahead and save this now we're ready to test our register controller route so let's open up a terminal you can do that from the terminal menu or press control back tick at least i can on windows and now i'm going to type npm run dev and that should start up nodemon and start our api server here just on localhost port 3500. we've got our message connected to mongodb server's running on port 3500. i'm going to use thunderclient to test everything out like i have in some previous tutorials if you don't have it you can install thunder client as an extension and then it's right here after you have on the left i'll click that i've got some collections and under auth i should have a registration route to test and now i'm going to hide the left-hand menu over here because it looks much better and it's easier to read when it's the full screen so here's the register route see what we're sending in the body okay i've got a user named steve1 to create and then it's got a password and that's really all we need to send let's see if the register route works new user steve one created and here's our object in the console so now we can see what we've got username steve1 the role was created with user 2001 we've got our encrypted password and we've got a new object id and then notice this other field as well that's always added the two underscores and the v and the zero you should always see that as well if you're curious the v is the version key and it keeps track of this and we can also increment this manually if we want to okay now that we created steve one let's create another user and i'm going to go back to my wall one that was an admin previously so let's create him as well and now new user walt one was created and if we look here in the console we can also see that walt one was created down here and here's his information now let's go to mongodb and inside of mongodb we can check our company db here and we should be able to refresh and now we have a user's collection as well and you can see it has two documents so let's look at the user's collection all right we load the documents up and here are the two records or we could call them documents really i'm used to saying records with sql this is a nosql database and it has collections instead of tables and it has documents instead of records so in either one of these we can expand the object and see our user 2001 that was created so we want to make walt an editor and an admin so inside of mongodb here we're mongodb.com and logged back into our account and we're looking at our collection inside of the companydb database that was created and we'd created the employees collection before but we had not created users so when we created the first user it also created the users collection which is interesting but after that we want to edit walt here and we can do that right inside of mongodb.com so let's edit and now let's go ahead and add another role add field after user and we'll put in editor and the value for the editor was 1984. okay now we've completed that now let's add field after editor and we'll add admin and the value for the admin was 51.50 if i remember correctly and so now we've gone ahead and changed that information but we still need to click update here to update the document now the document is updated and walt has all three roles in his document oh but notice what happened here and you want to catch this if you do it because i certainly just made the mistake this was entered as a string and this should be numeric data so we want to get rid of that we don't really need to remove that we need to change the data type over here on the right notice how user 2001 is int 32 so we want to choose that type here on the right and make sure we have the right data type as we make changes here on mongodb.com to any given document okay those changes have been made now let's update and now we have the correct data type in waltz roles 2001 1984 and 5150. okay going back to vs code and i'll close out of thunder client and close out of the terminal as well but let's go ahead and show the file tree because we have changes to make in the controllers we need to go ahead and implement our user model instead of the json file we've been using in the refresh token controller the logout controller and the auth controller and then we need to implement the employee model in the employees controller and change how some of this works just like we did in the register controller and that's what we'll be doing in the next tutorial but my challenge to you is before then go ahead and make the changes on your own and then compare to the tutorial that i release that makes the same changes today we're going to apply the user and employee models to the remaining api routes and update the asynchronous crud operations accordingly and before we finish i'll show you an easy way to deploy your rest api to the web we're going to start with the code from the last tutorial if you don't have it i have a link to the starter source code in the description below let's get started we're looking at the user schema and then of course we create a model here at the bottom that's where we're starting and we applied it to the register controller near the end of the last tutorial and you can see we imported in the user model and this replaced what we had previously in the tutorial series which were json files now we're using mongodb and we're interacting with mongodb by using the mongoose schemas and models that we've created so now let's apply our user model to the next route and instead of register let's just move up one and go to the refresh token controller okay you saw i copied the user model import from the register controller file and i'm going to paste that right over the user's db that we had previously defined to interact with the json file so now we're bringing in the user model and now we can update the handle refresh token function we'll start out the same here where we define the cookie and of course get the jwt from the cookie if it exists but then as far as checking to find a user we have to do that differently and let's go back to that register controller for just a second because we did a very similar thing we used user dot find one and we passed in the name of the user well this time we won't have the username but besides that it will be very similar so let's highlight all of this where we were finding the refresh token inside of the json and let's paste in our user find one but now instead of the username we can just put refresh token here and that's because the property name and the value name or the variable name are the same so instead of refresh token colon refresh token we can just put refresh token there we still need the exec here to execute and that is because we're using async a weight and that means we need to put async up here above which i almost forgot so let's put async up here by handle refresh token and make this an async function and we'll use await here and then we search for the refresh token inside of a document within the user collection after that everything essentially remains the same because we have defined the found user if we found the refresh token or not and of course if not it's a 403 forbidden but after that we're using the same definitions as before so there's nothing else to change in the refresh token route so we can save the file and move on to the logout controller okay we'll start the same in the logout controller and we will not need the fs promises or path either so we can just highlight all of that and paste our that's not the user model is it so let's change that control z to undo that i'll go back here to the register controller where i copied the user model import before i'll copy that again back to the log out controller highlight all of that and paste because that's what we need is the user model imported after that we already have the note here on client also delete the access token again this is the log out route and that's fine the next three lines just as before are fine and then we need to say is the refresh token in the database well that sounds familiar that's just like we used in the refresh token controller so we come back to the refresh token controller i'll scroll up where we had our await user find one and passed in the refresh token copy that come back to the logout this is already an async function that's good so now we can once again define the fine found user in the same way and now after that this remains the same but now this gets much simpler where we delete the refresh token we're no longer interacting with any of this json here so let's just highlight all of this and delete and we can make a few changes we can say found user dot refresh token and we can erase it simply by setting it to an empty string and then we can set a result and we'll set that equal to await found user dot save and that will save our changes back to our mongodb document that is stored in the user collection and after we do that we could go ahead and log the result if we'd like to see that because that will return the newly updated information and that's just for our purposes there you would of course delete that before you put it in production and that's all the changes so we can save that and again remember that found user this is a document now that we have found if it existed and therefore we're able to update that document with the save okay i'll scroll back up to the top and i'm going to copy that user model import one more time because we need it in the auth controller once again i'll highlight the user's db that we previously had and paste in the user model instead i'm going to go ahead and delete this line between bcrypt and jwt we need both of those but we can go ahead and once again delete fs promises and path which we should no longer need these first two lines are the same we'll keep both of them but then once again with found user i think you see the pattern now now we're back to looking at a user name though so we can take this and go back to the register controller where we had the user name with find one and copy that line go back to the auth controller and then we can paste that in as we find the user and save because the next line is fine as well and then the password is evaluated and we're not changing anything about that and really we won't make any changes until we come down here once again to where we were interacting with the file and we will be saving the refresh token with the current user so once again we can delete everything we had here down to the response cookie and let's leave a blank line in between and then we can once again say found user which is our document that we have found and set the refresh token we're going to set that equal to the refresh token that we now have here in the auth controller and then let's define result again and let's set result equal to await found user dot save and that will update the document back in mongodb and let's go ahead and log that result again as well so that should also look very familiar and that completes the auth controller so i know we tested the register controller the register route in the last tutorial but now we'll want to go back and test all the rest of these so we've got the refresh token route we've got a logout route and of course we've got the auth route as well so now let's test those once again with thunderclient if you don't have thunderclient installed it's an extension for visual studio code and you get that right here under extensions and search for thunder client and then you'll have it on the left and this is thunder client it allows you to save collections which i've already saved to match up to this but before we can test it we actually need to start our dev server i'm going to press control back tick you could also go to the terminal menu at the top and choose a new terminal window that way then we type npm run dev to launch our dev server and we should be running on 3500 and connected to mongodb here in a second when it gives us our information and there we see both connected to mongodb server running on port 3500 so it's now ready to test so i've saved a collection named auth and then here we have different routes if i can see which route we have here looks like this is the register route let's go ahead and try that i'm going to click thunder client to hide the left hand side so we can see better and let's look at the body to see what we're going to register we're going to register a user wall one with the password i believe he's already registered so we should get a 409 conflict back let's see what we get that's exactly right 409 conflicts so let's change this to tom one i don't believe i have tom one in my collection of users so now we'll send this and 201 created so we have a new user created our register route is working now let's go back to thunder client and look at the other routes that was the register route now that we've registered let's test the auth route now let's see who we want to authorize well i believe walt one was already created we confirmed that so we can just send in this information to authorize and we send it in and we've got a new access token back and everything is okay he is authorized and of course you see down here we're logging these responses that we're also getting back these console log statements that had the result and that's what we see here is the user that we've pulled in is walt one okay i'm going to pull this down and i'm going to authorize again because if you remember right we only get an access token the way we have it set that works for about 30 seconds but really i guess we're not testing that so wait a minute when we're not too worried about that because we're going to test either the log out or refresh token route let's test that refresh token route that i have in a separate collection and so with the refresh token we're sending a cookie it says no cookies available but i think we have a cookie let's try it out 401 unauthorized we did not get a cookie i think we're running into our secure site error where thunder client doesn't let us test even though we need that secure site option in there for chrome so let's take this out temporarily i'm in the auth controller as we issue the refresh token let's take this out and put it in a comment near the end in production once again you would want this back in there however we can't test it with thunder client with it in there so let's go ahead and save now and once we've got the server updated let's go ahead and run the auth again and then we should be able to test the refresh and now we're up and running connected to mongodb server running on port 3500 let's try this again in thunder client we'll go to the auth first hide this over here i'll go ahead and log and we've got a cookie let's go to the refresh now and come back before we were unauthorized but let's see if this works now and yes it does our cookie works you just have to take that secure out while testing with thunder client so the refresh route is working we have tested the register route we have tested the auth route we've tested the refresh route what is left is the log out route so once again we'll probably need a fresh login to ensure we are logging out correctly so let's go to the auth and now let's see who we're logging in it looks like walt won that's fine we'll send that and now let's go to the log out route and come over here in thunder client and it looks like we actually don't need to send anything it's just going to log out the refresh token that's right so we'll just send and 204 no content that's fine we didn't expect any content to come back but we can see down here because we logged the result we logged out there's the route we went ahead and logged out and we logged out our user walt 1 and we set the refresh token to an empty string okay those updates using the user model were not too bad at all let's go back to the file and what we want to do now is update the employees controller with the employee model and this will be just a little bit more work than what we had previously had but we'll start out once again by eliminating the json file and let's go ahead and import our employee model so we'll have const employee and we'll set that equal to require and then we need to go up one folder find the model folder and then employee that is correct and now let's look at our get all employees route well before we just grab the json and return that now this will be just a little bit more to do with mongodb and of course this will be an async operation so let's remove this response json for now and we'll define employees and let's set this equal to await employee.find and by calling find like this it will return all of the employees then we can say if there are no employees we're going to return and then we'll send a response with a status 204 which is no content and then json and we'll send a message here and in our json message we'll just say it's a string no employees found and after that we'll assume we do have employees if we've made it this far so we'll say response.json and we'll send the employees and i can see i've got an error i put brackets instead of curly braces go ahead and eliminate that bracket and replace this one as well and we should be good so let's go ahead and save this now let's look at the create new employee function which will also be async so let's start here and with that we can probably go ahead and change quite a few things that we have in here so i'm just going to highlight all of this and remove it and after that we'll start out with an if statement but different than we have below this will be if a request and now we can use optional chaining to say as a body and then if it has a first name because we need all of that or we can say the same thing about the last name essentially we're saying if there is no first name or last name and we would expect the request to have a body but for some reason if it doesn't we'll catch that as well so if we don't have any of those let's go ahead and send a response here and we'll return response dot status and this would be a 400 because it would be a bad request there's json curly braces this time message and our message will be first and last names are required and you can see we had something very similar below but it was just a little different than that so now let's eliminate that as well let's just go ahead and delete these lines too and we'll start over just a little bit and put an extra line there and we'll do a try catch block and of course we have the catch after there's our error and if we catch an error let's just console error the error okay but in the try block now let's define a result and set this equal to a weight use our employee model and now we create we'll create a record here and we'll say first name is request.body.firstname and lastname would be much the same pattern last request.body.lastname and i'll put my semicolon here and save but we still need to send a response so we'll say response.json oh let's put a status first and the status here would be a 201 which stands for created and then we'll send the result back with the record that we have created okay let's scroll down now and look at the update employee once again it will be an async function and after that we'll start out a little differently so let's go ahead and delete and well we don't need to delete that line let's just delete the top line to begin with okay so we'll start out with if and once again request and let's use optional chaining body and now we're looking for an id and if we don't have the id we'll return response status 400 and after that we can just give a message in json and let's see if it's the same message that we have below not quite the same so here let's add a little message different and we'll say message an id parameter is required okay so we've confirmed we now have an id if we make it to the next spot and here we can define our employee so we'll say const employee and set this equal to a weight call our employee model and we'll use find one here and now remember mongodb uses an underscore id it automatically generates that and we're going to compare that to request.body.id that is passed in as a parameter and after that we need to call the exec at the end to call that function into action now let's go ahead and delete the next line here and we can say if there's no employee return status let's change this to a 204 because it's not really a bad request at this point it just means that they requested an id that doesn't exist they might have issued the request properly but now let's say something just a little different we'll say no employee matches and id and now let's get rid of this at the end and get rid of the not found part no employee matches whatever id was passed in there okay so we're sending our status 204 we'll save that much now let's look at this if the request dot body and let's go ahead and optionally chain first name and last name and then we can say employee first name equals the request.body first name and last name is the same that's fine so we're just optionally chaining that's all we change there that's different than we had before and now this gets much simpler here we're not sorting any json data or creating new ids or anything there so let's remove all of that and we'll just say const result equals a weight employee notice this is the employee document we've created or we've found actually we didn't create it's the employee here not the employee model but employee dot save and now we've saved any changes we've made to this employee document and then instead of data employees we'll just send the result we've defined here and save and that is our update employee function okay let's scroll up and take a look at delete employee which should also get a little simpler but we're going to start out much like we did before so we'll say if there is no request and will optionally chain body and then we'll optionally chain the id and we're going to return response dot status 400 and that should also be json and here we'll have a message and our json will say employee id required and put the semicolon there and now we need to define our employee again which would be much the same as we had before really it's the find one with the body id so let's just scroll up here and copy exactly what we had before and come down and here we have defined the employee id again and so then our employee not found will probably be the same as well so we can copy that and come down here as well and just copy this over and paste and then after that we will not be filtering so let's just remove these lines here once again and we'll say const result equals await employee dot delete one now instead of find one and here once again this will be underscore id and then it will be the request dot body dot id that was passed in we do not need an exec after delete one and then we will put in the result and if you're wondering why we don't need the exec here it's just all based on the documents so once again look at mongoosejs.com and those docs and you'll see which different methods you need to put that after and which ones you don't and finally let's check the get employee route as well and we need to put in a check as we had before with the others let's check the request if there's no request dot params this time and then of course we're looking for an id once again and we have a similar message at the end so let's just copy this over and paste it in because that is required and now we need to find an employee again so we can copy the same line as we've defined the employee before and we'll come back down here and set employee equal to the find one statement if we don't find the employee well that's a repeat of this i'll just copy this return line here and paste it in here and then we're already set because we just want to return the employee as we were before as this is the get employee route or handler just for the one employee and of course we're expecting that id parameter to be sent in so let's save that and we have completed our async functions let's put async with that as well and if we didn't with the others it looks like i also forgot to do that with the delete employee let me check the rest we need to have all of these functions as async functions and they complete the different crud operations create read update and delete for the employees collection before we test the routes there is one error to fix notice i was using params as we're using a git route to pull that in but i put request body dot id in the function and this needs to be [Music] params.id to access that value that we get from the url in the route okay so now that we have fixed this and we're now using params let's test the routes and we need a jwt to be authorized so let's go ahead and use the auth route you might want to change your code to timeout or for a longer timeout duration than 30 seconds mine is set to 30 seconds so i've got to be a little fast to test these reps but let's go ahead and get authorized now we've got a new access token we can jump back over here i'll open the employees routes i want to get all employees and now for the authorization i need to paste in the new token and we get our one employee walt walters i'm going to copy his id open the terminal window and just paste his id down there because i'm going to need it to test the individual get employee route so we'll come back now and get authorized once again collapse the employees api routes and check the authorization get a new access token once we've got the new access token go back to the employees api go to the get an employee route an individual employee and paste that token in here and i need the id to put in the url i'll paste that in and send and we get walt walters back once again now that we're using the request.params.id for this route because the user id is read directly from the url as it is a get request okay let's get authorized once again and then we'll come back and test the post here is the auth route again we'll send get a new token back to thunder client open the employees apis look at the posted employee here's the new auth paste that in look at the body we've already got walt walters let's change this to dave walters is good now we have dave walters as an employee that was created a status 201 which is created one more authorization to go so we can test the put i guess two more and then the delete as well so let's go here and authorize once again new access token come back to the put route and let's see what we need here let's put in the access token and in the body oh we need to specify the id once again well let's and we change a first name to david let's go back and i believe in the get employee route i still have that id that we used before oh and it's still down here in the node terminal as well so we can pull it out of there so let's reauthorize new access token we will come back to the employees use put and for put we need to put in the new access token and then in the body we need the employee id so i'm going to paste that in here and change walt to david and now we have david walters and of course there's already a dave walters as well so the put route works and now we want to delete and of course we'll delete this same user that we still have the id handy for so let's reauthorize one more time get a new access token we have the new access token copy that go to the employees routes delete an employee paste in our new access token and in the body we once again need the employee id we paste in that id and we get returned the employee that was deleted so david walters is no longer in our collection but it was returned by the delete route as a confirmation that this employee was deleted okay so from here what you should do is go ahead and create a users js in the routes and then api folder and allow some user information to be requested maybe get all users and maybe delete users and set that up so it can be accessed in the route by admin only such as roleslist.admin because that's the users and i'll let you do that on your own but i will put it in the completed repository that i will post the link below so there'll be a link to the starter code and then a link to the completed code as well but before i go i want to show you how you can easily launch a repository and if that repository create or has a node application like this rest api it will easily be deployed okay there are several places on the web where you can host your node project and even a rest api using express in like we've created i'm going to show you one of the easiest ways to deploy a project like this and we're going to deploy to glitch.com so i'm going to put in another bold statement here and say well not start let's just say deploy by clicking the button above okay now that we've put that in i'm going to copy and paste some code but i'm going to just change which project it was for so this code will put a button on the readme of the repository that i share to glit or not to glitch to github and then when the button is clicked it will launch on glitch so here we have to put in the name of the current project and so i'm put async crud i believe i named this project and i'll save and we can verify here by i'll go back and let's see i named this async crud that is correct so i'll open up the terminal window and i'll push my changes to github that i've already initialized repository so i'll add the file and i'll commit messages updated readme and i'll push to github and i need a passphrase set up with mine and there we go i've pushed that to github and so now if we go back and look at the readme for this repository there should be a button that's available and it says remix this and that will allow you to go ahead and launch this application on glitch so let's go ahead and do that i'll just click the button it takes just a minute to load the project and it will be up and running except for one thing and that one thing is the values that we have decided to put in our dot env remember the dot e and v file should be listed in your git ignore so it is not here and notice the remix button is much larger once it gets to glitch that's interesting okay so once again looking at the get ignore you should have your enb file here so the secrets that you have stored in the dot enb need to go in the dot e and b that is provided here at glitch and you can of course click this to learn how to use environment variables we've already talked about that so you can add a variable and here is where you would type like access token secret i believe is what we named one of ours and then you would paste in your value for that you would do the same for the refresh token secret and you would also want to do the same for the string you put in the connection string that we used for mongoose and mongodb but this is just an example to show you how you can go ahead and launch that so what i'm going to do is leave that button in the readme and i'll put a little extra note in the readme saying remember to add your own values in the dot env because you can click that button right there in my repository and from there you can bring back up this project in glitch and if you create an account a glitch you can save it there as well so that will help you launch any future node application you might create and this would allow you to put a button in your repositories and launch them as well and i think you'll like working with glitch also i use it for several things and i should add that once you're on glitch and you have your project launched it will give it a name like this and then you'll have your live project you can click change url here and you'll see the url for your project so that would be the url for your api so that is what you would want to go to for your api and then the end points would go of course after this if you're trying to pull up any specific endpoint so we have covered a lot in this series and of course there is much more depth you could go into as you dive into the docs but i feel like we've covered the create read update and delete for and mongodb we've built a full rest api with node and express and we have added user authentication we have talked about authorization and json web tokens as well to protect those routes so if we talk about next steps you would want to take what we have built and what we have built here on the back end using express and node could be combined with react for the mern stack so if you haven't learned react you want to check out my nine hour beginners tutorial for that and you can combine that knowledge with this back end course knowledge to complete the mern stack however you could also add whichever front-end technology you wanted to this back end with express and node for whatever application you wanted to create remember to keep striving for progress over perfection and a little progress every day will go a very long way please give this video a like if it's helped you and thank you for watching and subscribing you're helping my channel grow have a great day and let's write more code together very soon
Info
Channel: Dave Gray
Views: 42,301
Rating: undefined out of 5
Keywords: Node.js Full Course for Beginners, node.js tutorial for beginners, node.js full tutorial for beginners, node.js for beginners, node full course, node full tutorial, node for beginners, nodejs full course for beginners, nodejs full tutorial for beginners, nodejs full course, nodejs full tutorial, nodejs for beginners, node tutorial, node.js tutorial, nodejs tutorial, node course, node.js course, nodejs course, node, node.js, nodejs, js, node js tutorial, node js, express, expressjs
Id: f2EqECiTBL8
Channel Id: undefined
Length: 410min 41sec (24641 seconds)
Published: Fri Dec 03 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.