RESTful API using Node JS, MongoDB & Typescript IN-DEPTH [2022]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what's going on everybody thanks for tuning back in today we're going to be taking a look at how to construct a restful api with crud functionality in depth i'm going to be specifically looking at mongoose and mongodb as my database of choice and as always i'll be making this project using nothing but typescript now that being said i'm going to show you a couple extra things in this video as compared to the last video i did on where i only showed you the read functionality of reading into a database with mongoose i'm going to show you full crud functionality which stands for create read update and delete i'm going to make you a small custom logger i'm actually going to show you how to build the build as well the only thing i'm not going to cover is tests so this is going to be a lot more in depth than the previous video that i made to help people who are struggling with other functions that are crud that aren't read and for those of you using visual studio code i have a special treat for you where i'm going to show you how to use visual studio code snippets to make life way easier when it comes to creating more than one controller or route file for example i'm going to make it so that we can easily take our code and replicate it over and over again okay guys let's get into it so let's open up a terminal in the folder that we want to create our project in and let's install a few things i'm going to zoom in here so you can see this a little bit better go ahead and run an npm install g for global and install the following packages nodemon ts node prettier and typescript i'm installing these globally so i can use them for all my projects next we're going to run an npm init and enter all of your information for your package here i'm going to use the defaults for now but edit my package.json when i open up my project in visual studio code speaking of which go ahead and do that once you have finished your npm init you can see my very basic package.json here so it's time to start editing first i'm going to run an npm install i'm going to install chalk at 4.1.2 a specific version i'm going to install dot m express joy and mongoose chalk is a library for adding color to the console this is just to show you how to make a custom logger if you don't want to use a downloaded library dot m helps us load our environment variables express is for building our restful api framework joy is for data validation and mongoose is to access mongodb with a nice little wrapper a lot of these packages have typescript definitions with them so we only have to install typescript dependencies for a couple of our packages go ahead and run npm install dash dash save dev and we're going to do typescript and then we're going to do the types for express now that we've done that take a look at your json file and you're going to see all of our dependencies installed next we're going to define some scripts let's go ahead and define our start script this one is going to be very simple basically we're just going to be calling node and then our build forward slash server.js file what this is going to do is basically run node against our actual build once we compile our typescript into javascript next for the build script what we're going to do is we're going to have an rm-rf and get rid of the build folder we're going to add two ampersands and then call tsc which is our typescript compiler next go ahead and run a tse-init so it's going to load up a typescript.json file for you that defines how your project is going to use typescript i'm going to copy and paste my file in here without the comments everything in here is the same as the default tsconfig.json the only thing i've added is my out directory which is period forward slash build and my include section which is basically telling typescript that i only want to compile my source files next for those of you using visual studio code i have three plugins installed that i'm going to be using that you should use as well dot m is going to add support for emv files just to make the linting a little bit prettier speaking of which prettier is installed which is going to be my code formatter for my typescript it's going to make everything have even spacing all the commas where they're supposed to be quotes semicolons etc and then finally the third one is optional but visual studio code icons makes the icons inside of my explorer look a lot nicer and a lot more organized back inside of our project inside of the root directory i'm going to make a folder called vs code and inside of it i'm going to make a settings.json as i do with most of my projects i'm going to paste in here some basic visual studio code settings that i like to use basically the default formatter that you can see here is that prettier plugin that i just installed so i want to make sure that i have in here and i want to have that format on save and format on paste those are the most important so anytime you paste code or save it it's just going to format that file for you next inside of my root directory again i'm going to add a dot prettier rc and i'm going to paste in my prettier rules again these are the rules that i like to use you can use whatever rules you want but these are the ones that i like to go with next go ahead and create the source folder that we referenced inside of our tsconfig.json and we're going to create a bunch of folders on the inside and get our folder structure underway as well so the folders i'm going to want you to create inside of your source folder are config controllers library middleware models and routes this is the basic setup of a lot of my projects we're going to tackle this project by first setting up some config then we're going to connect to then we're going to create our api rules create some routes and then we're going to protect our data so inside of the config folder go ahead and create a file called config.ts at the top we're going to import dot m from dot m and then we're going to take that dot m and call dot config as a function what this is going to do is going to load any environment variables we happen to have inside of our bashrc or inside of our current environment or inside of a emv file in our root directory of our project the reason that we want to use environment variables is because you don't want to store things like passwords inside of code you want them to be usually environment specific or hidden away environment variables when nobody can see them so before i create any of my variables i need to set up a mongodb if you have this already done you can go ahead and skip this step but if you haven't set one up i'm going to show you how to set one up for free hop on over to google.com and search for atlas you can go ahead and click the sign up with google and then it's going to ask you to log in so once you've done that go to the next step go ahead and accept the privacy policy and hit submit and then follow the steps to get set up with mongodb atlas it's going to ask you some basic questions you just got to fill them out once you get to the tier section on the right hand side you should see the free tier eligible one and then it's going to ask you where you want to create a shared cluster you're going to go ahead and fill out the information i'm going to pick aws and then you can go ahead and click create cluster then it's going to ask you to create a username and password this is what you're going to use to log into your database go ahead and create a username and then you can make your own password you can generate one just make sure you copy and paste it because we're going to need it for later now that you've created your user don't forget to whitelist your current ip address so this is an ip address i'm using from a vpn i'm actually going to add another subset of this and i'm going to change the 75 to a 0 and do a slash 24 which basically covers the entire ip range and the reason that i'm doing this is that last number on my ip whenever i connect never stays the same once you've done that you can hit finish and close and then it should start creating your cluster for you now you're going to see your cluster deploying it's going to take a little while so what we can do we can actually go back to our project and fill out some variables so we're going to make a couple constants i'm going to make a username and that's going to be equal to my process dot m dot underscore username or an empty string and the reason i put the or empty string at the end is so typescript understands that this variable is a string and not null i'm going to do the same thing with the password and then i'm going to create a url and i'm going to leave this blank for now because i'm going to fill this in once my cluster is created i'm going to do one more and that's a server port but instead of making it like the previous two i'm gonna check to see that it exists with my question mark if it does i want a number from that port because i'm gonna make everything a string inside of my environment variables or a default port number and i'm just gonna obviously pick one through three seven because what other number would you pick go ahead and export a cons config you could do something like add the username and password if you want but in reality all we really need is the url so export the url and create a server section and export the server port as well by the time you've done all this your database should be done deploying so go ahead and click the connect button inside of your cluster and then you're going to want to connect with your application and it's going to give you the string that we need copy that string paste it into your url and replace the super user and password sections with the username and password that you created next let's go ahead and create our server.ts file this is going to go right inside the source folder outside of all the other folders that we made we're going to import three libraries for now we're going to import express from express http from http and mongoose from mongoose once you've done your three imports go ahead and create a constant router and make that equal to express as a function so the first thing we're going to do is we're going to want to connect to mongoose because if we don't connect to mongoose we don't want to do anything else inside of our project so how we're going to do this is we're going to type mongoose.connect and then we're going to pass in our config.mongo.url make sure that you've imported config so that it auto-completes for you and then you're going to add a then and a catch block now the string that atlas generated for us actually has some options in it so i'm going to show you another way to pass those options in go back to your config and get rid of that majority and rewrites we're going to actually pass those in as actual parameters so you can go ahead and just get rid of those and then go back to your server.ts file and after you call config.mongo.url put a comma and then pass in an object and this is where you pass in your options and you can basically just pass in those same two options w being majority and rewrites being true once you've done that inside of the then block you can go ahead and log something like console connected and inside of the catch block you can log a console error before i do anything else i'm going to go back to my package.json and my main i'm going to change to source server.ts and the reason that i'm doing this is so i can just type in nodemon and it will automatically pick up the main file that i want to proxy now when i click nodemon you can see that there is an issue and that's the actual username and password don't exist and that's because i haven't declared my environment variables yet so what we're going to do is we're going to create a m file a dot emv and that's going to go inside of our root directory here you can create your username and your password and paste in the password that you created before i'm also going to add my server port to show you how it can change and i'm going to change this to something like 90 90. you can make it any number under about 65 000. now when i run nodemon again you're going to see that it takes a second and then it says connected which means that it's successfully connecting to atlas so the next thing i'm going to do is create a custom login component instead of using the console log i'm just going to create my own little logging library instead of using something like log for js or morgan or whatever people use so i'm going to create a logging.ts file inside of my library at the top i'm going to import chalk from chalk i'm going to export a default class logging and then i'm going to create some static logging functions to keep it nice and simple i'm going to create a public static info it's going to take args as any because i want to blog anything really and that's just going to point to a console.log but inside of it i'm going to do a couple things first i'm going to call chalk.blue and then i'm going to pass in a string that is actually the current date to a local string and the reason that i'm doing this is because i want every log to have the current date time on it then right after that i'm going to add the info just to declare that this is an info log statement next i'm going to check to see what our type of args is after the comma if it is a type string i want to chalk bright blue the args if not i just want to display the args and the reason that i'm typing it this way is because if it's a string chalk can color it but if it's not a string it's going to show up as object object you won't actually see what it is so to see what it is fully you just want to log the actual args themselves i'm going to copy and paste this two more times create a warn and an error function and change the blue to either yellow or red depending if it's warning or error and once you've done this you can even make a public static log function and it also takes args and just points to the info function kind of like what the console.log does sometimes depending on your logging library now inside of my server.ts i'm going to change my console logs to my logging.info it's going to import automatically for me with visual studio code and once i've done that then i'm going to just change these little logging statements and then run my project with nodemon one more time and then you can see that it displays the date the log level and the color is all correct depending on the log that has been passed now that we've got our basic config setup and our mongo's connecting the next step is to actually create our restful api and it's rules so what i'm going to do is i'm going to create a new function it's going to be called start server and the reason i'm not just declaring all of my router functions right here but i'm rather putting them inside of a function it's because if mongoose doesn't connect i don't want to call any of this stuff i just want the program to exit just in case i'm running this in a script or a docker container or something i want it to just safely exit so what i'm going to do is create this function and then put everything inside of it once you've named your function call it from the then block inside of your mongoose.connect and then let's start actually implementing our router functionality the first thing we're going to do is we're going to add the logging to our router so we're going to log the request and the response call router.use to create a piece of middleware inside of it you're going to have a function that has request response and next is props and inside of the function the first thing we're going to do is log the request so how we're going to do that is we're going to call our logging.info i'm going to say incoming because this is the beginning of the request i'm going to first check the method and how i'm going to do that is check the req.method or request.method i'm also going to check the url i want to see where this request is going so for example whatever the api endpoint is for example forward slash books slash get then i'm going to get the ip of whoever is calling this or whoever's passing in the request so this could be your local host this could be a function this could be a browser but whatever it is it should give me some sort of ip address and now that i've logged the request i'm going to check my response.on finish listener so once this specific request is finished i want to actually copy and paste what i had up before and add the status code so i can check to see what happened with the request did it pass or not so type in status and then the variable you're going to want to check in here is actually res dot status code to get my response.status code nice and simple after the response finish go ahead and call the next functionality what this will do is allow us to pass through this piece of middleware instead of ending the request on this middleware anytime you want middleware to actually pass the request through you have to have the next function on it some basic housekeeping that we have to do is call our router.use and then express.url encoded extended to true and then express.json so this is basically some settings that i only want to get json requests and i don't care if they're nested nice and simple stuff this used to be separated by body parser but it's included inside of express now which is really nice to save some time i'm going to copy in the rules of our api i use these in all my projects but i'm going to explain them to you so the first header i'll access control allow origin the star just says that these requests can come from anywhere you can put in a list of ips here or trusted sources if you want this to be super private and then the header following that just tells us what headers we're allowed to use inside of our project and then finally if we pass in an options request it's just going to return all of the options we can use inside of this api after that of course we're going to call the next function one more time to go through this just to make sure that we pass through our request so the next section that would come is our actual routes but we haven't declared those yet so we can skip this section for now next i'm going to actually add a get request here and it's going to be called a health check it's just a route i can call to make sure my api is working properly so i'm going to call router.get i'm going to give it the address of forward slash ping i'm going to put in the standard request response next middleware provided by express and all this is going to do is return a response dot status of 200 and a json message that can say anything you want i call the endpoint ping so it's just going to return pong nice and simple lastly after that we're going to have some basic error handling basically what this is going to say is that if our request passes through all the routes and doesn't match anything we're going to go ahead and throw an error saying that this is not an actual route or we're going to call the error not found as you can see here we're going to call logging.error and actually log that error and then we'll return a response status of 404 and pass the message now that we've declared all that go ahead and call your http dot create server pass in your router and then call the dot listen pass in your config.serverport and then add a callback function that basically just logs saying that the server is successfully running on port and then you can pass in the variable one more time if you want you can have any message here that you desire once this message is called you know that the server is running i'm going to go ahead and call nodemon one more time start up my project you can see that we're connected to and the server is running on port 9090 which means that my environment variables are being picked up i'm going to grab the postman utility which allows me to call api requests and i'm going to go ahead and pass in my localhost 9090 and i'm just going to call ping and you can see it returned the message pong if you take a look at the console log you can see the incoming method and then the outgoing method which i forgot to rename but we can do that later in the code now if i type in a route that doesn't exist you can see that the message is going to say not found and then you're going to see that this error shows up in the console and it actually prints red as we have declared it now since the error itself isn't a string you can see that it doesn't highlight just the way we wanted the functionality to work now that we have a basic server running it's time to have some fun with i'm going to be using the classic example of authors and books as my model i'm going to have a schema for my authors and for my books and i'm going to link them together as an author writes a book so what i'm going to do is i'm going to create the models controllers and routes next and first i'm going to create the author model controller and route then i'm going to show you how to use visual studio code snippets to automatically create as many of these as you want with very very simple variable management and what i mean by that is i'm just going to have some placeholders and we just have to replace certain variables and then we can populate any controller or route file that we want so inside of the models folder go ahead and create your author.ts file at the top we're going to import mongoose and then inside of some brackets we're going to import the document and schema from mongoose as well first thing i'm going to do is i'm going to export an interface and i'm going to call it iauthor this interface is just going to have a name that's a string because that's the only information we want for our author now after this i'm going to declare another interface called my i author model and it's going to extend the iauthor and the document that i imported before and that's because the document provides all of the underscore id the time stamps everything else that we would need inside of a model the reason that i'm not just declaring the iauthor as an extended document is because i want to use the i author as my base for some simple validation so i want to keep this separate for now you'll see what i mean when we start protecting our routes after this go ahead and create a author schema which is going to be of type schema make that equal to a new schema and inside of it we're going to pass in a couple objects the first one is going to have the name key and it's going to be declared with the type that's a string with a capital s and it's going to have a required as true which means that this has to be input in order for us to put in our model put a comma after this object and then inside here we're going to say version key is equal to false this just means i don't want to return the version key variable something that is provided by next we're going to export a default mongoose mongoose.model and inside of the chevrons we're going to pass in our iauthor model then inside of the function it's going to take two things it's going to take a string we're going to call this author which is going to be the name of our document collection and then the author schema and now our model is complete next we want to go to our controllers folder and create our author controller so how we're going to do that is at the top we're going to import the next function request and response from express we're going to import mongoose from mongoose and then we're going to import author from our model's author create a new function called consecrate author pass in the request response and next as we have been doing for middleware but this time you're going to have to assign the interfaces and types to them go ahead and copy and paste this four more times and change these to actually match our crud function so we're gonna have a read we're gonna have actually a read all as well an update and a delete so let's start filling out our crud functionality inside of the create author declare a const object inside of it we're going to retrieve the name and that's going to be equal to request.body create a new author object and that's going to be equal to a new author and inside of it we're going to have an object first you're going to have an underscore id that's going to be equal to a new mongoose.types.object id as a function and then comma that and pass in the name underneath this object return an author dot save make sure it's the lowercase author because this is a object now add a then in catch block for the then block we're going to have the author prop point to a response dot status of 201 pass in some json and just pass in the author that we just returned and then for the catch block you're going to have an error prop and you can return a response.status of 500 here and then pass in the error inside of the json block and you can see that when i save it periodically it fixes the formatting for me with my prettier setup next we're going to want to create our read functionality so we're going to want to read a single author from the database and we're going to get that author by the id and we're going to call a const author id is equal to request.params.author id now that author id is actually going to be defined inside of our route when we declare the actual path next we're going to return an author dot find by id we're going to pass in our author id and then add some then and catch blocks again so here we're going to have our author now if it is found so how we can check that is by calling author and then question mark to see if it exists if it does return a response of 200 and pass in that author and if it doesn't exist we can return a response of let's say 404 and pass in a message that simply says not found don't forget to add your error block by adding the catch block and call the error and pass in another response 500. what you can do is basically just copy and paste the one from above and your read author block is finished next let's create our read all functionality and let's just rename this to read all because we don't really need the author key here this one's going to be a little bit simpler because we don't need an author id i'm just going to copy and paste the one from above and fix it up a little bit change the function to author.find and just return a response.status of 200. i don't have to return anything else and just change author to authors because that goes more in line of what we're looking for here since it's going to be returning an array of objects the update author we're going to need to find that id again so you can go ahead and copy and paste getting the author id from the read author what we're going to do here is we're going to find this one by id as well so you can copy and paste that part from read author as well but the then block is going to be a little bit different so what we're going to do here is we're going to actually have a function inside of it you're going to see if the author exists cool we're going to actually do some work on it by changing the variables first fill out the else block and just simply return the 404 not found i'm going to copy and paste mine from above and inside of the if block if it does exist what you're going to do is call it author.set pass in the request.body as we're going to pass in the name in the body and then you're going to actually copy the save block from above because now this object or author object has been altered and just needs to be saved in the database now that we've filled out this function let's go ahead and round off this controller by filling out our delete author so what we're going to do is we're going to do this one by id as well so go ahead and copy and paste that from above next we're going to call a return and it's going to be an author dot find by id and delete pass in our author id we're going to add a then block and a catch block inside of this then block i'm going to copy and paste this from above this time though if i find the author i'm going to change the status to 201 and instead of returning the author i'm actually just going to have a message that says deleted and i'm going to keep the 404 not found just in case i can't find this author by id go ahead and add your catch block and then our delete functionality is finished the last thing we have to do now is export all these functions so we can use them inside of our routes go ahead and export a default object and inside of it just pass in our five functions that we created javascript is really nice because it just lets us type in the name once and then it automatically assumes that's both the key and value inside of the routes folder go ahead and create an author.ts file and now we're going to hook up all these functions to our appropriate routes we're going to import express from express we're going to import our controller from our controller's author next we're going to call const routers equal to express.router with a capital r as a function now we're going to create our five routes the first one is going to be a router.post i'm going to have this route as forward slash create and call controller.createauthor next is going to be a get i'm going to go ahead and call get and then pass in the author id and call the controller.readauthor function next i'm going to call a router.get and just call get with a forward slash with nothing after it next i'm going to call a patch and i'm going to have the update author id and call the updateauthor function and then finally a router.delete with the forward slash delete and as we've been doing another author id with the controller.deleteauthor function finally at the bottom i'm going to export our router and save the file finally let's go to our server.ts file and what we're going to do is at the top first we're going to import our routes so you can import and name it just author routes you can call it really whatever you want from our routes.ts file and then here you can do a router.use first i'm going to call forward slash authors and then secondly my author routes here so now that basically is saying that any of those routes all i have to do is call forward slash authors and then it will direct me to that routes file and then try and hook up with one of those functions there and if it can't find anything there then it's just going to throw the error as we've seen before so let's go ahead and call nodemon one more time and let's test this out so i'm going to call authors forward slash get and you're going to see that it returns me an empty array because i don't have any authors yet i'm going to open a new tab here i'm going to make a post and i'm going to change this to create instead of get now you can see here i didn't put authors first so this isn't going to work but let's go ahead and fill it out anyways change your body type to json and i'm gonna put in a name i'm just gonna call this guy gus person you can name whatever you want this really doesn't matter and when i send it's not gonna work because i didn't call my authors create i just called create so that's not a real route so i'm gonna go ahead and change that to authors create and then you can see that it returns me the author object that was created inside the database and the corresponding id that goes with it as well so if i go back and i call the authors get like i did before my authors list should now have this guy in it so let's go ahead and call that and you can see that he shows up so next let's play around with this a little bit more i'm going to change this to a patch and then i'm going to copy this id and put it after my update and i'm just going to change his name here to something else and i'm going to hit send and you're going to see that it changed his name so if i go back and i call all the authors again you can see that his name changes finally if i change this to a delete and i change the router to a delete you can see that he was deleted and he now no longer shows up inside of my call so all of our functionality seems to be working pretty well and let's just throw him back in the database and look at that he shows up again and you can see when i minimize you can see all the logging just going crazy for blogging all of our requests and it seems to be logging them properly so let's go back to our models folder and create our book model just like before we're going to be importing mongoose from mongoose and we're going to import document and schema as well export an interface called ibook and this is going to have a title and an author that are both strings then you're going to export an interface ibook model that inherits both ibook and the document from mongoose go ahead and create our new model object we're going to call it our const book schema and inside of our new schema we're going to have an object that first object is going to have the title and that's going to be of type string and that's going to be required and then the author of type schema dot types dot object id this is going to be required and then you're going to have one more that says ref and that's going to be author which references the author document collection here we're going to have some options let's have the timestamps included with this one and i don't think i have to set it but let's set version key to true i believe it is and that will actually have that variable show up i just want to show you what it looks like i think this might not be correct but we'll just come back to it and see if it errors out finally export a mongoose dot model you're going to pass in your ibook model and then inside of the function call you're going to call book with a capital b and then you're going to pass in the book schema and this will declare our book schema for us so now if you wanted to create the controller for this you could very easily go to your author controller copy and paste it and just replace the variables for you make sure you use capitalization search for all the capital authors search for all the lowercase authors and you should be able to find and replace it pretty quickly that being said if you want an extremely fast way to do this over and over again my recommendation would be to create a visual studio code snippet so i'm going to show you how to do that right now and then we're going to use it to create our book controller and our book routes go ahead and create your book.ts controller i'm going to go to my author controller and copy and paste the entire file next i'm going to control shift p for my preferences i'm going to search for snippet and then i'm going to click typescript dot json or a new global snippets file you can do either one but let's just do the typescript.json now to be safe inside of it we have to actually declare a snippet so first let's give it a name i'm going to call this one crud inside of it i'm going to have a prefix which is what i type in to populate it and i'm just going to call crud controller then we're going to have a body this can be a type string or type string array i'm going to pass in the array here and now i'm going to get my code set up for editing create a new file and paste in your code that you copy and paste it you can see at the top here it's a new file the first thing we're going to do is we're going to change all of our author variables into something that the visual studio code snippets will recognize as variables that we want to change so what i'm going to do is first i'm going to search for all of the authors that start with a capital a i'm going to hit ctrl f and make sure my case sensitive button is on there it's that a that's highlighted i'm going to type in dollar sign and inside of some parentheses i'm going to type 1 colon model name next i'm going to search for all the lowercase ones and change this to a 2 dot variable name i want them to be different you don't actually have to put a name into it but i am and then third i'm going to change this these two names the variables that are being passed in to my start name so how this is going to work is visual studio code we'll highlight each of these variables in groups so first it'll highlight the model name so i'll be able to type in my model and then my lowercase variable name and then finally it'll end with me typing in all of the things that i used to create my first document in the collection now what i'm going to do is i'm going to actually minimize this a lot because i don't want word wrap to be on for this and what i'm going to do is i'm going to use ctrl alt and then the arrow keys on windows this is going to be a different command on mac and linux and what this does is extends your cursor to the line below it so i don't want word wrap on otherwise it's going to mess it up for some lines and i'm going to start at the top on the beginning of the of the first row and then go all the way down to the end of the file and when you see the cursor lighting up the entire beginning of the file go ahead and insert some quotes and it'll put it on the whole file then you're going to hit the end key and you'll see that the quotes although they're not in a straight line anymore are at the end of each line add your second quote and then add a comma at the end and now this entire coding block has been changed to a giant string array very neatly and very quickly so now that i have my string array ready to go i'm going to copy and paste everything out of this file and it's going to go straight into my body array that i have in my typescript json and then i'm going to hit save and now i'm going to close the other file because i don't need it anymore you don't really have to save that and then i'm going to go to my book controller and test this out so let's go ahead and type in our crud controller and you when i hit enter you can see that first it wants me to edit the model name so i'm going to hit backspace and type in book next i'm going to hit tab and type in book with a lowercase i'm going to hit tab one more time and then i'm going to type in my title comma author and then hit save for the auto formatting and you can see that it has put everything in this file that i need and just like that my book controller is finished so now let's do the exact same for routes as we did for controllers create a book.ts in your routes folder copy everything inside of the author.ts file go to your typescript.json snippet file and let's go ahead and create a crudmongo routes definition the prefix for this is going to be you guessed it crudmongo routes and then we're going to put the body array and then we're going to open up a new file and do the exact same thing that we did for our controller and what i'm going to do is i'm going to find and replace the author with a capital a and that's going to be my number one model name just like i did before and then i'm going to do lowercase and do the number two variable name that i did before this one we don't need a third one because these are the only two things we have to change then i'm going to go to the top of the file at the beginning hit control alt my down arrow key put in my quotes hit end put in my quotes and my commas then i'm going to copy and then paste this into my typescript.json file just like i did before hit save and then i can get rid of this file and then go to my new file that i created for my book routes and type in chrome crowd routes and then start replacing my variable names here as i did for my controller and just like that i have everything ready to go for my books because there's nothing special about these routes so this works just fine i'm going to import my book routes inside of my server.ts file and similarly i'm going to define my routes below by using a forward slash books in my router.use function let's run nodemon one more time and you can see that the version key did crash it so i'm gonna go back and just erase that out of my model i don't need it because it's already set to truthy and now that i've done that you can see that it starts up at the bottom so let's go ahead and go to postman and start playing around with this you can see here when i run my books get an empty array shows up so i'm going to go ahead and create a book i'm going to call it i don't know gus's book call it whatever you want and then for the author i'm going to pass in the author id i have for mr gus dude down here and you can see that the book is created and you can see that the version variable is there now so you can play around with this and let's run a patch change the name and because we didn't change the route it's actually going to fail so let's change this to update first let's grab our book id and then put it here in our books update path and then you can see that it updated the book variable name so this seems to be working pretty well as well one more trick that we can do with mongoose is actually select how our data is returned to us so what we can do is when we're looking for the books instead of returning just an author id we can actually have mongoose populate that author id into the author name and we can also do things like remove certain fields and that's why i wanted to actually leave the version key to show you how to get rid of it in another way if you want to get rid of different variables so i'll just use the version key as an example go ahead and go to the read book function here and add a little populate block and just select author so that it will populate the author by the author id and then you can go ahead and add that to the read all as well and now if you wanted to actually get rid of a field you can use the select block and inside of it you pass in the field you want to get rid of with a minus sign in front that means to return not this field go ahead and add that to both the read book and read all blocks and then we can run nodemon and run our call again and see what happens you can see that now the author id actually populates into an author object and this works nicely wherever you're using interfaces from typescript because you're already going to have those defined for you so now that we have the heavy lifting of creating our controllers and our routes finished our basic functionality is complete so the next thing that we're going to want to do is validate any data coming in with our joy data validation library and what i mean by validate data is that any of the post patch or even delete in some cases if you're passing in data requests sometimes have a data payload and what you're going to want to do is validate that data to make sure that it's the data you're expecting so you don't want somebody inserting some malicious data into your database and then potentially compromising your security go ahead and go over to your middleware folder and create a new file called validateschema.ts at the top we're going to be importing joy and we're going to also import the object schema from joy i also want to import my next function response and request from express and then i want to declare my middleware function so we're going to export const our validate schema it's going to take one argument which is the schema of object schema and then inside of it we're going to return async and then pass in our express middleware so we're going to define it as we did inside of the controllers by defining our request response and next function inside of this we're going to add a try catch block inside of the try block we're going to await schema dot validate async we're going to pass in our request.body and then we're going to call the next function assuming that this passes inside of the error block or the catch block we're going to add our logging.error and then we're going to return a response of 422 and just return the error in case this fails underneath the function go ahead and export a con schemas and this is going to hold all of our schema definitions we're going to keep these schemas nice and simple let's start with our author schemas we're going to need them in two spots for our post and our patch where we post an object and update the object so inside of our author object go ahead and make a create object and this is going to be of joy.object and inside of the chevrons we're going to pass in our i author not the iauthor model because that's for the mango schema but just the i author i'm using it here because i defined them separately on purpose so i could use them to help with my validation inside of the function call open up another object and now start adding your keys for the author it's just the name and that's going to be a joy string that's required nice and easy i'm actually going to copy this and do the same thing for my update because i don't want to over complicate this at all therefore i'm just going to have them send the entire object that they want to update even if the keys are remaining the same now i'm going to do the same thing for my book i'm going to create and then for my author key i'm going to have a string but i'm going to use the regex block and i'm going to define this regex here a id is a mixture of alphanumeric characters that's always 24 characters long so this is how you enter the regex for that and then i'm going to add my title which is also just going to be of joystick required and you'll notice that my joy.object here has my ibook passed into it don't forget to copy and paste this for our update key as well now that we've done that we can start protecting our routes by going and altering our route files let's start off with the author what we're going to do is we're going to be protecting our post and patch routes so how we're going to do that is after our definition of the route we're going to call validate schema and then inside of the function we're going to pass in our schemas dot author dot create and then add a comma after copy and paste this throw this in the patch route as well and change the author.create to the author.update so now these routes need those specific keys to be defined the way they are in that joy schema file otherwise they won't work and we can do the same thing here in our book routes by calling the validate schema again but at this time calling our book.create and our book.update and just like that our routes should be protected now so let's open up nodemon and try this out so let's make a post request change this to gus's book and then go ahead and push it through it's going to say not found and that's because i had the update route here so let's change that to create and then you can see it creates properly for me at the bottom so let's go ahead and get rid of half this id and see if the red jack stops it and just like that you can see that this post request doesn't match the requirements because the regex is wrong so i'm not going to go through all the endpoints because it's all going to relatively work the same so the last thing that we're going to do is take a look at how to create a build for our project so very simply for our build all i'm going to do is open up the terminal and get bash and the reason that i'm using git bash is because i have that rmrf command if you're using powershell or command prompt please make sure you're removing the directories in the same way that they would do it and then i'm going to run npm run build and what you should see happen is that it attempts to remove a build folder if it's there and then run tsc which is our typescript compiler you should see a build folder show up on the left hand side here in your file explorer to test to see if this is running properly we can do an npm run start because it's going to try and run that server.js file let's just go to nodemon real quick and make sure that everything is running smoothly you see here when i run the ping it returns pong so everything is as it should be so mine is not running any tests that's pretty much it from start to finish for getting a brand new project up and running now that you have visual studio code snippets helping you out in whichever way you define your controllers your routes or any other files that you want to copy and paste easily it should be relatively simple and straightforward to continue cloning these files into new controllers at a much greater rate than you would by typing them out by hand now this is just for the express node framework for creating a restful api there are frameworks out there that help you create apis a little bit faster but if this is the method that you prefer to create apis i hope that this was a good starting point for you and showed you everything that you need to know to create one of these in under an hour that being said if you enjoyed this video please like and subscribe i really appreciate everybody's support and if you want to buy me a coffee please do so i'd appreciate it and it'll help me get you more videos faster alright guys thanks so much for tuning back in and we'll see in the next one [Music] you
Info
Channel: The Nerdy Canuck
Views: 55,036
Rating: undefined out of 5
Keywords: express, node, nodejs, mongo, mongodb, mongoose, typescript, logging, coding, tutorial, node17, dotenv, chalk, nodemon, ts-node
Id: 72_5_YuDCNA
Channel Id: undefined
Length: 49min 6sec (2946 seconds)
Published: Sun Feb 27 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.