MERN Recipe App with Authentication - Build & Deploy A React Intermediate Project

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys how's it going I'm back here with another video and today I decided to bring this video where I'm going to be showing to you guys how to build a recipe app with authentication using the Marin Tech stack at the end of the video I'm also going to be showing to you guys how to deploy and Host this application online so stick around to see this entire video if you want to check out the code all the code will be in the description I'm also going to demo it a little bit for you guys right now but this video is pretty long but I hope it teaches you guys a lot about myrn I've been wanting to bring a video like this for a while now so I'm excited for you guys to see this so keep in mind before we get into the video if you guys could leave a like And subscribe I would massively appreciate it it will help support the channel and yeah that's that's basically it really hope you guys enjoyed it so now let's get into the demo [Music] [Applause] [Music] [Applause] okay everyone so here is the demo of what we're going to be building so it is a recipe application and um I want to start out by saying that um don't mind the UI it doesn't really matter that's not the point of the video the point of the video is always is a functionality so obviously I spent little to no time doing the CSS in fact I'm not even going to show me writing the CSS because it will just take too long and it will take away the focus out of the the actual important things so if you still want to check out the CSS everything will be in the description but basically this is what we're building right it's a recipe app there's a bunch of recipes which I already created as you can see over here um and what happens is if you want to enter the website you need to log in or register so if I want to register I'll come over here and I'll put something like uh I don't know I'm just gonna create an account called Leo let's imagine the username was Leo one two three the password was Leo uh one two three four five something like that right I'll click register and it will say your registration should complete it now log in I can come over here and put Leo one two three then the password Leo one two three four five and I'll click login and you'll see that uh I've logged into my account I know I've logged in because um internally a lot of the like stuff is saved on the storage into their cookies but also because you can see it now says the button log out over here instead of the login and register uh link and if I were to close this right and I just open it again it would still be logged in it persists upon closing the tab or changing tabs or whatever so what happens is now that we've we've logged in we can even create a recipe so to create a recipe I just come over here I put the name of the recipe let's imagine I want to create the recipe for steak and fries um if you wanted to create something like that I would just come over here and put steak and fries then a description of it a piece of steak with a side of fries that's a horrible description but you get what I mean then we put the ingredients right I'm actually basing it off on this recipe over here I just found online so if I were I could just do this copy all the ingredients and to add more ingredients because it could be multiple ingredients right you just click on this button and it will the form will allow you to add as many ingredients as you want so I'll just copy this and put it over there um I'll just put the four I don't care that much it's just an example but you can you can get the point of what I'm doing right uh yeah I'll just put this ones and then for instructions you can just put the instructions I'll actually copy this instructions over here um and just paste them yeah as you can see then the URL for the image right so in this case over here we're not allowing to upload images although you could do something like this I just put the image URL because I thought it would make it more simple and it would work just as fine as if you were to upload and then for cooking time I have no idea how long this would take it says one hour and 30 minutes that's actually a lot of time for cooking a steak and Fry uh but I'll put 90 minutes over here which is the equivalent then when you're finished you'll click create recipe it will say recipe created and you'll see that now that recipe should appear over here as you can see it appears right but you also see that there's a page called saved recipes we haven't saved any recipes yet but if I were to for example save the California row you'll see now it says saved over here and the California row is in our saved one uh if I want to save the lasagna or banana bread too I don't know and let's try to save the steak and fries as well all of those will now be present inside of the saved recipes it's a very simple application but to be honest applications like this involve a lot of the stuff that are required for larger applications so you'll see it is a quite a bit of code and this video will be pretty long however it will help you understand a lot of how myrn works and how to implement projects using this Tech stack and the best part is at the end I'll show you guys how to deploy this application using hostinger okay everyone so before we start coding I'm gonna start the process for setting up the deployment for our app I'm just going to create an account on a hostinger and at the end of the video I'm going to show us deploying so this part is actually pretty quick but I just wanted to talk a little bit about hostinger because it is the platform that is sponsoring this video it is a really nice platform which allows you to deploy and host your applications on the internet I've used hostinger so many times in the past I've made videos where I used hostinger in the past and they've always been extremely reliable for me they have 24 hours support which is really good and I've mentioned this in the past because in the past I've deployed websites and had to deal with problems when I couldn't get support from while using other platforms so it is really nice that they have 24-hour support because you can resolve your issues really quickly in a world where there's users using your website it is important to maintain it up at all times it is also very affordable So like um we're gonna if you see over here you only pay 2.99 a month for a lot of stuff you get storage you get support you get a free domain and a free email you also get unlimited free SSL certificates and also you get the ability to host your entire application inside of hostinger so it's really cheap and they have an amazing price quality ratio which means you get a lot of quality out of this service for a very cheap price so like if you want to set up all we're going to do is we're going to click on add to cart over here for the web hosting plan then we're gonna go to our court and over here there's a lot of options right and you see all the perks that you get um on top of all these things over here you can pay different prices depending on how long you want to set up your your hosting I would indeed recommend setting up the 48 month one because it is technically the same price as setting up a whole year um with with hostinger however if you choose the 24 month one instead of the 48 month after that that year you'll have to pay a different price an increase in price to renew it for another year so if you're interested in maintaining this for a longer time you can save up to 432 dollars using this over here so we're going to click on this and then you have to create your account I already have an account so I won't be doing this so just either put your email address over here or connect with Facebook or Google then you can select your payment uh there's they have so many different options as you can see over here but the important part that I want to show you guys is that I actually have a coupon code so hostinger was really nice and they provided us with a coupon code called pager attack you'll see that if I apply this we now get a discount which is a pretty good discount and it's that's on top of already the discount that you're getting from this plan which is 78 so this is incredible and you just fill in your your information for payment and um you should pretty much be set so this is kind of how you set up hostinger it's really simple to set up after you're done with it you can log into your account and you can go into the hostinger dashboard so this is pretty much how the hostinger dashboard looks like um you might not already have other domains or stuff like I have already set up it's probably empty however you should pretty much see this part over here which says for you to clean your free domain because when you bought the hosting plan it comes with a free domain so you can set it up by going through this and we're going to do all of this at the end of the video but then we also have our premium web hosting which is pending setup and this will also be done at the end of the video so make sure you see your uh dashboard looking like this and yeah that's that's pretty much how you start setting up hostniger now let's get into coding our project okay everyone so let's start writing the code for this project you can see all I have over here is my vs code opened and I actually haven't created a project chat all I'm doing is I just created two folders inside of my project called client and server so the reason why we do this is when we have a full stack app you should probably be dividing your project into different directories one for the client and one for the server there's various different ways to organize it this way um however I like to have both of them open like this so I don't have to have different Windows of vs code open at the same time but you can do however way you want to do it but for me I'll just create a folder the separate folders like this and I'll put the react tab into the client and the node.js and express server into the server folder so as you can see I will navigate towards my client folder by doing CD client and over here I'll run yarn create react app and I put a dot so if you're using npm obviously just run npx create react app but I'm using yarn so it will start generating a create react App application inside of my client folder then I'll open up another terminal I'll change my directory to the server and we'll run the following commands we'll first run yarn init just like this it will ask us a bunch of questions we'll just press enter for all of them and it will say done what this did is it just created a package.json a very simple one as you can see but this package.json will change because now we're going to add a couple packages so what we want to add is we want to add first of all Express right then we probably want to add um course which is uh I'll explain what each Library does as we use them but it's a really important Library as well then we're gonna add the bcrypt library for password cryptography I believe or yeah for password hashing then we're gonna add uh the Json web token library and finally we're going to add Mongoose um and I'm gonna press enter so those are the actual dependencies we're going to be using in our server uh there's still one more dependency we need to install but this one is a Dev dependency so in order to install a Dev dependency using a yarn I'll just say yarn add dash dash Dev node one this is the dev dependency we want to install now you've seen all the packages are inside of our package.json and also our front end has been created we're not going to touch our front end for a bit we want to start out with our backend and that's what I usually recommend because the backend kinda a lot of people think the backend is serving the front end but I like to think it the other way which is the this front end is serving the back end the data and the logic all exists in the back end the front end is supposed to display or interact with that data so um we're going to be working with the backend first so what we want to do is uh we want to create a folder called The Source folder and inside of the source folder I want to create an index.js and this index.js is where our project will start so initially we have to set up uh our Express server inside of this file so how I'm going to do this is I'm going to start by importing Express from the express library now if you're familiar with node.js you might know that when you want to import stuff you might see a notation like this like columns to express equals to require Express something like this and this is fine this is actually the default Behavior node.jest if you want to import a file however when you're working with the front-end application you actually use the newer JavaScript notation which is the import Express from the express Library this is a notation and this works and either way works but the thing is if we want to use then more the newest notation which is this one over here we actually have to make a change into our package.json it's a very simple change all we do is over here or anywhere else that makes sense you just put a type and you put module just like this module and now it will allow us to use this notation which is great because I prefer this notation either way so we want to import Express from Express then we want to import uh course from the course library then we want to import Mongoose from the Mongoose library and what these libraries are is the following Express will be will serve as a framework to create our API so it is a big part of um of the modern stack because it is the express the E of mern and we're going to be using it to serve our front end co-create an API really simply with node.js course is a library that allows you to set up the rules between the communication between your front and your backend if you don't use cores over here you'll probably get an error when you try to make an API request from your react application to your um your your own server right and Mongoose is actually an arm for mongodb which is the database management system that we're going to be using inside of this project Mongoose will allow us to write Community like queries and Communications to um our database in a really simple away and it's one of the most famous mongodb arms out there so right over here we'll just put const app and set it equal to express to generate a version of our API then we can apply some middlewares that are going to be really useful inside of our application the first one is the express dot Json middleware which all it's going to do is whenever you get data from the front and from the from when you send data from the front end it will convert it into Json instead of every single request May recreate so it is important or else you won't be able to get data from your front end in a simple to understand way so then we're going to say app.use and we're going to put course this over here will solve you many issues when trying to make that API request from the front end this is basically all we're going to do with chords inside of this whole project but it is extremely important to have it over here then we're going to come over here and we're going to say app.listen with this all this does is basically tells our API to start and we're going to choose a port we have to choose a port for our API to run on I'm going to put 2001 because 3000 will be used by our front end and then we can put a callback function that will be called whenever the API is running all I'm going to put over here is a message saying server started just like this right now if I want to run this server I can just come over here and say node then write the path to our index.js file and you'll see that it'll say server started however uh we installed something called known one because what happens is if I make any changes into this code I'll have to kill the terminal and run this again but I don't want to do that I want every time I make any changes and I save the file for it to restart the server to demonstrate those changes so that's where node one comes into play with node one what I can do is I can come into our package.json over here and I can add a script um and I'll close this I'll can add a scripts tag over here and a script I can write is the start script so what this does is whenever I run yarn start inside of our terminal whatever I put over here will run as well so what I want to run is nodemon Source slash index.js which means that when I run yarn start you'll see that now Norman will run and it will start our server and the most important thing is if I make any changes into my server or even just save the file you'll see that every time I save it will restart the server automatically due to changes as you can see so this is basically the setup for our server now we have to start setting up our mongodb database so in order to set up your database you have to go to this link over here we're going to be using obviously mobile DB and they have a service called mongodb Atlas which is a cloud provided database that you can use right you can create databases and deploy them to their cloud service and the way we do this is we sign into our accounts I'm going to sign into mine so as you can see I just signed into mine and it will bring me to this dashboard over here so I already have databases right I already used my this thing over here to create databases so that's why it looks a little bit like this there are some already here but yours if this is your first time then maybe not so what I want to do is I want to first of all come over here and I want to create a new project right I'll click on new project then I'll give it a name so it's taking a bit it's my Wi-Fi however um it will load eventually as you can see it just loaded it will ask us to create a project so put a name over here I'll call it recipe app just like this then click next It'll ask us to choose the project owner I'm choosing me myself uh as the project owner but you can invite other people they'll have the same kind of permissions as you have so I'm going to click on create project because I'm not going to add anyone and it will start creating the project for us so when it's done you'll see this is what it's going to appear it's going to say create a database however there is a thing that we should do first which is this message that appears over here it says the current IP address not added because and you will not be able to connect to databases from this address what this means is initially you need to write a white list the the IP addresses that are going to have access to making requests to the database so if you're currently using your computer you or your internet wherever you are you want to add your current IP address so I'm just going to click on this button and it will automatically allow us to connect to this database as you can see so now what I want to do is I want to click on build a database and it will bring us to this part over here there's many options that you can choose but obviously for the purpose of this video we're going to choose the free option over here it is the worst out of the other options however it's still really good because especially for learning as a conservator it says for learning we're going to choose this one over here then it's going to ask us for a provider so what what does a provider mean well our database will be stored in one of these three Cloud providers right and depending on it it will actually have a different price AWS for me is the best option in my opinion is what I like the most and you can choose where your database will be will exist right so I want to choose the closest to me which is Oregon but you choose whichever one you think will be best you can see Oregon is the one that is one of the ones that they recommend because it is closer to me then you can put a name for your cluster again it says over here that you cannot change your name for the cluster after it's created I'm going to call it recipes like this it's just a name for your database then I'm going to click on create you'll see that it will have created our thing but it's also going to ask us for a username and a password so we can authenticate our connection so I'm going to actually change this over here the username I'm going to call it pager attack and the password I'm going to call it um something else but it has to be a strong password I'm going to try my no actually I'll try something that makes more sense but it's also a random random so I'm just gonna call it myrn password I'll even show you guys what I'm writing learn password at one two three I'll save this because it is important for me to save it and I'll keep it I don't know over here then I'm going to create the user hopefully it works uh it seems to have worked as you can see we added this user as a user that has access to this database then it's going to ask how we want to connect to it I'm going to um ignored for a moment but you can see it's asking us to either to put our IP addresses right but we already did this it's already over here so we don't have to worry about this now finally what we're going to do is we want to finish and close so I'm going to click on this I'm going to click on go to databases and we have set up our database so recipes is over here it is loading it but we currently don't have any connection to it inside of our code so how exactly are we gonna connect to it through our code well the way we do it is really simple we use Mongoose for this so somewhere over here after our middlewares are applied but before our app is listened to we're going to write Mongoose dot connect so this will generate a connection towards our server now the way we connect is we come over here we click on connect it will ask us it will give us a lot of options of how we want to connect the first thing we want to click is connect to your application we're going to click on this it's going to ask us the version or whatever but it's also going to give us this thing over here this link is what we're going to put inside of our code right over here and there's one thing we still have to do which is we have to replace this password field over here for our actual password now I recommend using environment variables if you're going to deploy this to GitHub but for Simplicity Reasons I'm just going to write the password that I created in front of you guys which is this one over here I'm going to save it um then I'm gonna put over here just like this and this should work as expected however there's also something important before this question mark over here we want to put the name of the database we want to specifically connect to in our case it is the recipes database so we'll copy this and we'll put it over here now I'm going to save this now we should have connected to our database um we can check to see how it says that it's broken let's see why actually I think I know what the error is I think the password we put um yeah I think the password we put can't have a an ad symbol like this so I'm gonna actually try to change it so the way we do this is we actually go to our database access over here click on edit and then for password I'm going to edit the password and I need to enter a new password I'm going to try the same password as before but without the the ads so something like this but without this at symbol over here yeah this password contains special characters which will be URL encoded so um I should have seen that but it's fine so I'm going to use this password instead and I'm gonna click update user hopefully works and I think it did so now I'll actually put this password over here and if we save this I hope it doesn't break yeah as you can see it's not breaking anymore which means that was the issue with our code all along so now it seems that we have access to our database but um we have no way to know this unless we actually start using it and making requests to our database so that's exactly what we want to do right now so the way we do this is by first creating what is known as a model inside of our code so a model would be a description of how um a table or um collection in our database would look like so instead of our source world over here we're going to create a folder called models and here we're going to create all the different collections also known as tables we're gonna have inside of the database so technically we're only going to have two but we're going to create the first one right now it's going to be the users collection so we're gonna have users inside of our project right so we have to tell mongodb how this user's collection will look like so inside of our users folder over here or this our users.js file over here we're going to import Mongoose from Mongoose just like this then none over here we're going to create a variable called user schema and set it equal to a new Mongoose dot schema now a schema is just an object that is going to define the structure of our data so what do we want to know from a user Well for now we only want to know two things right we just want to know their username which we can describe it as having a type of string and it should be required so required equal to true and it should be unique we don't want two people with the same username right so what we have over here is we're defining that we want our collection to have a username field and it has to be a string it has to be required so you won't be able to create a user without a username and it also has to be unique then we want to create a password field and for password it should be almost the same but we don't want it to be unique because people can have the same password it's it shouldn't it why wouldn't why wouldn't they be able to so this right here should be the definition of the user schema for now keep that in mind because we're actually going to change it later when we start dealing with recipes so what we do now is we want to create this thing called the user model which is going to be equal to a mongoose.model that is going to be generated based on that schema so why do we have to create a model when we already have a schema well because over here we're basically setting this schema to be a a collection and we give it a name so this is the name that is going to be uh called inside of our database it's going to be a table or collection called users whatever we put over here I want to call it real users so that's what I'm going to put over here and this user model is also what we're going to be using to make calls to this specific collection so I'm going to export this into our code I'm going to save this now I want to see if this actually worked right I want to see if this appeared inside of our database system over here so what I want to do is I want to actually connect my database to a program inside of my computer which is going to demonstrate the data in a simpler way uh compared to using this website for our from mongodb Atlas um right here right so it's actually better there's programs that they provide uh software that they provide to do stuff like this to see your database to maybe add data to do all of that without using their website one specific is the mongodb compass I recommend downloading this and I'll maybe put a link in the description if you want to it's going to facilitate a lot it's kind of like MySQL workbench if you're using MySQL I don't know if you guys used in the past but it's kind of like that but for mongodb so when you download this um you'll see it open over here and you can click on new connection and you can come over here back to your database click on connect and you'll see that they already have a simple connection mechanism to mongodb Compass all you do is you click on this copy this link over here paste it inside of the mongodb compass connection thing again put in your password so I'm going to put myrn um I forgot what the password was I'll go back over here it's burn password one two three so I just put it over here uh just right over here and I'll click on connect so now you can see we have um we have access to the actual mongodb Atlas project that we've connected over here and it only has two different databases as you can see it has an admin and a local I want you to ignore both of them because we're actually going to create a new database straight up from here now this database is going to be called whatever we put over here so we put recipes over here we'll just put the same over here so we're going to call recipes and we can add a collection as a default uh thing right they allow us to add a collection now the collection we basically already created right it's this thing over here I already defined its structure and everything but we haven't actually created it inside of our actual uh we hit it in cold but it's not connected to our actual database so what we do is we create it right now by copying this thing putting it over here and clicking on create database you'll see that now it'll say recipes and users and um now we have access to both of them so that's pretty good you'll see that now if I come over here to collections what we just created should be here as well right it's fully connected between all three parties and if we wanted to add data you'll see that now it will have this structure as well so let's start doing that so you guys can get a better idea of what I'm talking about so we created this folder called models for defining how our structure will look like our data will look like but we're going to create a folder called routes so that we can separate our API endpoints into different routes so we're going to have two routes actually in our project the first one is the user's route which is going to Encompass everything related to logging in and registering so inside of our users route what we want to do is we want to first of all import Express from Express right then we want to import some other stuff we want to import JWT from Json web token which we're going to be using inside of this file then import Big Crypt from Big Crypt which are we're also going to be using in this file then we need to set up this as a router so to do that we create a verbal code router and set it equal to Express dot router just like this and then at the end of this file we need to export this whole thing um as a router just like this we're going to export an object which is going to contain this router and we're going to change its name to uh user router so that because we're going to have more than one routers so we have to change its name to user router and now what we do is in our index.js we come here we import this thing from uh the file routes slash users and because we're using uh the import notation over here it is important that you actually import the files using dot JS at the end right using the extension or else you'll get an error then instead of this import statement we import user router and we can come over here and we just apply this router by saying app.use and we put in the route or the endpoint that we want to set this up with I'm going to call it auth and then we put in the user router so what we did here is we're just separating our code so that we can write endpoints with all the endpoints which are going to be related to authentication will exist inside of this file over here um and we're just applying this so that Express knows uh that is divided this way so now whatever endpoints we create over here they will automatically start with this thing over here the slash auth route so what we can do now is start creating the two routes which are going to exist over here the first one is a post request which is going to be for registering so we can put post slash register just like this and the second one is uh another post request but it's going to be for logging in so login just like this let's start off with the register one so this will be an asynchronous function we're going to put a callback function over here and each callback functions in Express have at least this two variables over here or arguments to this function a request variable and a response variable so the request variable is used for getting data from you from whoever made the API request to this endpoint and the response variable is used to send data to back to whoever made that API request so over here when we are running in the front end when we want to register an account right we want to register a user we're going to send in from the front end two pieces of information one of them is going to be the username and the other one is a password so when we make this API request in the front end we need to make sure that we send in the through the body of the request an object containing the username and a password right but so we're kind of assuming that in the front room we'll do that but this is how we Define endpoints in your API then what we want to do is we want to confirm that a user with this username exists so we're gonna do our first request to our mongodb database and I'll show you guys how this will work so we're going to say const user equals to a weight and we call the user model that we created so it automatically imported as you can see over here and don't forget to also put the JS because or else it won't work and then over here in our user model we're going to use this you can see there's a bunch of functions we can call with this user model so what we are doing here is we're calling we're making requests to this collection over here so the request we want to do is we want to find one user so there's this function called find one and you can pass over here some sort of field or specific search that you want to make so I want to find a user where the username of that user is equal to the username variable that we got over here obviously in JavaScript when the value and the key are the same you can shorten it to uh just be one word but this is kind of the logic that we are using over here also whenever you are making any con like requests to your database it should be it will return a promise so you can use your you can either use the dot then.catchnotation or you can use an async await notation like we're doing over here so right now actually all I want to do is I just want to give back this user so what we do is we say res for response dot Json meaning we're going to send back a Json uh and we're going to send back the user that we found so obviously this is not the whole API endpoint this is not how it's going to look at the end but I'm doing this right now so we can test it out and see if our API is running smoothly if it's all working and if our connection to our database is actually true but the thing is we currently don't have any users inside of our database so let's create a fake user right here to do this we can click on add data as you can see over here and we can click on insert document what this will do is it will give us this thing over here where it's kind of a Json and we can add fields to this so um I can come over here and add a field called username and we can put its value so I'm going to create the Patriotic user and I need to put obviously commas and we're going to put the password for this user as well let's put Pedro as a password I'm going to click insert and you'll see that now inside of our collection users there's a user with a username Pedro Tech and the password Pedro and also it also Auto generates an ID for this user you see that not only that but this data exists inside of our um inside of our actual database in the in the cloud as well you can see it appears over here so what I want to do now is I want to run this API call this endpoint over here and see if it will return back this user that we just created so to make this API request we can obviously create a front-end that is going to make that whole request or we can use some sort of API like testing software like Postman or insomnia to test this out and the one I like to use is insomnia you can download it in the description this is the software over here it's really simple to use you don't even have to pay or anything all you do is you click on new request by clicking on this button and choosing an HTTP request then you put the link to your API so the API obviously will be probably something like http uh localhost 3001 and since we are in the auth route we have to put slash auth and since we are going to make a request to the register endpoint we have to put slash register now this is a post request not a get request so we have to change it to a post request and we're not sending anything right now um actually we should we should send a username and password right so if I try to make this request right now you'll see it will say no because it couldn't find any users I hope with this with because we didn't send anything right but if I come right here right now I change this to be a Json right we're sending to a Json as the body and we put over here a username and we use pager attack and we put in a password and we put in whatever because the password actually doesn't matter because we didn't do anything with the password as you can see it is sending back the user with the username page attack meaning that our connection between our code and our database has been successfully uh established right so everything seems to be working which is perfect so let's continue writing the code for registering a user so one thing I want to preface this with is basically if this is your first time creating a register logging system this will all be confusing for you it just will be because it was for me and it was for everyone I've ever taught how to do something like this um I recommend just taking some time to look over the code understand every step and with time you'll understand but I'm just advising you that it might get a little bit confusing but don't worry I'll explain every step so what we're going to do now is we just search for a user in our database with the username sent from the front end right so now we want to check to see if if we return null or not because if it returned no so if there's if if the user um is already inside of the database right then you're trying to register with a user with a username that already exists which means that we don't want to continue trying to create another user we actually want to return and give a response dot Json with a message saying that this user already exists so what we're doing here is we're checking to we're trying we're getting the username that was sent from the front end uh we're checking to see if there's already a user with that username and if there is then we're returning we're ending this function over here and we're returning a Json with this message but if this pass if this check over here passes so we get to this part where we there there's no user with this username so it's good to go to create this user so what we do now is we use bigcrypt to Hash the password the reason why we want to Hash the password is because you see right now in our database it says that the password is Pedro right but this is extremely unsafe you should never have strings like plain texts as a password because if this leaks um it will become really easy for uh hackers to see the user's passwords so what you want to do is you want to Hash that password so I'm going to create over here variable called hashed password and when I set it equal to a weight bigcrypt dot hash so Big Crypt will be used for this for hashing passwords and we're going to put over here the password that we want to hash and we can put a number um this number it doesn't really matter for you to know what it means but it just influences the the hashing process of our password I'm going to put 10 because it's the default it's what I always put so I wouldn't worry that much about this but basically we just created a version of our password that is now hashed and this is where we're gonna actually send to our database now we want to add the user to our database so what we do is we create a variable called new user set it equal to new user model and just create the user with the two fields that we defined so the username field and the password field but the password we want to pass is not the password that we got over here it's actually the hashed password right hashed password so now this is how you actually add something to a database in in mongodb with Mongoose you just say new user model create this variable and then if you want to make the changes you just say new user dot save and this should create the user I'm also going to put in a weight over here now if this is successful we should actually just return back a message saying something like um I don't know like user registered successfully something like this um and then just save right so now let's test to see if everything over here is working I'll delete this user that we manually created because now we don't need to manually create over here we should be able to create users using our API so I'm going to put a password called Pedro at one two three and then send this request you'll see that it says user register successfully which I hope means that if I refresh this by clicking on find now we have a user with a username page attack but the password is completely hashed we can't make sense of this password because that's how it's supposed to be now let me try creating another user with the same username you'll see that now it should say that user already exists exists meaning that it won't allow us to do this so this is pretty great it means that our registration API endpoint is pretty much done so now we have to create the login endpoint the login is a little bit more complicated because it will involve some Json web token logic right because what happens is when you want to log into an application you want to create what is known as a token which is going to represent your login session then you want to send that back to the front end and whenever a user in the front end makes a request they need to prove that they are the original users that were logged in so they should send that token to the request and every time you make a request you should validate to see if they are the authenticated users that's a whole concept in in web dev that it's hard to understand in the beginning but I'm going to show you guys a simple implementation of how the this would work using Json web tokens and Mer so to create the login route we're going to do something similar to what we did over here we're gonna create an async callback function which is going to include a rack a res and pretty much just this then what we're gonna get from the front end is also pretty much the same right when you log in you should send in a username and a password then um we want to do something very similar again which is we'll try to find the user with uh this username just like this but this time the problem is not when we find a user so instead of saying if user we're going to say if not user because if we don't find a user it means that you try to log in with an account that doesn't exist or so we'll just say return res dot Json and say something like a message uh let me see message user doesn't exist something like this then over here we have to check to see if the user exists right you try to log in with the username that is in our database um that's fine but now we need to check to see if the password that you have matches the password that is on the database so what we do is we create this variable called is password valid and we're going to be using Big Crypt to determine this because Big Crypt uh you can't actually unhash a password that has been mashed so when you send the password like this right to the database we can actually never know what the password originally was because when you hash something you can't unhash it but what we can do to know if what your your inputting is the correct password is we can hash what you just inputted and if it's the same thing as this value over here then perfect it's it's the same password because the algorithm for hashing will always return the same value so that's why we use Big Crypt over here and a function they have called compare where we just put in the password we want to compare it with with the original password in the database which we can get by saying user.password because we just found the user with this username and we want to compare it to the user with this username right so if it is valid this should become true if it's not it should become false so if it is valid or if it's not valid actually if password if is password is not true then again we want to end this request right here by saying res.json and the message will be um username or password is incorrect something like this and then if it is valid so you're correctly logging in now is where we start the process for logging in with the correct information so we first create a token by saying const token is equal to JWT DOT sign and this is how we create a token using Json web tokens right we have this um we have this GWT thing we imported at the top so now we are using it by saying jwt.sign and when you sign you can actually sign some data what I'm going to assign is the ID of the user by saying ID is equal to user dot under slash ID then I need to put a secret for this token so our our token will be basically a string of numbers and letters uh that makes no sense but can be converted into this object over here so this piece of data and this secret over here is really important because it should be used uh whenever you want to un unsign or it's not unsigned but verify if uh the user is really authenticated you need to use it right so whenever you use it when we're trying to verify that we need to use the same secret we put over here but for Simplicity reasons in this video I'm just going to show you guys a secret it's literally the word secret but I recommend you creating an environment variable and using it over here so now that we created a token what we want to do is we want to end this request by seeing res.json and sending back the token that we just created and also I want to send back the user ID so that we can store it inside of our project so I'm going to say user dot under slash ID and yeah this this should be fine so I'm gonna save this right here and um let's test to see if the login functionality is working I'll create another request over here similar to this one I'm going to copy this paste it over here but instead of being register we're going to have the login thing over here then this is also a post request and it should be accepting Json now I'm going to copy this and paste it over here and we'll try to log in with the incorrect password I'll just write something that is wrong you'll see that it should say username or password is incorrect but if I try logging in with uh the correct password it should return back a token and our user ID now let's try logging in with a user that doesn't even is not even registered into an account it'll say user doesn't exist which means that everything seems to be working pretty smoothly and this also means that pretty much our user functionality is done because like we we just finished the the whole functionality of logging in and registering now to keep you guys engaged I don't think I should finish the entire back end um before going into the front end because I feel like a lot of what we can we're going to be creating might not be registering in your in your heads because you're not seeing a visual representation of what we're creating in our backend so what I like to do is I start out creating the backend but I start out by creating a post version of the back end which in our case is the login and registration because you guys are probably used to seeing logging like this kind of stuff in websites right so now that we've done this I'm gonna go and start creating the react front end that communicates with this and when the user in the front end isn't able to register and login we're going to write a little bit of the front end for um the recipe part and then come back to create the API for that so I think this process will maintain you guys as engaged as prob as as possible because it will keep you guys uh learning different stuffs and not become very monotone so like just working on the back end for a long time and then go to the front end and just working on the front end right I think this is a better process to teach you guys this so if you want to start working with your front end let's close all of this stuff over here and let's open up the client folder inside of our project I'm going to delete some files that already come with react because all I have right now is the simple create react tab I can run this app by going to my client terminal and running yarn start and it will generate it will open up inside of my browser as you can see and obviously will come with the boilerplate from create react app however we're going to delete some stuff so like we're going to delete this setup test file the report web vitals file the logo the index.css and the app.test.js so we're moving everything from to trash because we're not going to be using them I'm going to delete the instances where they are being called or used in our project and in their app.js let's start from zero just like this and as you can see we just have an empty page okay so one of the first things I want to do is install some of the packages we're going to be using inside of our client so inside of our react application I'm going to open up another terminal this one will be used to install packages then I'm going to CD into my client folder and I'm gonna run yarn add um or if you're using npm it's npm install and we're going to install the following packages so we're going to install react uh router Dom which will be used to create routes and different pages inside of our website then I'm gonna install axios for fetching data and finally I'm gonna install react cookie for um for dealing with cookies in react right so I'm going to press enter it's going to start installing everything and what I want to do is I want to start everything by setting up our route system inside of um inside of our app.js so at the top over here I'm going to import some stuff from react rather Dom so what I'm going to import is first of all the browser router and we're going to change its name to router and then we're going to import the routes component and the route component so if you're familiar with reactoradon this should be pretty self-explanatory all of them have their own purposes the way we structure it is basically we Define first our router to determine where in our app we're going to have routes it's all going to be inside of the app div then we're going to create over here uh the routes component and wrap all of our individual routes with this inside of the routes component so in our routes what we're going to Define is we're going to find a path for it and the first one will be for the home page so I'm going to Define an empty slash as the like the the URL of the website is the default route then we're going to put an element over here and the element is just the component which is going to be rendered when you go to this path so the component we want to render is the we haven't created it yet but we're gonna create a folder over here called Pages just like this and a set of pages we're going to have the three different pages we're going to have in our app actually it probably will be four pages because we need the authentication page as well so let's create some of them let's create the home.js which will be a page for the home component then let's com create one for the authentication which is going to be for registering and logging in then let's do it for the the create a recipe page so create recipe.js and let's put one for the saved recipes.js just like this now to Define this components all you have to do is just say export const home for the home component and return some sort of UI specify something about this component so for the home page for now we'll just render the div with the text home now we'll copy this and do it for each one of this as well but change the name of the components and what we write over here and we're just initially creating the the first image of each component right so the create recipe and we'll do the same for create recipe and finally for saved recipes we'll do the same so recipes just like this saved recipes now that we created all of our Pages at least the beginning of it we'll close these tabs and we'll import them over here at the top we can automatically import them by trying to for example for the home page I'll just say that the home component will be used over here and they should have an import but they actually don't so we'll just do this and we'll import the home component like this dot slash Pages slash home and we'll import the home component now we'll do the same for the other routes we'll have four routes so we can just paste four of these routes we'll make one for the um authentication and this will be the auth component um then this will be for the create recipe and this will be the create recipe component and finally this will be for saved recipes so we'll go for the saved recipes component we'll have to obviously change and import all of those over here we'll change this to auth this to create recipe and this to saved recipes and then we'll change this to auth the same thing right create recipe it's kind of uh repetitive but you guys get the point so saved recipes now our app should have some routes so we're in the default URL so it's showing the home page but if I go to the um auth for example it should show auth if I go to the create recipe it should show create recipe so our routing system seems to be working now that we have our routing system done we have to have the functionality to be able to navigate between the routes so obviously we can change our URL normally like where we've been doing however every website must have a navbar if you're going to have multiple routes so we're gonna be creating that right now so to create the navbar we're going to create another folder over here which is going to be used for uh whenever we want to add components that are not pages right so a component like a navbar component would be applicable over here so we're going to write over here navbore dot GS and we're gonna create the navbro component so export const navbar is equal to this function so how we're going to do this is as follows we're going to first of all uh return a div which will have a class name of um navbar then inside of here we're going to set up all of our links that are going to be used inside of our routes so I'm going to import over here the top from react router Dom and I want to import the link component just like this then I want to set up first the link to the home page so I'll just write a link like this and wrap it around with the text that is going to be used for the URL so home will be what the link text so we'll just put over here a prop called two and this is where you put where you want to navigate when you click on the link so I'm going to navigate to the home page whenever I click on the home link then we're going to do the exact same thing for all of the other links which for now will be just four uh we're gonna do again the auth actually I'll put the create recipe here and then create recipe I wrote it wrong so create recipe then we're going to put over here this saved recipes one and saved recipes and then finally we'll do the auth and we'll write here probably something like login slash register now we'll save this and import this over here so we'll import from dot slash component slash navbar and we'll import the navbar component and we have to put it above the routes component but below the router the reason for that is because inside of the routes you should only put routes right like the definition of routes but if you put the network above the router component it won't be able to use components from react to other Dom such as the link component so we have this perfect space in between them to put the network component so I'll put this right like this and you'll see that now we have our beautiful nav bar right and it does look ugly but don't worry like I said all the CSS will come with time in fact I'm actually going to paste all the CSS that I wrote for this code already just in case while we we put in uh class names and stuff it will automatically show the UI for you again like I said I'm not going to show me writing CSS like I never do this in my videos because I find it a waste of time when the focus of the video is not CSS but if you guys want to use this CSS it's really simple and ugly if you guys want to use it just check the link in the description or just copy what I'm showing you guys right here so enough of CSS for the rest of the video this is how the UI is looking right now so what we do now is we basically have our nav board done so we have to choose which page we want to start working on now in order to do anything on our app we pretty much want to be authenticated so let's start with the auth um component not to mention we only wrote The backend for logging in and registering so it makes sense to start with the other component so over here in our div we'll have a class name of auth just to Define our auth page then inside over here we're gonna actually call two components we're gonna make two separate components one for logging in and one for registering just like this register we obviously haven't created them yet but we're going to create them right now now you might argue that since they are external components we should probably put them on the components folder but for Simplicity reasons I just want to put the components folder components that are shared between different pages or that is useful for the whole app so this too are only useful for the auth page so I will actually create them all inside of the same file I'll create the login component over here and I'll create I'll just return something I'll create the register one over here as well I want to have a page with both of them like you guys saw in the beginning of the video now to start off let's work with the register right because you want to be able to register first to then be able to log in so for the register we want to have a div we're going to give a class name of auth container then inside of this div we want to have a form because it's the form for registry now instead of a form we want to have a couple of stuff so I want to have a little h2 tag over here which will say this is the register part of or the registration part of the the page then you want to have a div which and this is just for organization purposes and UI purposes I want to get a div with the class name of form Group which I already assigned in my CSS file now instead of this div I want to put in a label and the label will be representative of the username field now when you have a label that is representing a field you have to put in the html4 tag to to tell your UI that this label is referring to the input with the name call or the ID called um username so we're going to come over here we're going to put an input and this input will be of type text just like this text and we want to give an idea of username to match the one for the label then we're going to give an unchange to this but obviously we currently don't have um any states that are going to be representing this input we're going to create that in a second but before we do that I want to leave this like this just close in this div and create the same thing but for the password because we just created one for the username but we'll create one for the password like this and now it should pretty much be done right so now we are in track for creating our states that are going to represent the registration and password um input Fields right so how do we do this well over here at the top we're going to say const equals to use state which when we press enter it's going to automatically import this from react then this will be a string we're going to create one for the username and you have it is a function called set username and we'll do the same thing for the password so we'll create one for the password and set password then over here we're going to uh copy the site username and just whenever there's any changes in our input we're going to set the username equal to the event.target.value which basically means that we're setting the username state to be equal to the value of the field every time there's any changes in the field which makes sense right then we're going to do the exact same thing with the password one but change this to set password I also want to set the values of the input to their own States so this will be username and this will be password now basically what what's happening is we have if we go to the login and register we should see one input field with uh no one form group with a for registration and if you have a username and a password and as I'm typing on this it's actually saving the values of what I type into this two states over here which will then send this data to our API to actually register now the UI for this is almost pretty much done all we have to do is below this div we'll put a button uh of type uh submit but we're gonna call it register and give the type A submit because when you submit the form uh this but when you click on this button it will submit the form so now we pretty much finished the register we'll do the exact same thing for the login but the only difference is that the logic and API requests that we make while handling the data will be a little bit different so technically what I think would be good would be to actually uh copy this paste it over here uh obviously change this to login so the components are pretty much the same the only difference is that I'm gonna actually create over here at the bottom a form uh components I'm going to say const form equals to this function and it's going to take in two different props what is going to be the username and set username it's actually Four props but two groups and the second one is the password and set password right and what I'm going to do is I'm going to copy all of this UI logic over here and just return this right so why am I doing this well because when I return this uh right here at the bottom we're going to save on uh having to copy code we can just actually come over here replace all of this stuff with returning the form component keep the actual register and logging components with the purpose of just handling the logic so for the form component we'll pass in the username and the username like this as a prop then the same thing for set username we'll pass in as props and the same thing for password we'll pass in as props and for set password now this is a very simple simplified version of what we're doing over here we're keeping our register components to be uh purely for logic so over here we'll put the API request and everything like that and we created this form component which we now we can use it both on the register and also on the login component just like this so you see the components are pretty much the same but what's going to change is what we the logic we write in between over here and the form will be reused how many times we want because we are using props to differentiate them which is pretty good now you can see that we have two forms one for register and one for login I just realized since we put the register label over here uh inside of the form uh it's going to say register for both one way to change this is we can actually put another prop over here called uh label and we pass in the label over here as register and the label over here as login and now what changes is the fact that we'll use this label to display the texts so we'll display that and we'll display this and you'll see that now they're different this is for login it says login and this is for register it says register one thing important to understand why we're separating them is because the username Fields over here and the username Fields over here shouldn't be the same value which they should be different that's why we're separating them now it's time to start making our first API requests to our own API so what we want to do is let's start with the register we're going to have a function that we're going to pass into our form called the handle submit function now this function will pass in as props so let's call it handle submit or on submit actually it's better on submit and this function is going to be called whenever you submit the form so over here we're gonna put in the on submit prop and then just pass in the on submit prop that we're passing through our form now over here in our register we can pass this in and uh create the on submit for our register so const on submit is just a normal function but it's also going to be a asynchronous function so a sink over here now we want to uh use axes for this to work right we also want to get the event over here to say that we don't want to we want to prevent default in order for whenever we submit the the form it won't like uh refresh the page so we'll just say event dot prevent default like this and what we want to do is we want to use axis to send a post request to our API so I'm going to import all all over here I'm going to import axis from axis and if you're not familiar with axis it's actually a pretty simple Library just a replacement from the for the fetch API in my opinion it's easier to handle in more complex projects I don't use either of them I use um actually I use fetch but I I use different types of fetching libraries but for this project we're just using axis because it's going to be as simple as possible so we're gonna try catch uh because we're going to use an await so we need to do try catch or you can use promises as well if you're if you're if you prefer that but what we're going to try is we're going to try to uh await uh axus.post request now for the Post request we need to put over here the URL for our API so open up our insomnia and I'm going to open up for the registration one copy this and paste it over here now the way you structure this is you make the post request you put the URL and then right over here you pass in an object that is going to be the object for the body of the request so if we recall in our API over here when we handle the registration request we assume that in the front end we're going to send in a username and a password so this is exactly what we have to send in over here we'll have to send in an object with a username and a password which is exactly what we have over here so in case this works we're gonna alert a message saying registration completed then now you have to log in because you just registered the user you didn't actually lugged them in if there's any error uh we're gonna keep it simple I'm just gonna I just want to see as the developer I want to see the error so I'm going to console log the error or concert console error the error because this actually will make the the text red in the in your console but this is pretty much it for the registration it's really simple uh this is all that we want we just want to try to make this request and we can try this out right we'll open up our mongodb Compass over here we'll try to find to see if there's how many documents are here we see there's only one user Pedro Tech but now let's try to create a user with a different username I'll try to create one called um I don't know check Dr I don't know why though that was autocompleted the password will be password uh oh I just realized the password field is not an actual password field uh I should change that I'll change this to be from input text to input password and now you see it's a password field but basically if we click register it should say registration completed so no errors occurred and we should find that this user should be over here which they are which means that we finally were able to set up a clear connection between our front end and our API so now we are pretty much done with her registration let's start working with the login now for the login it's a little bit harder because uh we're gonna have some stuff to deal with we need to authenticate all the kind of stuff and to do that we're going to come over here we're going to create the on submit for the login so const on submit similar to the registration one again this has to be async and we're going to just pass the on submit as a prop to the form like this now we have to grab the event again and say event dot prevent default and now over here we're gonna set up our try and catch right so far it's pretty much the same thing as before uh we'll even already console dot error the error but in the tries where stuff starts to get interesting we're gonna try to make a post request similar to the registration one but the difference is now we care what we get back from this request in the registration one we're not really it doesn't really matter what we get back because I don't think we even send anything from this request um we just try to create the user so we don't we're not expecting the API to send anything back really um but over here we are because if you recall we send back our authentication token so over here I'll do the same thing as we did before but right in the await I'm gonna grab the response from this request just like this this response should receive everything that is sent back from the API not to mention this should change to login and also uh this is the structure between the login and registration routes are pretty much the same we're also sending the username and password from this component now when you get the the response back we can take a look to see how it will look right but pretty much what it will look like is just the token right the token that um we're sending the the JWT that we're sending from the backend so what I want to do with that is I actually want to set the token into our cookies so to do that we have to come over here at the top and import a hook from the react cookie Library this Hook is going to be called use cookies and to set it up we'll just come over here inside of our login component and call the use cookies hook like this Define the name of our cookie that we want to create which in our case will be called access token and then over here we're going to uh we actually don't need to have access to a cookie we only have to we only need to have access to the function that sets a cookie so we're going to grab the set cookies function and we'll use it right over here um to set the response that we get back from the API as our Cookie by basically saying that we want to set the access token cookie to have a value of response dot data dot token because if we go to our routes over here you'll see that in the login we sent back a Json which is an object containing a token field and a user ID field so that's pretty much what we're doing over here now now that we're setting the the cookie to have that value we also want to store our user ID that we're sending back inside of our local storage for quick access to it so I'll say I want to get the window.localstorage.set item and we want to set a user ID item to have a value of the response dot data dot user ID like this and finally what I want to happen when you log in is I want to be redirected to our home page right so there's multiple ways of doing this you can actually just say something like window.location I think it's window.location.pathname something like that and set the path but I'm keeping track of the location using react water Dom so let's import something from react order Dom which I recommend using if you're using reactor Dom for navigation let's import the use navigate hook this Hook is pretty simple whenever you want to redirect yourself based on like on command you just call this hook like this uh navigate equal to use navigate and now this over here is a function that when you call it it will navigate and redirect you to whichever path you put inside of this quotes over here which in our case is just a home page so it's an empty slash so this code should be working let's test it out we'll open up our inspect element we'll go to application you see that in our local storage there's nothing here but if I try to log in with our um I'll try to log in with check the organ you see that we are redirected to our home page which means that it probably worked and also with a good application now our user ID is uh inside of our local storage which should match the user ID of Jack uh yeah it does match as you can see over here so the login functionality seems to be working which is pretty good but one thing really quick that I want to fix is the fact that uh we're logged in but the login and register thing over here still appears we actually want to whenever you're logged in replace this with a button that when you click will log you out so to do that it's pretty simple we actually come over here to our code we just go to our nav bar right over here and inside of our links over here we want to have access to our access token cookie because as long as we have a token then it pretty much means that we are authenticated right we're logged in um obviously there's more checks that we can put like we can check to see if it is this if the token is the same token and we in the real website you should probably do this but for Simplicity reasons we're gonna actually just check to see if the token exists so to do that we'll import similar to what we've done so far we'll import from the react cookie Library and we want to import the use cookies hook again we're just gonna set it like this use cookies we want the one with the access token which is the one we created and over here we're going to grab the cookies this time and also we might wanna in the future inside of this component uh alter the cookie so we'll grab both things from the hook but the most important one right now is the cookies one because what we want to check is okay if there is no cookies dot auth access token it means that you're not logged in so we should actually show the link for logging in but if there is an access token it means that you are already logged in so we should actually display a button saying log out like this you'll see that this is exactly what happens because we are logged in but when I click on it nothing happens now the logout functionality will be pretty simple all we do is we come over here we create a function called logout and we pretty much just need to clear our tracks like we need to reset the cookies uh to be in to be empty so we'll set the access token to be an empty cookie like this uh then we probably want to clear our local storage from our user ID so I'll remove the item called user ID like this and we probably want to navigate to uh uh to our authentication page because you're just logged out so when you click on the logout you should probably want to log in again so we'll do uh this thing where we're gonna just call the use navigate again this then just like we've just done it we'll just call the navigate function and then use navigate hook and we'll just navigate to the auth page so let's check this out we are logged in we can refresh the page it's always logged in but when I click on this button uh nothing seems to work oh I know why actually I know I'm sorry I didn't I never set this function to be called when you click on the button now it should work so I'll refresh this click log out we're back in our auth page and we don't have the logout button anymore so our front end for this seems to be working perfectly which is amazing okay so now I actually think it would be better for me to start working on the API for the recipes part of the app because now we've done registration we've done the backing in the front end I think actually you guys trying to get an idea of how both the backend and the front end are connected so it would be good to just start creating the API for this and then come back to the react part of it so let's open up our Visual Studio code um let's close our client over here and let's open up our um backend right so we've created our model for users and our routes for users but now we have a different type of data we want to keep track of rest recipes right a user should be able to create a recipe she'll be able to save a recipe see the recipes all of that stuff so for that we need to create a new model called recipes so uh I'll actually create a new file over here let's call it recipes dot Jes so inside of this file it's very similar to what we've done so far we're going to import a mongoose from the Mongoose library and if you recall this is how we structure our schemas right I'm going to copy this so that we can we can save time writing um it's going to be very similar the difference is this is going to be called a recipe schema and um then this over here obviously we're going to change this the data inside of it but this will be called recipe model and this over here is the name of our schema right inside of our mongodb we have currently the users one we want to create one called recipe or recipes right I just realized since the database is called the recipes that's actually a horrible name for it I apologize because the name of the collection will be recipes this probably should have been called something like a recipes app or something like that however there's no point changing now let's just keep it like that we'll just have a collection with the same name as a database so over here we're going to call it recipes like this and we're going to pass in our recipe schema now how are we going to structure this data well the way we do this is we want each recipe to have um first of all the name of the the item right the food that you're going to create a recipe for and it will have a type of string and it will also be required right you need you need this in order to to create a recipe now we also want uh to keep track of the ingredients but the thing with ingredients is that um it should be of type string right because each ingredient is of type string and it again needs to be required because to make a recipe you need the ingredients but if you recall it's ingredients meaning that it's multiple of them you can have multiple ingredients inside of a recipe so to make this represent an array of type string we just wrap this around with um some square brackets and now mongodb will know that this is an array of strings then we need instructions our instruction um it will be again of type it's string and required be equal to true then we're going to have an image URL so an image for the food it would be of type string I'm just going to copy this um because a lot of the stuff is just strings um but then we have the cooking time right cooking time how long it takes to cook it this one will be a little bit different because the type will be number not whatever this is now finally we need to um make the setup a reference between um this a recipe and the user who created the recipe we need to keep track of the user who created the recipe so to do that we're going to come over here and say user owner this would be a fuel dinner recipe schema which is going to refer to the idea of the user who um created this recipe the way we structure this is pretty simple we just say that the type of this will actually be of type Mongoose dot schema dot types so you can actually get the mongodb types or the Mongoose types by accessing it like this and there's a lot of types that you can manually input and we could have done it for Strings and numbers as well instead of just writing string but I finally I find that writing string a number like this it's way easier than writing this whole thing the problem is that with ID since user owner would be the ID of the user we should refer it to this specific type because it is the type that usually exists for IDs as you can see in mongodb so this is the type we also want to say that this um oh I don't know how I opened that so we can also say that this makes a reference to the user's table right and finally we want to say that this is required just like this so now we're pretty much done with our recipe schema if we check over here let me try reloading this to see if um it will already appear I don't think it will uh yeah it didn't appear but pretty much oh yeah because we haven't used it but pretty much this as you can see we created our schema so how do we what do we do now well we basically create a route file for our recipes so I'll create recipes.js and inside of here we import the model that we just created so recipe model I just wrote it because it will automatically import and don't forget since we changed the type for this backend to module uh we need to come over here and put the dot JS or else it won't work so now that we've done this we can start creating our recipes route so what we do is we import Express from Express like this then we need to import Mongoose as well so import Mongoose from Mongoose then we know that we have the recipe model so for now that should be fine so we will first create our router so router equals to express.router and right at the end like we've done before we're just gonna export this thing but we're going to export this router with a different name we're going to call it um let's call it recipe router like this now in our index.js we're going to import this by saying by just copying this and changing this to recipes and this to recipe router should be recipes router actually makes more sense keep it uh keep it the same and then we're just gonna apply this like this and we're going to change the route for our recipes route to be recipes and this should be recipes router like this now um we should come to our recipes file over here and we're going to press enter and we're going to set up first the first route that we're going to set up is just a get or like a get route which will be an API request which is just going to return all of the recipes that it can find inside of the database this is what we're going to call inside of the home page because the homepage we want to see all the recipes in our database just displayed normally so the way we do this is by making an API request a get request to uh to this specific route and similar to how we did the previous routes file we're going to make this an asynchronous function it'll have a rack and a res and the Callback function will be pretty simple we're going to have a try catch right as you guys might already be familiar with um again an error over here uh the error if there's any errors we're just going to return a Json with the error like this but if we don't have any errors we want to um make an API request by saying cost response equals to a weight and the way we get the data from a specific model or a specific collection is we grab this model this collection we say dot find and we put over here an empty um object right well this empty object means is you can actually find based on specific fields and you can put those conditions inside of here but since we have no conditions of what we want to find in the recipes collection we just want to find all of them this should return all of the all of the documents in that collection so all that will be stored inside of this response variable over here which can then uh we just can just send it back to our front end by saying res dot Json response now we don't have any current recipes in our database right we haven't created anything um so it doesn't make sense for us to call that right now uh it will make more sense when we create a new recipe so let's write the route to create a new recipe so we can test all of this up so it would be a post request because we're kind of creating something so post is used for that and what we want to do is we want to change this we'll just keep it the same right the the post actually we'll keep it the same because when you're making a post request to the recipes route it makes sense that it is expected that you're creating a new recipe now all this should remain the same even the dot catch in the try so we want to come over here and we want to create a value called recipe similar to what we did with the users remember when we're adding a new user in the register one we need to create a new instance of that model so not here actually it's it's here we need to create a new instance of that model so that's what we're doing we're creating a new recipe so constant recipe B is equal to new recipe model and what we put over here is the structure of the data of how that model will look like so technically we're going to get all of the information so like the the name the image URL the the ingredients the instruction the cooking time everything from the body we're going to send all that from the body of this request so we can just um put over here saying that this object will basically just be the request.body with this little location over here just means that um we're setting this object to have the fields of this object over here however um it doesn't make sense to do it this way we can actually just close this and just say that the recipe model will have the rack.body just like this right and this should work perfectly now what we want to do is we want to try to await a recipe model actually not recipe model we'll just say recipe the one that we just created dot save and if it works out then we should uh probably just return back whatever uh we get back from this right which shouldn't be anything I think we just actually let's just return the recipe makes sense right um and we don't even need to get any response because I don't think it will provide us with anything useful so what we can do now um actually let's just return the response yeah I think will be the same thing but uh with the ID from the item created already so this is our post request and it seems pretty simple right so let's try reloading this um we're gonna for the first time try to make a request to create a recipe so we'll create a new request here in insomnia we're going to copy all of this and put it over here now it's in the recipe route so instead of auth we're gonna put recipes slash actually we don't need to put any slash because uh it's just a post request right we just put an empty slash and I think it is recipes right yeah that's right so now what we have to do is we come over here we change this to um a Json and we need to put in some data so first we need to put in uh the name right so let's write name and the name of this recipe that we're creating a fake one let's just call it steak just to keep it simple so we're putting the recipe for a steak now we need a description right did I even put description in the in this data in the model let me check um I don't think I did so yeah let's not put description then yeah let's not put description so I'm gonna save this over here remove this then over here we're just going to put um ingredients now what ingredients do we need for steak since it's steak and it's simple we just need three things probably meat or beef actually then uh salt and then pepper something like this right then what we need is the instructions so we'll create some fake instructions we'll just say something like cook at medium at high heat and then baste it I don't know uh then for the image URL I'm going to get a URL for this image real quick and be back in a second actually I decided to put everything already so I didn't have to you guys didn't have to see me doing all of this but basically I put the image URL for a random picture of a stake and I put the cooking time to 30 and I put the ID for the ID of the user Jack um and let's test to see if this will work so I'll click on the button and you see it says couldn't connect to server so maybe there's an error and it's good that there's errors because I always like to to show you guys um how to fix this kind of stuff so it seems like it is something related to importing uh incorrectly so let's see so uh yeah I forgot to put the dot JS over here so I'm going to save this you'll see now there's no errors so let's try making the request again I'm going to click Send and you see that it seems like it worked perfectly now the only way to check this is actually checking out our database I'm going to reload the data and you see that now we have a recipes collection because we finally made connection like we we established a connection between our code with our database and this specific collection that we just created more importantly we see that the data that we just tried to create is over here so we're properly inserting it into this collection so this route seems to be working perfectly now there's another route which we already created which we can test so the recipes right over here the get one and the way we test it is by just probably just changing this to get I don't want to create a whole new thing this over here wouldn't matter actually I will create another one just for so I can keep the Json there intact so I'm just going to copy this paste it over here and send this and you you'll see that we do get all of the recipes currently in our thing which is just one but we do get them so two of our routes for recipes seems to be working so now the route that we want to create is the one that will allow us to save a recipe and this route specifically is interesting because uh we're gonna make some changes to one of our models um we're going to start off by just copying this and adding over here a post request to save a recipe actually you know what I'm going to do I'm just going to make this a put request and not put any routes over here then what we want to do is we're going to delete this over here we actually want to get from the body of this request we're going to get two things we're going to get the user ID and the recipe ID so what we want is we want people to save a recipe now how we're going to do this is by changing the model of our users to include a field called saved recipes and that field will be an array of recipes that you saved so if you want to do that we have to come to our users model over here and we're going to add another field this one's going to be called saved recipes and we're gonna make it into an array of type string like this actually the type will be probably it's better to be Mongoose dot schema dot types um it has to be capital T types dot object ID right because it's a list of IDs and we're going to make a reference to um the recipes table so now we have this field inside of our users and what we can do is over here we're going to get both the user ID and the recipe ID we're using the user ID to find which user we want to change their saved recipes field and we're gonna get the recipe ID to insert into that array so to do that we're going to first get the recipe so we're gonna we're gonna do cost recipe is equal to a weight um recipes model um dot find by ID and we're going to put the erect.body dot recipe ID so we're finding the recipe that we want to save then we're doing the exact same thing but with the user we're going to find the user who's saving the the specific recipe and for that we need to have access to the user model so we import that over here at the top and then over here we put the rack.body dot user ID just like this now we have both the recipes and the users so we're going to put inside of the try um and what we want to do in this case is after this we want to grab the user Dot save the recipes dot push because we're adding to the end of the saved recipes from the specific user we want to add the recipe just like this we want to save this user so we're going to say awaituser.safe meaning that we're going to save the changes into our collection at the end we can just return back the saved recipes like this save your recipes is equal to user dot saved recipes and we're going to get back on the front end really simply now this is pretty much it for this route we can actually test this out if we wanted to by coming over here and doing the whole process but I trust that it will work if anything in the front end we can see if there's any mistakes and check back I just don't want to waste time always going to insomnia and adding more requests so now we just need two more routes inside of this um inside of this section there are two related to the saved recipes and related to getting the saved recipes in the front end we want to get a list of all the recipe IDs that the user who's logged into at the moment have saved so um to do that we need to make a specific route that is going to get the IDS that were saved by a user given us a user ID so we're going to call this route saved recipes and we're gonna put probably like IDs over here so signify that we're getting IDs from the Save to recipes and then we're going to create the async rec res and then create the function and then we're going to put a try catch just like this um catch error and then we're gonna obviously return the error if possible and inside of the try catch what we want to do is we just want to get the uh first of all the user who has the ID that we're going to send through the body so we're gonna we're gonna say const user is equal to 08 user model dot find by ID we're just going to put the the user ID we're gonna send over here then we're going to uh return back so res dot Json uh the saved recipe so we're going to say saved recipes is equal to user dot saved recipes also since this might be no we can put over here a question mark just in case now we have to do our last route which is going to be a route which is going to get basically just to save recipes um and not the IDS right the whole thing so we're just going to put save recipes slash [Music] um actually no slash just saved recipes like this and what we're going to do is we're going to try to get a user just like this using the user ID then we're going to get we're going to try to find we're going to query for saved recipes where uh the recipes model like this recipe recipes model or is it recipe model yeah recipe model where when we're trying to find them we're trying to get those which their ID is in um the user dot save recipes so saved recipes from the user is an array of recipe IDs so what we're seeing is we want to grab the saved recipes where their ID is inside of this list over here it's a pretty nice like logical like notation that I find with Mongoose and I honestly really like doing stuff like this then what we can do is we can literally just give back the saved recipes just like this now we're pretty much done with our uh backend for recipes now in order to test this out we should go to our front end and start generating the UI for this okay so in order to create the UI for our recipes let's start out by allowing ourselves to create a recipe right so since we've created all the endpoints we can now start creating the individual pages and the create recipe page is one of the most important ones because it is where we're going to be having all the form which you're able to create a recipe so let's put over here a div with class name equal to create recipe and inside of here what we want to do is we want to formulate a h2 tag saying create recipe then we want to put a form which we're going to be using to to send the data so form over here and we're going to do similar to what we've done in the login and registration we're going to create a label for each field so the label for name will be an HTML for an input with ID name just like this and then we just add the input like this the type for this will be of type text and the ID will be name and we'll just for now keep um keep it like this let's not add anything else so what I want to do now is I'll just fill out this form and I'll be back in a second because it's very repetitive so I'll just show you guys all the inputs and labels we're going to have and be back when we're done okay so as you can see I filled in all of the inputs and labels we have a label and a text area for the description okay so I finished up over here all the inputs and labels we have an input for the the name right a label for the ingredients but I haven't added the inputs for the ingredients because it's a little bit more complicated and we'll do in a second but then we have a label for instructions a text area for instructions a label for the image URL an input for the image URL and then a label for the cooking time and an input which is of type number for the cooking time so what we do now is we want to define the state that is going to keep track of the rest if you were trying to create so right over here at the top we're going to do create a state like this let's call it recipe and set recipe then set this equal to use state right now at the top over here we need to import the use State hook so import from react the use stage hook just like this now with the recipe we wanted to find an initial structure to how this object will look like because it will be a whole object containing all of the inputs and text areas and stuff so how this data will look like is as followed it will have a name which would be of type string so initially it will be empty string like this then ingredients which will be an array so will be an empty array then we'll have some instructions um which will be of just a string as well then image URL which is a string then we have cooking time which is um a number so we start at zero and then we have user owner but I haven't shown you guys where to get the user owner ID yet so for now let's just keep it like this so this is the format of our data now we can easily change uh and set this values equal to what is being written on the input by doing something like this getting an on change for the input like this on change then grabbing the event and then just setting the values to the specific um state but what I want to do is uh since it's a big form and all of the functions are are going to pretty much be the same I want to create a function called handle change and it will do all of the logic and all we have to do is just put call handle change in each input and it will perfectly work so I'm going to put handle change over here this function will take in an event and then what it's going to do is it's going to first of all get the name and value of that input and that's where why I decided and I forgot to even mention you guys why I decided to get uh put the name a name property on each input I forgot to put on this one so um you put a name property and it's going to serve as the key equal to this thing over here so that whenever we want to handle the change we can easily modify it by accessing the name so each of them are referring to their specific things over here so we get them from the event.target like this and then what we do is we just set the recipe uh to be equal to an object that is exactly like the recipe was however the input with or the key name will have the new value which is going to be the value that we put on the input this logic might seem a little bit weird but it makes sense right you're just changing uh one specific part of the object by doing it this way so now that we have this function done um we just pass it just like we just did with this input to all of the other inputs as well um even the text area everything should be pretty much the same um and one of the coolest parts of this we're going to work on right now which is adding the ability to add ingredients because our form right now if I go to create recipe you'll see that it looks like this but the ingredient section obviously doesn't have anything what we want to do is we're going to have a button where when you click on it it will add a new field a new input field over here so if you click three times you can add three ingredients there will be three Fields so the way we structure this is by coming over here and adding a button right which will serve we'll just write add ingredient over here and we can just add a function to this button on an on click and let's call it add ingredient like this now what we do is we create this function and the function will be pretty simple um there's many different ways you can actually make this functionality work the way I want to do it is we have this ingredients array over here inside of the recipe object right so what I can do is I can just add an empty ingredient when I click on this button what I mean by that is we'll come over here and we'll set the recipe like this set recipe to be equal to whatever the recipe was before so recipe but now the ingredients field will have whatever the ingredients array was before so we do recipe dot ingredients um like this and we put three dots to say that we want everything from the ingredients array plus whatever we put over here which we'll just put an empty string but for now so let's think about it this way so if you're not familiar with this notation over here all we're doing is we're setting the recipe object to be the same as it was before and that's what the spread operator means we're just keeping everything the same but whatever you put after the comma over here is what's going to change in that object in our case we're changing the ingredients field which initially if you don't have any ingredients it will be an empty array but now we're changing it to be whatever the ingredients list was before and again this is what the spread operator is plus whatever we put over here but since we are not adding the ingredient we haven't written on the ingredient yet the add ingredient button all it does is just adds an empty string to the end of the array which um for us is good because now what we can do is we can generate the the ingredients input based on the recipe dot ingredients list so whenever you click on a button you add another item to the list so it will map that item and we can grab the both the ingredient and the index of that ingredient and then just return over here we'll actually not even use um curly braces let's just use um parentheses like this and we can just return an input for each of those ingredients now the input will have first a key we have to add a key since this is we're mapping through a list then we can put a type of text and we add a name because we have to add a name right it will be ingredients has to match the state then we put a value and the value for this will be equal to the ingredients the ingredient that we are I'm just getting from the array and finally we're going to give an unchange now the on change will be a little bit different because we need to know which ingredient we want to change right which ingredient we want to add and also we need to know the value of what you're writing on the input so what we're going to do is we're going to create this function over here event and passing another function called um handle ingredient change let's call it that way so we're basically creating another version of this handle change but specifically just for the ingredient because it will be a little bit different so let's call it handle ingredient change and pass it in over here and we're gonna we're gonna need both things we're gonna need both the event for this function and the index of where this recipe is because now what we can do is we can come over here to the handling gradient change we can get just a value that's all we need technically because we already have what we want uh we can get it from the target then we can create a kind of like a a replica of our current ingredient list so we'll call it uh ingredients like this is equal to recipe dot ingredients we're just making a copy of it but this copy we're going to change the elements in the index equal to index the one we're getting from this function right we're passing it in and we're changing it equal to the value of the event so that's why we keep track of the index because we already added it to the array and adding it to the array is done in the add ingredient function but now we just need to change the value of that specific ingredient so that's how we do it and to set the recipe we don't set it like we were setting it before all we do is we just set the recipe to be equal to the same recipe but now we have the ingredients equal to the field ingredients um equal to the new ingredients array with the changed index over here now again since JavaScript has a shorthand notation notation we just we just have to put it like this but now this seems to Art should be working we can actually check to see if it's working our console log over here the the recipe not even over here I'll console log like below so it keeps constantly logging so we can see so I'll open our inspect element over here let's go to our console uh it seems that there's a bunch of weird errors that I'm not oh okay they went away so we have over here initially are in a recipe right but if I type over here lasagna you see that now the name field is said to be lazame if I put some instructions you'll see that obviously now we have those instructions I'll put a URL it seems to be working as well I'll change this to 10. and it seems to be working as well the final thing is the ingredients list now let's check to see if I click on this button we should see an input appearing over here and it seems to appear but it seems to disappear after we click on it which is weird now I guess I understand why this is happening uh I just realized we created the button but um since there this is the only button inside of this form the form automatically assumes that this button is being used to submit the form so a way we can differentiate this button inside of the form from a submit button is by actually giving it a type of button and then we can create the button for submit which we haven't done yet but we will need eventually uh we can put it over here and change the type to submit and also remove this because this is not how the button will look like and I'll change this text to create recipe now let's take a look you'll see we now have the button over here nothing happens when I click on it other than submitting the form um but we'll handle that later what we want is to see if I click on this button will it add the ingredients and it seems to be adding the ingredients you'll see that the ingredients list now has four elements but they're all empty strings which makes sense because that's what we added over here as the functionality but if I were to type for example on the first one if I wanted to add it an ingredient six pounds of ribeye steak right now it changed the value of the first ingredient to that if I change this one to something else you'll see it is accordingly changing the ingredients which is pretty good so our inputs and our form seems to be working perfectly so what do we do now well now it's the best part it's where we send this data to our API so what we want to do is I want to delete this console log and I want to create unsubmit function so const on submit and this function will be used to submit our form we want the event so that we can prevent default and not have our or form our page refreshing every time we click on the submit button so we'll say event dot prevent default and then we want to try catch right because we're we're gonna do some API requests over here and do the same thing we've been doing so far so console.ever error and now what we want is to pass this on submit into our form so we'll put on submit and we'll pass in the on submit perfect now what do we want well we want to send this data so we're going to say oh wait and we want to make a post request to our recipes route so you're going to say access.post and I think we don't have access imported over here so let's import access from Ax use and we want to make a post request to the URL that we have set over here yeah I think yeah this is the I think this is the correct URL so let's put this over here and then we need to pass in the recipe right but how do we pass in the recipe well the recipe is an object containing all of the data that we want to send so we can technically just put it over here just like this and if we go down and alert a message saying recipe created something like this recipe created we can now check to see um if everything seems to be working so let's see how many recipes we have right now so we have um only one recipe but let's add another one okay as you can see I just added some information I didn't show it to you guys because it would get a little bit boring I just added a very simple recipe for shepherd's pie I don't even think it's right because I got bored after copying the data and I just literally put Shepherds and Pie over here uh but it doesn't really matter it's just an example let's try to create the recipe let's open this up go to our console let's see if any errors will appear and also check this out when I click on the button create recipe we should see it over here so when I click on it we got this alert which means that on the try catch the try prevailed and it didn't catch any errors but let's check to see if the data is here when I click find um it doesn't it doesn't seem to be here for some reason but there was also not no errors which is weird so let's check our Network request let's click again hmm that's weird uh let's look at this to see what's happening so we say recipe.created oh we can check actually in our server to see if there's any errors huh there seems to be no errors when I click create recipe which is interesting oh I I forgot to remove the third party requests over here let's check to see what's happening so I am sending the data but it's giving us an error oh I'm aware of what the error is and this is totally my fault we forgot to add the the user owner ID as part of the of what we're sending to the front end right so over here we're just sending the recipe but we're not sending the the like the user who is creating the recipe we're not sending their ID so as of right now I just put 0 over here which obviously doesn't work because and that's why it's not working but um the way we're going to do this is if you recall we saved our our actual user ID in our local storage so if I go to to um application go to our local storage oh I'm not logged in I'm going to try to log in uh I'm gonna use jackdr account and I'm gonna put I think it was password I think that's their password yeah seems to be so now we should have our user ID in our application in our local storage right so I'm going to create a hook so I'm going to make a custom hook that is going to um return back this user ID whenever I wanted to now why am I making a custom hook because it is best practices in my opinion I like making hooks for stuff like this and I think it's a good idea to show you guys um how to create a simple hook that you can reuse whenever you want to get your the ID for example so let's call this hook use get user ID so we're going to create this file and the hook is going to be really simple so export const use get user ID all the hook does is it just returns back all it returns back is the window dot localstorage dot get item and we pass in the user ID I believe this is how we we wrote user ID over here uh yeah so this is all the hook is doing but we don't have to rewrite this whole thing all we do is we come over here to create recipe for example import um we import the use get user ID and we just this structure or actually just get the user ID like this now you might say oh isn't this more lines of code than just uh writing this every time you want it yes of course it is but the thing is if I want the user ID in multiple parts of my app uh now I just have to to call the user ID variable instead of having to rewrite all of this obviously I could also just create that variable every single time but trust me I'm just doing this because um I wanted to set up an example of how hooks can be useful and how you would create a little hook so that's why I included in this in this video but now I can just use this user ID whenever I want to and I want to over here I want to use it inside of our user owner like this I'll just put it over here now if we try to create a recipe I have to rewrite all of that but I'll be back in a second when I'm done and it should be working okay so as you can see I put in the information I got bored this time so I didn't even put in everything but let's check to see um if everything will work perfectly so no Shepherds buy inside of our database let's create a recipe we've got this command over here so let's check to see if it's here and yes it is thank God so we have we have over here um the shepherd's pie recipe created so we've successfully added this functionality to our front end now when you create a recipe I technically want to redirect to the home page so I'm gonna use the use navigate hook again uh just to navigate to the to the home page so I'm going to say const navigate equals to use navigate and we have to import that over here at the top import use navigate from react router Dom and then when we submit right after this I wanna navigate to the home page now what we want to do is we want to add the functionality to display all of our recipes created inside of our home page so that's going to be pretty simple and quick because technically we already have a lot of the code and um we've done a lot so far so it should be pretty similar to what we've been doing so it won't take a lot of time so for the home page we'll just come over here the home component seems really empty and sad right now but we're gonna make it look better we're gonna come over here at the top we're gonna import the use take Hook from react for react use State and we're going to create over here the state called recipes and set recipes now this the state will be used to keep track of all the recipes that are exist in our database so to do that we have to get those recipes now how are we going to do that well we're going to use a use effect I use effect as a cook that will be called whenever the component is rendered so whenever when you enter on the web page on the home page for example this function will be called now we want to have asynchronous stuff inside of here right so we can't just make this function in the use effect async this is actually against what react allows us to so what we do is whenever we want to do have some async functionality inside of a user fact we just create a function that is async inside of the the use effect and just call it right after right so I'm going to create this fetch recipe function that is going to be async and right after this I'm just going to call this function right so in the fetch recipe function I want to try catch I'm even going to just copy this over here so we don't waste a lot of time I'm just going to paste it over here and what we want this time is we actually want to keep track of what we're try catching or what we're getting back from our request because um we want to set our recipes to be equal to that so we need to import axis as well from axis and now I want to make this into a get request and this should be working this should be how it is we just have a get request with this URL if you recall just like this and um the response now is useful because all we have to do is we just set the recipes which I just realized I wrote it wrong I'll just set the recipes equal to the response dot data and response.data should return back the list of recipes now I don't want to alert anything and I don't want to navigate after this this should work as of right now let's just console log the recipe the response.data so we see if we're getting the correct data um and we should let's see yeah we're getting an array with two recipes so the request seems to be working but what we do is we actually just want to keep track of this recipes array and inside of our return statement over here we're going to put a first an H2 tag scene recipe these just like this and then we want to make a list right a list with all of the recipes being displayed so we're going to add a UL to start an unordered list and inside of this list we're going to map through the recipes State and for each recipe that is in that array we want to make a l i right and then this Li will have a key right and we want to set the key equal to the recipe dot underscore ID the reason why we want to do it this way is just because we know this will be unique so it won't cause any problems then we want to set the div over here and put inside of the div another h2 tag actually since this we're going to be using H2 tags over here maybe this will be better as an H1 tag so I'm changing this and the h2 tag will just display first the name of the recipe so for each recipe will display their name then we want to close this div come over here and open another div now this div will be for the instructions so we'll give everyone a class name because I think I added some CSS for this as well and inside of here we'll put a P tag that will just display the instructions for this recipe then we come over here we add the image right the show the image from the recipe will just set the source equal to the recipe dot image URL and then we also need to set an ALT right in case the image doesn't load we'll just set it equal to the recipe.name and then below this finally we just put the cooking time so I'll say cooking time equals to recipe dot cooking time I'm going to specify that this is in minutes so I'll just correct this like this and put in minutes like this now I'm going to save this and let's check to see how it looks uh it looks pretty good right it looks it's demonstrate it shows exactly what we wanted it shows the the title the instruction and the image and the cooking time now there's one thing that we have to do left with this obviously there's it seems too easy right this is all we did for this page but no technically we have the functionality to save a recipe right and that's interesting because when you save a recipe it should actually store in the users array it should add into the user's array a new field called save your recipes and add the recipes ID that you saved into that array but how are we going to do that well the way I did it and the way I recommend doing is whenever you have a recipe like this there should be a button over here where you can click to save the recipe so I'm gonna add that button right now and I want to add it right below the recipe name so or right next to it so I'm going to add a button which is going to be called um probably something like save over here to save the recipe and when you click on this button we're gonna put an unclick over here and call the function um save recipe but it's important that when we call this function we pass in the ID of this recipe so we can send it to the backend right we need that so that's why we're doing this because now in this in this function we're going to pass in the recipe ID now we can go up over here and create this function because this part is a little bit more complicated the whole saving recipe thing so I want to go slowly so I'm just going to create this function and obviously it will be async so I'm going to make this async like this and we need the ID over here now this function this part of the function won't actually be that complicated we'll just copy the try catch over here paste it and all we want is just a response right because when what we get back from the saved recipes API if we look back what we created right we'll see that in the in the request to save a recipe it's a put request and we receive back the list the updated list of of Saved recipes for this user so we can make a put request to the recipes API and when we console this console log this we should see the list of um of Saved recipes Let's test this out let's come over here oh I forgot to pass the recipe ID as end the user ID we need to pass both things right the user ID and the recipe ID into the body so I'm going to pass in the recipe ID and the user ID just like this now let's check this out uh oh user ID is not defined I need to call the the use get user ID hook from dot slash I tend to go back twice hooks slash user guide use get user ID then I'll just get the user ID just like this and now it should be working so let's test this out if I click on save for the stake um if you go to users over here obviously there is there's no user ID over here so there's no saved recipes over here when I click on this I actually think it will give us an error but maybe not let's see the data actually it seems to have worked let's update this yeah it worked so we now have um the recipe ID for this specific for the recipe that we saved the steak one over here now let's refresh this and try to save the shepherd's pie so when I click on this now not only should we receive back an array with the shepherd's pie but also the steak that we saved previously and that's exactly what happens if I refresh this you see the shepherd's pie is here again now the interesting thing is I I can't save this again which is not a functionality I want to allow the front end to be able to to do obviously in the back end I could have uh made it so that you can repeat stuff that you're saved but that doesn't really matter uh it won't change anything because all we want to know over here is technically which recipes are saved or not so I do want to create a state over here which is going to keep track of all of our saved recipes because we want to fetch the ID of those recipes to be able to determine which ones are saved or not so I'm gonna create a state called saved recipe and set saved recipes then I want to inside of our use effect create another function called Fetch saved recipes just like this now for this one uh the API request we want to make is not for this get request over here but rather for this one over here so we're going to get this and put it right over here now to get requests just like before and instead of setting the recipes we're going to set the saved recipes but actually I just want to see something I want to actually just console uh log the response.data so we look a little bit to see if it's if it's working to see if it's if we're getting the correct data also we need to pass in the the user ID I remember right we get the user ID in this request so we need to pass in through our body so I'm just going to put over here the user ID just like this so let's test this out I'm gonna inspect element uh refresh the page and nothing appears I guess it's because I never called the fetch saved recipes function but now it should show something but it doesn't seem to be showing anything although we are logged in let's take a look at the request let's look at the network requests so IDs what are we sending to them so hmm let's look at our backend um is there anything that we're doing wrong over here it doesn't seem like it as well oh guys I'm stupid I'm sorry uh I just realized what the error was but keep in mind I like when I commit errors in my videos I've said this a lot in the past it helps to show you guys how to fake serious how to debug and also it shows that I I'm not I haven't like finished everything uh I'm trying to come up with it at the spot as well so you guys can kind of get a good representation of how coding actually is so obviously you can send data body data to get requests anyone caught this before uh it's a stupid mistake but uh with get requests what we can do is actually send the data through the params so we're not going to get this through our body we're actually going to get it from uh the param over here so user ID is how we're going to you to send the data and to get data this user ID from the params instead of saying rack.body we're going to say rack.params and then over here instead of making can't request sending a body like that we'll just pass in over here a variable equal to the user ID but to send a variable we have to make this string into backticks and then put in the money sign and curly braces and just pass in the user ID I'm pretty sure this will work now let's check our console refresh the page oh it actually didn't break it did correctly send it back I don't know what happened so uh you see it is sending back the saved recipes so everything seems to be working perfectly and that was indeed the error so now that we're getting back to save recipes what we want to do is we want to just set the same recipes to be equal to response.data um dot yes saved recipes so dot saved recipes I'm going to delete this console log and now we're keeping track of the saved recipes which is pretty good now how do we know if a specific recipe has been saved by the current user well we're keeping track of the state which tells us which recipes were saved by the user so all we have to do for example is if I want to make if I want to I don't know write the word uh saved whenever this specific recipe was already saved right all I have to do is I just have to put a conditional over here a condition and say that oh okay if the saved recipes array includes the index or the ID for this specific recipe then um display this and you'll see that this works because it was already saved but if I were to create another recipe over here which I'm gonna do right now but not show you guys so this is the recipe I'm creating I'm going to click on create recipe it will create it you'll see that all of them says already saved but the new recipe that I just created doesn't say already saved because I never saved it I could test it by clicking on this button and I'm pretty sure if I refresh it right now it will say already saved now it should save it automatically but we haven't finished that up yet so let's continue coding it but you'll see all the functionality seems to be working now we should we don't want to just show already saved like this we actually want to show a button right we want to actually use the button and whenever you already saved the recipe you want to disable the button this save button over here so the way we're gonna do that is this whole includes functionality we can actually create a function over here which is going to be used when everyone know if a recipe was already is already saved by the user so let's create this function called is recipes saved and all this function once is the ID of the recipe and it will return back a Boolean saying if it's saved or not I don't want to be checking if it includes every single time I just want to call this function so inside of the button over here we want to disable this button if if the is recipe saved is equal to true so we're going to set the recipe dot under a line ID over here and you'll see that now for all of the buttons it will be disabled and we can't click them now this seems pretty good right but it still says save so let's change the text if it's been saved it should say saved if not it shouldn't so we can actually just add this functionality over here and say that if is recipe safe is equal to true then we want to say saved but if not we wanna say save and you'll see that now all of them changed to saved but also we'll see that in the save recipe function over here if you want that functionality to whenever you add a new recipe and whenever you save a recipe like this the button and all the UI will change automatically instead instead of having to refresh the page all you have to do is just set the recipe the saved recipes to be equal to the response dot data dot saved recipes when we save a recipe so if we recall we did send back the updated list of Saved recipes when we save a recipe I believe let's check it out uh yeah we return back the saved recipes so uh if we just set it like this it should work perfectly and now this entire section over here seems to be working perfectly uh so now all we have to do is just uh create the saved recipes section and at the end we're gonna add all of the stuff related to authenticating the user when they make a request it's just a final thing we're going to use the token that we created in the beginning to fix all of our endpoints but for now let's just work on saving creating the saved recipes page so this page will actually be very similar to the home page so similar that I'm actually going to copy all of this code and just paste it over here now I'm going to change some stuff like I'm going to call this saved recipe or saved recipes like this and um what I want is I don't need to create a date called saved recipes because technically we're in the saved recipes page so the state the state recipes should assume it is already saved recipes right we also want uh we want the same thing over here the use effect because we want to whenever you go into this page to automatically show the recipes but again we don't need to have a fetch recipe and a fetch safe recipes we just need the fetch saved recipe or just call it fetched recipes as well I don't think it matters actually let's call this saved recipes still just to maintain consistency like this now this whole thing should be similar but the difference is we don't need the IDS anymore we actually need the entire recipe so we're going to pass in just like this and um let's see what's giving errors oh okay we don't need the save recipe function also we don't need the is recipe safe because that's that doesn't matter all the recipes that are going to be displayed in in this page already saved or assumed to be saved now this thing over here let's change the text to saved recipes and when we return this we don't want to have the button to save because again you don't want to save recipes that you already saved the rest I think should be fine I don't think it matters to put any of anything else let's check what the error is it says recipes oh because we need to change this to saved recipes you'll see now it seems to be working it is not yet displaying the safe recipes because remember we made a mistake in the in the get recipes ID route where we were passing in the body and I believe we did the same thing over here we can't pass a body um to a get request so we're going to do the same thing we did over here where we pass in the user ID through the params so we're just going to change this to params and now um what we do is we come back here this should be working and I guess this should be working soon right yeah it is working it's showing all the saved recipes inside of this um page but the difference is that you guys are not actually seeing if it's working or not because all of our recipes have been saved so what I want to do is instead of creating a new recipe I'm actually going to try to change this I'm going to delete uh the lasagna actually I'll delete the stake and not save the stake so you can delete it directly like this we'll go back to the home page you'll see that the stake is not saved anymore but the shepherd's pie and the lasagna are saved so if I go to saved recipes we don't see the steak anymore we only see the lasagna and the shepherd's pie meaning there are whole functionality is working which is perfect now that's great we're pretty much done with a lot of the functionality inside of our project now really the last few things we want to do is being able to use our token which we created in our backend um to validate every request so whenever we make a API request right either it be for the recipes or for the users actually just for the recipes in this case whenever we make any of these API requests if it is an important request that you have to be logged in to make we want to really authenticate the token that you have instead of this request so the way we do this uh usually in node.js at least with a simple very simple version of this is by creating what is known as a middleware which is a function that will run before each request and that function will verify if your token you're sending from the front end matches the token that you should be sending so inside of our users thing over here let's create a middleware we'll do it even after the the router export over here so let's just export a const called and the middleware will be called verify token and for middlewares in Express you kind of have access to the rack the res and to this function called Next which will be used to authorize um the the request to continue now if you're not familiar with meter wires I truly think you should watch one of my videos on it I have a full video just on Express middlewares and I'll just come through a little bit over here but I would recommend watching a full-on video on that so in this middleware what we're going to do is we're going to first assume that we're going to send our token our JWT through the headers and through a header called authorization so let's grab that token like this and set it equal to Rack dot headers dot authorization so in the front end we have to send a header with the authorization field our key and then we're going to check okay if any token was sent then we want to verify if this token makes sense so we're gonna verify with the token with the same secret that we used over here so this has to match this and then what we do is we'll have a callback function which will give us any errors in case there's any errors and we're going to check okay if there's any errors we want to um probably return uh res dot send status we want to send a status saying that this didn't work so we're going to send a 403 status just that to if you're familiar not familiar with status codes I recommend looking at them but we're just telling ourselves that we're not authorize this user is not authorized and right after this we'll call next because if the verification was done and there was no errors then we should allow the user to continue with their request now if there's no token that means we don't even have a token to verify meaning that the user obviously is not verified so we're going to send back a status and we're probably going to send a 401 over here so now we have this middleware that we want to run before every important API request that requires us to be authenticated now what are those well the create recipe one is it is one right because we want to only allow um people who are actual users to create a recipe so we'll import this at the top the verified token and pass it in right before the Callback function in the routes then we also want to do this for the for the save recipe one probably and the other ones I don't think it matters because I'm going to actually prohibit the ability to go to the save recipe page unless you are logged in so I don't think that will matter that much but if you guys want to do it anyways I think you guys should like it it's best practices to it makes your project more secure always verifying stuff but to simplify everything I'm just gonna um do it for the create recipe and the save recipe so since I put this middleware over here this means that this request will never work anymore like I won't be able to save this thing anymore because you'll see that when I try to save this I'm not currently sending anything through the headers I haven't I've done the implementation on the back end but I haven't done anything in the front end that will allow ourselves to send the token so if I click on this we should get back uh request failed with status code 401. why did we get a 401 because over here in our verify token if we don't send a token from the front end we're sending back a 401. if the token is wrong we send back a 403. so let's test sending a wrong token if I come over here and I go to the save recipe thing we want to send it through the headers right so let's uh to send something through the headers in ax use all you do is you just create this object over here pass in the headers and set of the headers we need to pass in an authorization um field right because that's what we assumed we were going to call it now let's put in a fake one just a random strings of letters right and let's test to see what's going to happen we should get back a 403 code because it has a token right it has a token but it's not verifiable now how do we send in the token that we want to be verified well inside of here we need to grab our cookies just like we were doing um in our authentication thing we'll grab the use cookie hook and we'll grab the we'll actually destructure the cookies like this um just like this and we don't need the set cookies thing we need the just the cookies so we passed in the cookies inside of here by saying cookies dot access token and now if everything seems right we should be able to save this stake and we are able to because we are sending the correct token to be verified so we just set up correctly authentication and authorization inside of our project um now we just have to do it for the for the create recipe one as well but it's pretty much the same thing so I don't think a lot of explanation will be needed for that we'll just come to create recipe um after the the body we send the headers and we do need to have access to the cookies so I'll just copy this whole logic of of importing the use cookie over here at the top and getting the cookies from this and I think now it should be working for the create recipe one as well so this is pretty much it for the code all we can do now is like I said I'm gonna prohibit ourselves from seeing the saved recipes field but that's pretty simple all we do is we go to our auth over here and we just extend our actually it's not in the office it's in the nav bar we just extend our check for if the if the user is logged in and if they are logged in we want to display the saved recipes thing only if they're logged in so we'll put the saved recipes over here we're going to put a fragment in order to be able to have elements without a parent and now you'll see that disappears but if I log out it doesn't appear anymore so oh it's breaking the home page it's breaking because we're trying to check for users who who are not since we're not logged in we're trying to check for their saved recipes so a way to actually prevent all of that from happening is we can actually just um just allow the the fresh saved recipes thing over here if uh cookies.access token is true if not then we don't want to make the request and you see it works right that's good I think it will break if I click saved actually it won't but oh yeah it won't because it makes sense so everything seems to be working now all we have to do is be able to deploy this to hostinger which is one of the most important parts of the video okay everyone so let's start the process of deployment so we just went into the hpanel from hostinger like I showed you guys in the beginning of the video and from here we can basically handle everything that we need so the first thing we need to do is claim our free domain with the account that you guys should have created and and purchased in the beginning of the video so I'm going to click on claim domain and I'm going to put a domain name so uh I you should choose whatever makes sense for you you can even use this for another website if you're interested in because you got the domain so you can claim whatever domain you want to but I'm going to make one Associated to this so I'm going to create I'm going to call it Pedro Tech recipes I doubt that there's already a domain like that so I'm gonna put a.com because it it looks better Pedro techrecipes.com I'm going to check the availability and as you can see there it is available because who else would have bought this domain but you can see that instead of being 14 a year we're actually paying nothing because it comes with the plan so now we're going to click on claim domain and um we should see our domain being um claimed so as you can see we can choose the domain uh the profile of whoever owns this domain I already have a profile I'm obviously not showing to you guys because it shows my address and stuff but if you don't you can just click on add new profile as well so I'm going to choose the one that I already have and click on finish registration it's going to start uh registering and you can see it's pretty much done the only thing that you need now is to verify your domain so I'm gonna go to my email um verify this domain through my email and be back in a second okay I just verified in my email if I refresh this it should be working yeah it seems that it was verified and this should update to say it was verified as well now that this is done we're going to go back to our home page over here and we're going to click on the setup for premium web hosting when I click on this uh it's going to open this up we're going to click on start now now you see there's two options one of them is to transfer and migrate an existing website to hostinger this isn't the case you're already hosting it somewhere else for example and you wanna now host with hostinger now the create new website is the hostinger actually gives you a really nice like system for you to build your website without code by using something like WordPress however we're not going to be doing that we already have our website so I'm going to click on Skip and create an empty website then it's going to ask us to choose a domain or use an existing domain that we've purchased outside of hostinger but we already have a domain we have pageotechrecipes.com so I'm going to click on that and then click on select now it's going to ask for a server location they have a bunch of servers out there I'm going to choose the South America one because closer to where I am right now however it doesn't really matter like just choose the one that is closest to you but it will pretty much work everywhere um I'm not actually in South America right now but it works perfectly fine um and all the ones that I've deployed in the past worked continuously worked pretty well even though I'm not in this specific continent so then I'm going to click on finish setup and it should pretty much be done now it seems to be done we're going to click on view website now it's going to open up our website with our domain however we don't uh currently we didn't deploy anything yet so obviously it doesn't make sense then we're going to click on manage website and over here is where we're going to actually insert our files so we click on file manager over here and this will redirect us to a page where we can actually just drag and drop files that we need to deploy so we have over here our public.html folder what this is asking for is basically the public.html folder that we have over here and inside of our app right but for that we do need to run my create a build version of my uh project right and I'm talking about the front and only just the client so to do that I'm going to go into my client folder over here I'm going to kill the terminal that was running it and I'm going to run yarn run build it's going to create an optimized production build it's going to be over here as you can see and that's what we're going to put inside of our file manager so here in our file manager inside of the public.html folder I'm gonna we have this default.php file over here which we we don't actually need this is only the only thing that this does is um it's currently just demonstrating this page over here so that's why it's it's here but if we actually delete it um it will remove whatever creates this I don't know if it's automatically but um yeah it removed whatever was there the only piece of code that was there so now what we do is we put our files inside of this folder so we just come over here we opened this folder I don't know reveal it in finder you'll see that this over here is what appears and now that we are in the client folder we just open the build folder and we copy all of this stuff and just drag and drop over here you should see that it is uploading the files and they go pretty fast as you can see now that they're here it's pretty much done what we do is we literally just refresh this page and we should see the front end of our app appearing over here now we can see all of our data being displayed as you can see and it's all being hosted our front end is all being hosted and this URL over here with a secure connection meaning that we have an SSL certificate that is valid um and you can see everything is working out perfectly right we can create a recipe we can log in if we wanted to we can do all of that kind of stuff now one thing I want to mention to you guys is that the reason why we're seeing all the data being served is because we're running um our project and our backend over here so we have our backend running as you can see now if you want to run this and have your data being served um you can deploy the backend um in a variety of ways you can deploy it to a VPS for example and serve it using hosting or they have this this capability and I would recommend doing this as well however I'm not going to show it in this video because it would add a lot of time to this video and I think just showing you guys how to deploy the front end and how to build the application is enough for now because because it's already a lot of stuff for you guys to to like have to understand and learn so if you guys are interested in learning how to deploy the back end of this app to a VPS I can definitely make a video on that as well again thank you hostinger for sponsoring this video this is the third video that hostinger has sponsored for me and it is because I love the platform I've been using a lot of it and all of you guys in the previous videos have told me that you guys liked it as well so I really appreciate them supporting the channel you guys should check them out in the description there will be a link you guys can get a discount completely like I showed in the beginning and yeah that's that's basically it I really hope you guys enjoyed this video If you enjoyed it please leave a like that below and comment what you want to see next subscribe because I'm posting every single week and I would massively appreciate it and I'll see you guys next time [Music] [Applause] [Music] [Applause] thank you [Applause] [Music]
Info
Channel: PedroTech
Views: 154,547
Rating: undefined out of 5
Keywords: computer science, crud, javascript, learn reactjs, mysql, nodejs, programming, react tutorial, reactjs, reactjs beginner, reactjs tutorial, typescript, react js crash course, react js, node js, express js, pedrotech, traversy media, traversymedia, clever programmer, tech with tim, freecodecamp, deved, pedro tech, mern, mern tutorial, fullstack project, react project, mern project, mern authentication, mern projects for resume, tutorial mern
Id: P43DW3HUUH8
Channel Id: undefined
Length: 157min 48sec (9468 seconds)
Published: Tue Mar 07 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.