MERN Stack Free Course: MongoDB, Express, React & Node.js Full Project

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey welcome back to the channel so who is this video for this video is for you if you're already at least a little bit familiar with html css javascript you at least have heard of react and you know that it's a front-end library where you can break down your interface into components so you're familiar with all of those basic concepts but maybe you're confused on how to combine all of those puzzle pieces into a meaningful project so in this video we're going to learn about the mern stack but let's not even worry about the technical details of what the mirn stack is right now we'll cover that organically and gradually throughout the entirety of this video right now i want you to focus on what we're going to build so here's a sneak peek preview of the finished product of what we're going to build together in this video so we've got this public listing of animals and anyone in the world can view this page and the browser here is not loading even a single ounce of javascript so this is just traditional server generated html and that's great when a page doesn't need the interactivity of javascript so server side html like this has lots of benefits search engine optimization boosts maximum accessibility great initial render speeds so on and so forth however for an area where we do want the interactivity of javascript if you're the owner of the website you can visit this admin page you can access it with the super secure username of admin and a password value of admin and now when you're here you can create new pets you can update existing pets delete a pet and this admin page this is entirely driven by react and client-side javascript so that way all of these crud actions were performing they happen in real time without any old-fashioned you know traditional full-page reloads or refreshes and what's really cool here is these animal cards right each little box for each animal whether we're seeing that on this admin page or back on the public home page those are both being powered by the same react component the same bit of jsx and i think learning how to leverage the same component file in both environments like that is going to be super empowering for you now for persisting the data all of this is getting stored into a mongodb database and finally we're also going to learn how to let the admin user upload a photo for each animal and we're going to resize the photo in memory so that the file we actually store on disk is a nice small file size the point of building this project is for you to be able to sink your teeth into the mirn stack without things being super hypothetical right so yes this project is simple but it has just enough complexity that it feels a little bit real world so yes this is a long video but if you've watched a few videos on the mirn stack before and they didn't really connect the dots for you i'm hoping this video can be the one where things finally click anyways without further ado let's jump into the action so where do we begin well let's start with our server as it's sort of the home base that connects everything together we're going to create a server that's powered by nodejs so if you don't already have node installed on your computer you're going to need to pause this video and get it installed right now this video is not a tutorial on installing node you just need to visit the official website and then come back to this video once it's installed okay but once it is installed let's go ahead and create a new folder somewhere on your computer so for example i'm going to create a brand new empty folder on my desktop the name doesn't matter but why don't we call it maybe mirn dash project okay and then go ahead and open up this folder in vs code in the left hand side the file explorer let's go ahead and create a new file so i'll just right click new file there's nothing special about this name but just so you and i are on the same page why don't we name it server.js in this brand new empty file let's just say console.log maybe hello from node go ahead and save that and now open up your command line in vs code so that's ctrl j on windows or command j on mac and then just run this command with me let's say node and then the name of our file so server.js cool hello from node so this means we successfully just executed our node application awesome but we don't want to just output a string of text we want to build a web server now there's no point in reinventing the wheel there's already an amazing unopinionated package called express and it makes it super easy to get a web server up and running with node so how do we get access to that package how do we download it well we're going to use npm node package manager so first let's set up sort of a grocery list that keeps track of all of our dependencies so we'll say npm init dash y go ahead and press enter you'll notice that created a package.json file for us and now when we install any third-party packages this file will automatically keep track of which ones we need so in the command line now we can go grab express we can just say npm install express go ahead and press enter cool and now let's go actually use it in this file to set up a really basic web server so i'll get rid of this console.log line and let's pull in that package so const express i'm just making up a variable name and setting that to equal and then require in and this is how you pull in the third party package so its name was express now on a new line we can access this so we just want to create a new instance of that so let's create a variable you can name it anything but so we're on the same page let's name it app and that equals just a new instance of express right we're just calling express okay but now we have our app we can tell it to begin by listening for incoming requests so we can just say app.listen and let's tell it to listen on port 3000 now before we save this file and test it out let's set up two url routes right so we would want the home page url route but then we want people to be able to visit slash admin as well so we can say and notice this is above the app.listen line we're going to say app.git so if someone sends a get request right that's what happens when you just enter a url into your address bar a typical request is a get request and we're going to give this two things so first we spell out the path so for the home page that would just be a forward slash right sort of the root url the home page the second thing we give it is a function that we want to be executed when a request comes in so instead of b you could give it an anonymous function or an arrow function let's do an arrow function with two parameters request and response after the parentheses and arrow symbol and then curly brackets we can drop down now request and response are given to us by express so when express calls this function it's going to give us things called request and response request represents the incoming request that the visitor is sending to your server and then response represents your ability to send back a response to that visitor so for example if on our home page we just want to send back a little bit of text that says you know welcome to the home page we could just say res you know response dot send give it a string and just say welcome to the home page okay let's spell out a route for it when someone visits slash admin app.git for when someone visits slash admin comma give it an arrow function or an anonymous function but just give it two parameters so request and response arrow symbol and just say response.send this is the top secret admin page okay let's go ahead and save this file and test it out so in the command line just go ahead and run node server.js we're just running our node application again only this time it's never going to stop running until we tell it to stop running because it's a web server right it should be up and running forever so with that running if you go to your browser and open up a new tab and in the address bar visit localhost colon 3000. awesome we see welcome to the homepage and if at the end you add on slash admin as you might have guessed this is the top secret admin page so when it comes to the mern stack and the mern acronym this is already the e and the n the e stands for express right which is just the web server package that we're using and the n stands for node which is the language or run time that we're executing all of this within at this point let's change gears and talk about the m in mern stack which stands for mongodb so our express server is great at listening for incoming requests right so users can visit our different urls when they're on a page they could fill out a form or type into a chat box anything that website visitors do and then our express server can receive that request and then send back an appropriate response that's great but in addition to that we need something that is persistent or permanent we need a place where we can hold on to data forever and that's where a database comes into play so that's what the m and mern stack or mongodb is going to give us so how do we get started with mongodb well there are about 10 different ways so mongodb offers a cloud service called atlas they have a free tier where you can sign up they'll host your database in the cloud if we were actually going to go live with our application i would recommend this however for just our first simple project this is a bit complicated because you would need to go in manually and allow your local ip address or add a wild card so on and so forth just to establish a connection so i actually think we should install mongodb on our personal computer now you could look up a tutorial on how to do that how to install mongodb locally but i actually think the easiest way to do that is to just use docker instead now actually and truly learning docker is its own video topic but the good news is that we can 100 leverage docker in this video to get mongodb up and running without needing to know basically anything about docker so follow along with me right now i want you to google for something called docker desktop or if you visit the github link in the description of this video down towards the bottom here you'll see that i have various links and one of the links is to docker desktop anyways from the docker website just go ahead and download and install docker desktop on your computer it's completely free so go ahead and pause the video and then come back and resume the video once it's installed okay so once you have docker desktop installed what do we do next well for now we don't actually need to do anything from this new docker application window we can jump back to this app in just a minute or two but for now what i want you to do is go back into vs code and in the root of our project folder i want you to create a new file with me so new file and the name of this file needs to be docker all lower case docker dash compose dot yml in this new file we're going to tell docker that we want to spin up a mongodb database that we can practice with now in order to save some typing because there isn't really much educational value in this file i actually want you to just visit the github link in the description for this video so i've created this github repo and you'll see that there's a file called dockercompose.yml so if you click on that file and then you can click the raw button right here and then you can just copy select everything here copy it and then in our new file paste it in and hit save cool so essentially we're just telling docker hey we want to use mongodb and you know the username is going to be root the password is going to be root so obviously it's super insecure but we're just installing it locally on our private computer so it doesn't matter cool now how do we tell docker to actually start using this to spin up a mongodb database well open up your command line so again ctrl j or command j you can see my node web server is still running so you can press ctrl c to stop that task okay and now to tell docker to begin working we just say docker compose up and then dash d go ahead and press enter for me that command finished almost immediately but if you're using docker for the first time your computer will need to download about 700 megabytes for the mongodb image so be a little bit patient but once that command does finish you now have a mongodb database up and running on your personal computer before we move forward i do want to show you how you can start and stop the database so even though we said docker compose up you only run that once the very first time when you're first creating this database instance so the idea of up and down is just a one-time thing to create or destroy the container if you want to know how to start and stop the database it's docker compose stop so i can run that cool it stops it if i want to start it up again like imagine it's the next day or next week it's just docker compose start cool in addition to those commands you can also go into your docker desktop application now click on containers over here on the left hand menu cool and you see i have the one called mirn project it's just based on the folder name but if you hover over it you can also use the stop and start buttons right here cool so we have this database running on our computer how do we actually connect to it and start working with it well before we worry about connecting to the database from within our node or express app let's first just try to connect to the database at all so let's begin by using a gui or graphical program so what program should we download which program should we use if you go back to my github repo down at the bottom you'll see there's a link called mongodb compass so you can follow that link this is the official tool by the official mongodb team it's just a graphical app that makes it really easy to connect to a database and start working with it so again pause the video go ahead and download and install mongodb compass okay once you open compass it should look something like this and now the question becomes what value do we enter here to actually connect to a database well when docker created our database remember we gave it a username and password of root and root so instead of typing that in if you go to the github repository in the description for this video down at the bottom just down here in the read me not this first value that you see but this second value says the database connection string value that we will use in the mongodb compass app so this value right here you can just click this button to copy it into your clipboard back in the compass app just use that as your value here so just paste it in it's just connecting to the local instance of mongodb on the default port with a username and password of root root go ahead and connect okay once we're connected let's click on this databases tab up here and our local database server has these default databases of admin config and local let's actually create our own database where we get to choose the name so just click create database and just so you and i are on the same page why don't we name it amazing mern app for the collection name in mongodb a collection is like a table in my sequel right so you might have one collection named animals and then another collection named users and then another collection named posts so on and so forth but let's just start with one named animals let's go ahead and click create database okay here we see it in the list now go ahead and click on it we only have the one collection of animals we can click into that and let's create our first animal document in the database so i'm just going to click this add data button that opens a menu let's choose this insert document option we can leave this default id property here but after that inside the overall object let's add a comma and then let's add a property named name colon give it a value of meows a lot comma let's say species give that a value of cat down at the very bottom right corner you'll see an insert button go ahead and click insert cool let's go ahead and add one more document let's add a dog so add data insert document say comma name should be barks a lot comma species should be dog go ahead and insert perfect so now the question becomes how can we connect to this database not from within compass but from within our node or express application remember back in this tab we have our different localhost 3000 urls and you can imagine that we would want to loop through all of the animals and display them here so this is the point in the lesson where we really start to connect all the dots let's go ahead and jump back into vs code we can go ahead and hide our terminal for now we can close this docker compose file and i want you to open up the server.js file so essentially in this file we want to programmatically connect to our mongodb database in order to do that we're going to need the mongodb driver for the node.js environment so to get that we can just use npm so in the command line down here just run this command with me npm install mongodb go ahead and press enter should be a very quick download okay then back in our file up at the very top here let's say const curly brackets we're going to destructure something let's set that to equal and then just require in that package so mongodb inside the curly brackets the item in particular from this package that we're interested in right now is client now we can leverage client to open a connection to the database but we need to think about when or where we want to do this in other words we want to establish that connection before our server begins listening for connections in other words we want to have the database ready before anyone can actually visit any of our urls so here's what i would do down here right above the app listen line let's create an async function because we're going to use the await feature so async function you can name it anything i'll name it start and then just right after the definition just immediately call the function in the body of our async function let's say const client equals a new instance of client okay and now in these parentheses we just give it a connection string now this is very similar to when we connected to our database from within the compass app it's a little bit different though and it's not very educational just to type out a long string in a video so if you visit the github link for this video this first value down in the readme this is the connection string value that will work for our mongodb setup so again it's just using the username of root password of root local host default port but then it's pointing towards our exact database name remember we named our database amazing mern app it's got this extra setting on the end to make sure that it plays nicely with our exact setup so just go ahead and click this icon to copy that into your clipboard back in vs code just paste it into those parentheses cool now right below that line still within our async function though let's say a wait and now we're just going to leverage this so client.connect okay because we included the keyword await here the next line of code is going to wait until this has actually finished you know whether it takes one millisecond or a thousand milliseconds we don't know but we're waiting for it to finish and now we can call client.db and this is going to return something that is basically the database that is very easy to work with the database so whatever this returns we want to store that somewhere so it's very easy for us to access now there's a million different ways that you could handle this but here's what i like to do up at the very top of this file let's just declare a variable or initialize a variable i'm going to use let instead of const so that we can actually change or update the variable so let's just say let db we don't even need to set it to anything we're just initializing it and then back down in our database code at the start of this line let's just say db equals client.db so now we have this global variable named db so that it's always really easy to access our database from anywhere within this file okay now finally once we've completed that then we can actually tell our express app to start listening to essentially launch and be ready to receive incoming requests so i would just move the app.listenline so just cut it paste it right there just like this cool now to test this out why don't we write a little bit of code in our homepage route so that when you send a get request to the base url let's practice querying the database right here so let's make this an async function so just right before the parentheses just say async okay and then right above this response.send line we can say const maybe you know all animals i just made that up equals but now we can say db that's our database it has a method called collection so remember we only have one collection named animals on that collection let's call a method named find because we're not going to provide any value here like we're not saying we only want to find the cats or only find the dogs we're just finding any and all documents and then finally mongodb would return this in a format that makes sense for mongodb but maybe not sense for you and i as a human being so at the very end here we're just going to say to array and that will format the data in a way that makes sense for us okay and remember that a database operation could take some time right if our database had five million documents in it this query would take a little bit of time we don't know exactly how long it's going to take so right before the db right here we would say await so we want to wait until this operation has actually finished and then below that let's just log it to the console console.log all animals let's go ahead and save this and test it out so open up your command line and just run node server you don't need the dot js but it doesn't hurt but just go ahead and run our server okay and then back in our browser to test it out if you visit the homepage url so just localhost colon3000 go check your vs code console awesome you can see it logged all of the animals this means that our node app is successfully accessing the database that's great but we don't want to just output that to the console we would want to output a list of the animals on the actual website right that we send back to the visitor we'll get to that in just a minute but let's take a quick timeout because for example if we were going to go make that change we would need to quit our node application and then restart it because remember our server is going to run until the end of time or until we stop it so in other words we can make changes to our server.js file but unless you actually restart the task it's not going to be using your new code so we're going to stop right now take a quick timeout and use a really popular package that will watch our file for changes and when it detects a change it'll automatically restart the task for us so do this with me in the command line go ahead and press ctrl c to stop our server and then i want you to install this package with me so npm install and it's named nodemon right it's going to monitor our node application applications nodemon go ahead and press enter okay now let's go use it so to set it up jump into the file named package.json and we're looking for this scripts area we're just going to create a new script so right about here we can make up a name for our task why don't we name it our server colon quotes at the end of that line be sure to include a comma in the quotes just say nodemon and then the name of our file so server.js you don't really need the js just nodemon server and now in the command line if you type this in say npm run our server go ahead and press enter now it will automatically restart our server for us anytime we save a change to our server file trust me that's going to save us a ton of time throughout the rest of this video cool so right now let's practice actually sending back a response so that a visitor to this website could see the list of animals there's a million different ways you could do this the most basic way would just be to spell out a string of text right here so for example we could get rid of this console.log line and then for response.send in the parentheses get rid of the quotes in that value and instead we could just have backticks and you know have a heading level one that says welcome to the page close close out the heading level one and then after that we could say dollar sign curly brackets to do something dynamic we could take all animals it's an array so it has access to the map function inside that you give it a function with one parameter so we could say you know animal arrow symbol and then have it return a string of text so back ticks maybe just a paragraph or list item whatever inside there dollar sign curly brackets say animal dot name and then dash you know dollar sign currently brackets animal dot species and then towards the end after the closing parentheses you could say dot join and just join an empty string of text so that there's nothing separating them so instead of an array we just have a big string of text again that's what we're sending as our response we could save that go refresh awesome welcome to the page meow's a lot cat box a lot dog now that works but that was just to prove a point and the point that i'm trying to prove here is that spelling out an entire html template in a string of text like this is bad right it's not organized it's messy it's gonna get unmanageable very quickly so instead of doing something like this developers will often use something called a template engine now there are you know 30 or 50 different template engines to choose from right now i want to show you a really popular one called ejs so you can do this with me in the command line we can press ctrl c to stop our project and install a new package with me npm install ejs go ahead and press enter okay now let's tell our express app that we want to start using ejs towards the top maybe right below this line where we say const app equals express let's just say app.set view engine comma ejs and then let's also spell out which folder we want to keep our view files or templates in so i'd say app.set views so where should our views live and then just point towards a folder so quotes dot slash views okay we can go ahead and then create a new folder in our project named views in that folder let's create a file and name it home.ejs in this file just say hello i am the home page template you can save that go back into server.js and now for the home page route instead of response.send you can get rid of this entire response.send line and instead just say responser res dot render and then you just tell it which template you want to render so we named ours right in the views folder we named it home.ejs so that's really just home so you just say home go ahead and save that and then let's tell our server or tell nodemon to start watching us again so npm run our server go ahead and press enter if you wanted to you could open up a second terminal to install npm packages and just let this terminal always keep our app up and running but if we go back into the browser and refresh the home page hello i am the home page template cool so now we just want to pass the database results are info into that template so when we're saying response.render the first argument is which template but you can say comma and now you can give it an object with as many different properties and data that you want to give it so let's just give it an object with one property and it's just all animals okay the idea is that now back in our homepage template we can access that so for example let's have maybe a heading level one that says welcome and then below that imagine we want an unordered list inside that imagine we wanted list items and just list out all the different animals so in ejs the syntax is a tag that looks like this and then to close it out it's percentage greater than but inside that tag we could say all animals dot four each inside that you would give it a function so function or you could give it an arrow function but i'll just say you know the current animal that's been looped to curl the brackets drop down now at the end of this line we could drop out of ejs in the middle here let's output a list item and let's just have you know animal dot name dash animal dot species you might notice i included an equal sign here on the opening tag that's just letting ejs know that i want to escape whatever text i'm including here so escape and output the value okay then down on this line we'd want to jump back into ejs so that we can close out our loop so we can go ahead and save that and if we refresh perfect so this is a real dynamic listing of our animals so you could go back into mongodb compass you could add a third animal right so let me add another say comma name it's purrs loud and the species is cat i can go ahead and insert that i go back and reload the website perfect now if the year was 2003 we'd be done we could just close out the video but in the modern era we really need to learn client-side javascript so for example when we visit our slash admin route we would not only want to see the pets but we would want to be able to click on them to edit or update you know their name or species or photo value we'd also want to be able to click a delete button and i guess what i'm saying is we want those actions to happen in real time right we don't want to have a traditional full page reload and refresh when we're performing those sorts of actions like creating a new pet updating a pet deleting a pet and in order to have actions in a web browser happen in real time like that we need to write client-side javascript right we need to be able to make network requests on the fly asynchronously so in order to add that client-side javascript this is where the r in mern comes into play so r is for react now before we focus on react let's first set up an html template for this slash admin url that tries to load a bit of client-side javascript so what i mean is back in vs code in our views folder let's create a new file and name it admin dot ejs in this new file you can type doc and then hit tab that'll give you sort of an html skeleton up at the very top i'll maybe add a doctype tag okay in the body i'll just say hello give that a save and then back in server.js the route for our slash admin url instead of response.send we'd say response.render and we named it admin so you can give that a save refresh that url perfect so we wouldn't just want to output the word hello if we go back into that new file admin.ejs here's what i would want to do let's have an empty div and we can give it an id of app and then we would use client-side javascript we would use react to render our user interface into this empty element so then down at the very bottom before the closing body tag we can just include a script you know so script hit tab source let's just look for a file named main.js and actually at the start of that path out of slash so it just looks for it at the root of our domain so slash main js we can give that a save and now let's go create a file a javascript file that just alerts an annoying pop-up so before we can do that the question is well where should that file live so that it's accessible from just the root of our domain in other words if you look at server.js we know how to spell out routes for certain urls but how do you just make a file available well let's do this in our sidebar let's create a new folder and you could name it anything but let's name it public okay then in our server.ejs file maybe right after we set our view engine we can just say app.u in the parentheses express.static in those parentheses just quotes public okay you can give that a save in the public folder let's create a new file name main.js and just alert and say hello from javascript so we give that a save if we go refresh perfect so now instead of just a plain javascript file alerting that pop-up we would want this to use react right and we want to build out our user interface using react and then it would render into this empty div here however we can't just go into the main js file and start writing react and that's because react uses something called jsx now jsx makes it really easy for us the developer to spell out our html interfaces but web browsers don't speak jsx so the reason we can't just start writing react code in this file directly is because we need a workflow tool that will take our jsx and convert it into javascript that the browser can understand so in other words do this with me in the root of our project folder let's create another folder and i'm going to name it src for source right this is our source code for the client side javascript so now in the src folder let's create a new file i'm going to name it index.js and the idea is that in this file this is where we're going to build our react client-side application and then we're going to have a workflow tool that will convert whatever we write into regular javascript that the browser can understand and when it converts it it's going to output it into our public main.js file so to get started using react we know that we're going to need to download or install react so let's go use npm to do that so open up the command line i'm actually going to stop our current nodemon task so control c because we're going to want to create a new task that watches our client-side code for changes as well but anyways in the command line run this with me say npm install we know that we would want react but we would also want so space another package named dom right react for the web browser but that's not it let's grab a few other packages that will help us automatically convert jsx into regular javascript so we're actually going to install a bunch of packages right now so type this out at symbol babel forward slash core space and then at symbol babel forward slash preset dash react another space babel no at symbol this time just babel dash loader and then a space after babel loader we also want webpack and then as well we want webpack dash cli and then in space we want webpack dash node dash externals and finally just one more package we want something called npm dash run dash all that's it before i press enter if you want to pause the video so you can type this out that's okay do note that this is just jumping onto the next line so this is at symbol babel forward slash preset react okay let's go ahead and press enter cool now out of everything we just installed webpack is actually the key here so webpack is the automation or workflow tool that can automatically bundle up our jsx and convert it into regular javascript that the web browser understands so the question becomes how do we tell webpack to do exactly what we need it to do well in the root of our folder we just create a file and it needs to have this exact name of webpack.config.js now in terms of what should go in this new file well that's not super educational so we're not going to spend a ton of time typing out the exact configuration instead i want you to go to the github that i've linked for this video and just at the home page for this repository you'll see there's a file named webpack config.js so you can click on that file then click the raw button and then just ctrl a or command a select everything here copy it into your clipboard back in our webpack config file just paste it in and hit save now we're not going to go over this file line by line but to give you a bird's eye view essentially we're loading the tools that can convert jsx into regular javascript and then we're just saying that the entry point or our source code is the index.js file in the source folder we're saying that we want to output it into the public folder and name it main.js now this code down here at the bottom this is a bit of extra credit that we will touch on towards the very end of this video but for now we don't need to overanalyze this file you can go ahead and close it okay now the question becomes how do we actually tell webpack to start transpiling or compiling our javascript well i need you to jump into our package.json file with me so remember this scripts area when we created our server we're going to create another script or task right now so maybe on this line i would say quotes we could name it anything but why don't we name it our webpack colon quotes be sure to end that with a comma in the quotes just say webpack and then a space dash dash watch so just like nodemon was watching our server file for changes webpack can watch our client-side javascript for changes and anytime it detects a change it will rebundle or re-transpile things for us cool now to avoid us having to run both of these tasks right one for the back end and one for the front end why don't we create a task so a new line i'll name it dev you could name it anything but colon quotes comma and let's just have this one command run both of these commands so in the quotes i would use the run dash p that's why we installed the package named npm run all it gives us this command which lets us run multiple commands in parallel so at once and then just say you know our server space our webpack we can go ahead and save this file and now to test it out down in the command line just run npm run dev press enter to really test this out jump into your source folder index.js file and let's just alert a pop-up that says testing if webpack is working so give that a save and now if we go refresh our website and remember it's the slash admin url that's actually loading the client side javascript if i refresh perfect testing if webpack is working so what's going on is webpack is taking this code and then it's going to output it into our public folders main.js and that's what the browser is actually loading in other words in this index.js file we are free to actually start using react now so let's get started let's get rid of the alert and start working with react just to note i'm going to move very quickly with react this is not a video about learning react from the ground up i already have a 10 part series on my channel called the 10 days of react and i also have a video that's over an hour long on learning how to work with state and react so in this video i'm assuming you've at least heard of react maybe you understand what it is right it's a front-end library it lets you break your code down into components but maybe you're curious how it fits into the bigger picture of web development or how to set up something real world with it so on and so forth so if it feels like we're moving way too quickly with react you might want to watch another react tutorial after this video but anyways let's go ahead and get started so we would import react from the react package let's also import and then we're going to destructure it and we want create root from the react dom package future brad here with a quick interruption at the end of this package name it should actually be forward slash client like this so react dash dom slash client i forgot to include the slash client until about 30 minutes later into the video so if you see my code looking like this don't worry it's indeed supposed to look like this okay let's create our overall component so we'll just say function we can name it app parentheses curly brackets to start out let's just return a div and inside we can have a heading level one that says hello and maybe a paragraph that says hey let's actually say hey this is from react just to be clear all right and then down at the very bottom below that function let's just say const root equals create root in these parentheses we're going to give it that empty div that has an id of app so to refresh your memory remember in our views folder in admin.ejs that's why we created this totally empty div with an id of app our client-side javascript is going to hook onto this div and render its interface inside of the div so that's what we're going to target so back in our index.js that's what we're looking to target in these create root parentheses so we'll say document.queryselector hashtag app for an id of app and then below this line the final line is just root dot render what do we want to render our overall app component so sort of a self-closing tag that looks like this right app and then forward slash greater than let's go ahead and hit save and now this syntax here this looks like html but we're in a javascript file that's jsx and a web browser does not understand this so the idea is that as soon as we hit save webpack is going to take this code convert it into regular javascript and that's what's going to end up in our public main.js file so if we go back and refresh awesome hello hey this is from react and just for a quick timeout and tangent if you were wondering how i was getting html tab triggers or emit triggers in the javascript file here well down in the bottom corner you can just tell this file to use javascript react instead of javascript for the syntax that's a bit annoying though because you would need to set that every single time you open up this file so personally what i do if you go into your vs code settings so hit control comma or command comma and then hit this icon this area that i'm highlighting right now you can see i've permanently told my vs code to just treat any and all javascript files as javascript react at all times this might seem a bit gimmicky or hackish but it works great and i've never come across any cons or drawbacks also onto just a random note if you're wondering about ejs maybe in your ejs files your vs code was a bit awkward or getting confused just know that there is this great extension in vs code called ejs language support by digital brain stem so that's what i have installed that makes working with ejs files a bit easier okay that's enough on the tangents let me close those files and let's focus back on writing our javascript code our react code let's give ourselves a goal so let's imagine we just want to output a list of the animals right so whether there's two animals in the array or a hundred animals in the array we want each animal to have a little bit that says hi my name is meowzalot and i'm a cat you know hi my name is barks a lot and i'm a dog so to practice staying organized you could spell out that interface right here in this top level jsx but why don't we create a separate component called animal card so down here i would just say function animal card parentheses curly brackets in the parentheses let's have a parameter called props and then all that this function needs to return so return if you had multiple lines of html you'd have parentheses if it's just one single line of html you don't even need the parentheses maybe let's just return a paragraph that says hi my name is blank and i am a blank and then instead of this blank it would be curly brackets to do something dynamic in jsx props dot name and then ima this would be curly brackets props dot species so now imagine in our overall app component you know maybe we had 50 or 100 animals it can just loop through the array of animals and use this once for each item before we fetch the real data let's just hard code this as a quick example so up in our app component let's make up a bit of fake data so you could say const animals equals an array each item would be an object right so name meow's a lot comma species cat and then comma one more object name bark's lot comma species dog but you could use your imagination that this array has a hundred items in it and then maybe below this paragraph you could just say curly brackets to do something dynamic we could start working with this array of data so animals dot map to do something once for each item in the array in map we give it a function i'll actually spell it out i think it's a bit more intuitive seeing it this way than an arrow function but see function parentheses curly brackets in the parentheses we'd give it a parameter so this is the current animal that's been looped to in the parentheses we'd want to return something and what we would want to return is just a bit of jsx only instead of spelling out a paragraph that says hi my name is you could just use our animal card so we could literally just return animal card self-closing tag so a self-closing animal card to use this component and then just give it a few props of name and species right so name equals animal.name right the current animal that's been looped to and then species equals curly brackets animal dot species so you can save that and then refresh cool looks like barkslot's missing his species that's because i had a typo here and the second instance of species cool but you get the idea so now instead of this fake hard-coded array imagine if this data was actually pulling from our database well let's do that now let's make that happen our first step would be to go into our server.js file and create a new route that just outputs raw json data instead of an html document so for example maybe right below this admin route i would just spell out a new one so app.get we give it two arguments so a b as placeholders the first one is the url so it would be slash and i'm just totally making this up but why don't we say maybe api animals okay and then the function for that so instead of this b it would be arrow function arrow symbol curly brackets in these parentheses let's have request and response and then we don't need to rewrite code to query the database we can literally just borrow this line of code right that queries for all animals so i would just take that line copy it paste it and then on the next line just say response instead of send or render we're going to use response.json and express will automatically send the right type of headers so that this is recognized as just raw json so in the parentheses just all animals let's give that a save and now we can go test it out in the browser so if you visit you know 3000 slash api slash animals whoops you'll get an error screen like this because i forgot to include the word a sync right before our function right you can only use the await keyword inside an asynchronous function so if i save that and try it again perfect so this url gives us just raw data with all of our different animals so now we just want to consume this url from within our client-side react code so let me go back a url back to our react page cool just slash admin and let's go back into our index.js now you could absolutely load that url using fetch but i'm a really big fan of a package called axios axios is definitely not necessary for just loading or retrieving data but when it comes time to actually send data i find axios to make things a lot easier so let's open up a second command line we'll leave this original command line running because it's got our different tasks that are watching us but we can click this plus symbol here to open up a second terminal and in this second terminal i'm just going to say npm install axios cool if you want to you can close that secondary terminal i'm just going to leave it open for now all right now at the top of our index.js file this react file let's just import in axios so import uppercase axios from quotes the package name and now in order to load the data from that url using axios in the react way we're actually going to use two react tools so on this line where we're importing react after the uppercase react add a comma and then curly brackets we want to destructure or pull out specific things from react and make them available as sort of shortcuts so we're going to say use state capital state and then comma use effect capital e at the start of effect cool now within our app component do this with me we can get rid of the const animals the hard-coded array in its place i want you to say const square brackets we're destructuring from an array we can circle back to what goes in these square brackets in just a moment but equals use state in the parentheses just give it an empty pair of square brackets that is our default value the starter value now we're just creating a piece of state for all of the animals and use state is going to return an array with two things inside it so that's why we're destructuring it so in these square brackets i would probably say and i'm just making up variable names here but i would say animals comma set animals so the first property lets us access the value and this is going to be a function that lets us update it in the future so now when the page first loads we're saying that the initial value for this piece of data or state is just an empty array so our jsx isn't going to have anything to loop through right it's going to loop zero times through an array that has zero items in it however as soon as we update this piece of state our interface will know to loop through that array and output right the appropriate content so now we just need a way to perform that request where we load the json only once right when the application first loads or when this component first renders because we wouldn't want to keep performing that request every single time this function reruns and reruns so in react a nice way of doing that is using use effect so let's say use effect we give it two things the first thing we give it is a function so let's just give it an arrow function the second thing we give it is a list of dependencies or an array of dependencies in other words these are the things that you're watching for changes and only when they change will react actually rerun whatever's in your function here now if you just give it an empty array react will know to only run this the first time that this component renders this is perfect so this is a great place to perform our network request now axios is great you can just await an axios request but you can only await inside an asynchronous function and you can't give use effect an async function directly so inside the body of this function here what i like to do is just say async function you can name it go or start and then just immediately call it the idea is that now where the cursor is we can use await so i'm going to say const response you know response from the server equals and then we're gonna await axios.get we're performing a get request with axios which url are we sending a request to slash api slash animals my cat just sat three inches away from the mic and it's checking out my coffee uh then right after that we don't know how long this is gonna take could be one millisecond could be two thousand milliseconds but once it finishes we can just use this function to actually update our state so set animals response.data so just whatever raw json the server gives back to us let's go ahead and save that and if we refresh awesome so we had three items in our database there's the third one if you really wanted to test this out you could go back into your database let me add a fourth document so i'll say name junior and species cat as you might have guessed if i refresh perfect now i don't want this video to dive into three hours of us just building an html and css interface with react i want to keep this video focused on the big picture understanding of how react fits into the puzzle of web development right so how it would relate to our server and our database so here's what we're going to do we're going to copy and paste the html and css and the basic user interface for our react app right for the create new pet form and for the layout of where you click the edit or delete button on a pet we're going to copy and paste that but then it will still be up to us in this video to write the code together that actually connects the dots between that interface and making anything happen on the server or the database so when you click on a button in react we need to connect that to our server still so really quick let's get the design and user interface aspect out of the way so do this with me back in vs code in our sidebar in our public folder i want you to create a new file and name it my dash custom dot css okay then what should go inside this file well just visit the github repo for this video on the homepage for the repo you'll see there's a file called mycustom.css so just click onto that click raw and just select everything here copy it paste it let's give that a save and then in your views folder jump into admin.ejs and up in the head section let's load that css file so maybe right below the title tag i would say link hit tab on the keyboard in the href value just say slash my dash custom dot css while we're here let's also add bootstrap's baseline css so in a different tab you can just google for bootstrap or gitbootstrap.com scroll down just a little bit we only need the css we do not need the javascript so here we see include from the cdn and then this link css only i'm just going to click this button to copy it to my clipboard and then right above that line where we just included our css just paste it in right here cool let's give that a save and finally before we jump back into react let's make sure that we have a fallback image in place for the image avatars right so before we get to the animal image upload feature it'd be nice if we had a fallback or placeholder image so back in the github repo on the homepage for the repo you'll see there's a file named fallback.png just go ahead and click on that so just it's just gray it says no photo available just save that into your downloads and then just move it to live inside the public folder in vs code so i believe you can even just drag and drop it right so here it is fallback if i just drag that into vs code's public folder perfect close that at this point we're ready to jump back into react now again i don't want this to become three hours of us spelling out you know html elements and class names in react so here's what we're gonna do to save a ton of time in our src folder right that contains our react client side code in the src folder i want you to create a subfolder and name it components in the component subfolder i want you to create two files so let's create one file and name it create new form and i capitalize the first letter of each word dot js in the components folder i also want you to create one more file and name it animal card dot js now in these two files let's just go borrow code from my github so we'll start with animalcard.js so from the home page for the github repo you can click into this folder called finished product reference yes you could just download this entire folder and use that but that would you know remove all of the educational value here but if you go into the src folder and go into the components folder here you'll find the code that we're going to borrow just for these two files just to save some time so if you go into animalcard.js click raw just select everything in this file copy it into your clipboard back in animalcard.js paste it in hit save and then do the same thing for create new form so if we just go back in the components folder create new form.js click that click raw select everything here copy it back in our new empty create new form just paste it in and save cool now we just need to go into our index.js in the source folder and actually use those files so up at the top let's pull in those separate components so maybe below this axios line i would say import create new form from quotes and then dot slash so we're starting in the same directory that this file lives within but then we're looking inside the components folder and then just the file is create new form and then right below that do the same thing for animal card so import animal card from quotes dot slash components slash animal card okay now within our overall app component let's spell out sort of the top level overall template or jsx so we can keep this overall wrapper div but let's give it a class so in jsx you can't just say class equals because class is a reserved word in javascript so we say class name and then react we'll be sure to convert that back to just class when it actually renders it to the dom anyways let's give it a class name of container let's get rid of this heading level one maybe instead let's have a paragraph and inside it we can have a link that just takes you back to the home page and this can say you know let's have a little left facing arrow so ampersand l-a-q-u-o semi-colon back to public home page okay then below that we don't need this hey this is from react instead let's include the form where you can create a new animal so self-closing create new form tag let's give this a prop and let's pass into it set animals so that in other words this function right so that it can add new items to our data right when we create a new pet from the browser we want this form or this component to be able to update this state so we just pass it as a prop we could say set animals equals curly brackets set animals cool now let's add a little bit of html that has no purpose other than just css styling reasons but essentially before we start looping through the animals so add a new line here i'm going to add a div with a class name of animal dash grid this is just for css purposes and then you can see vs code tried to auto complete and put the closing div tag right here we would just move that to live after the animal loop so right here finally let's just give animal card a few additional props so let's give it one called key key equals curly brackets animal dot underscore id for react's own performance reasons when you're outputting a list of items you want to be sure to give each one a unique key value let's also pass in their photo value now at the moment right in our database each animal doesn't have a photo value but we're going to add that in just a little bit in this video so in addition to passing in you know name and species i would just say photo equals curly brackets animal.photo let's also pass in their id right so in the database right the underscore id each animal has a unique id value so i would just say id equals curly brackets animal dot underscore id and finally we do want each individual animal card to be able to update itself or delete itself so in other words we would want to give it access to that state function called set animals so i would just give it a prop set animals equals curly brackets set animals let's go ahead and save this and test it out so back in the browser i was going to be surprised if it worked on the first try so anytime i go more than 20 seconds without testing something in the browser i probably made a mistake somewhere so what you can do is just right click on the website click inspect and we're just going to look at the console it should give us a hint as to what's wrong so it says identifier animal card has already been declared that makes perfect sense right so back in our index.js file since we're importing you know create new form and animal card we don't want that function in this file any longer so towards the bottom go ahead and get rid of this you know simple placeholder animal card function that we had just delete it entirely let's go ahead and save the file test it out again so if we refresh and again i'm refreshing the slash admin url perfect so there is the create new form to create a new animal but if you scroll down awesome you see a list let me zoom out a little bit there is a grid view for all of our different animals from the database cool so we didn't spend the time to actually write out the html and css to make it look like this but that's not what this video is about what this video is about is making these edit and delete buttons come to life and making this create new animal button come to life right we need to tie that into our server and into our database but actually before we start working on those create update and delete features let's first not forget that the entirety of this slash admin section of our website that it should be password protected right the general public should not be able to view this url in fact we would want every url on our website except for the base homepage url to be password protected that way the public can view or load our data but they can't you know create update or delete any data now in this video we are going to use the most oversimplified way of password protecting something because if we didn't this video would become a three hour video about password hashing and cookies and csrf attacks and protection sessions and tokens and so on and so forth if you're interested in learning how to actually set up a real account registration system like that where you can register for a new account and log in and log out you might be interested in my premium 27 hour full stack javascript course on udemy in that course we build a simple social networking app and along the way we take the time to actually learn about authentication but in this video we're going to set up a super oversimplified username and password system just to keep this video somewhat short and digestible so how do we set things up so that anyone in the world can visit this url but in order to visit this url you need to know the secret password well let's jump into our server.js file together and to make this happen we're going to create our own custom middleware function so up towards the top of our server.js file maybe right above our app.git route so maybe right about here let's create a function the name doesn't matter i'm just making this up but just so you and i are on the same page why don't we name it password protected parentheses curly brackets now you heard me use the phrase middleware so what in the world is a middleware well the function that we're creating here can be used for any route so remember when you spell out a route first you give it the url that you're looking for and then the second thing you give it is a function well you can provide a third argument and a fourth and a fifth and a sixth and a seventh argument you can just keep giving this as many functions as you want just comma separated functions and the idea is that express will call those functions in order so essentially we're just going to use this password protected middleware function as sort of a gatekeeper well we wouldn't do it for the homepage url but for example for admin we could tell express right about here that hey you need to run the password protected function before you run this function let me show you how this works so in the parentheses for password protected we give it request and response that might seem intuitive right because obviously a function would need those things but we're also going to give it a third parameter called next so express will give us this and then within our function we can call that whenever we've determined that things should actually move on to the next function so in the body of our function let's do this let's say response dot set and we're just going to say www dash uppercase authenticate comma basic realm equals and now we're already inside of double quotes so i want you to include single quotes inside the pair of single quotes we're just making up a name maybe call it our mern app on the next line let's set up an if else block so if parentheses curly brackets else okay now for the condition let's say if request.headers.authorization if that equals and then we're not actually going to type this in so it doesn't matter what you include here just type something that you're not going to type in the password input field because we don't even know what we want the correct password to be yet so it does not matter what you enter here for the next 30 seconds but the idea is that if someone input the correct password then we would just call the next function right so essentially our gatekeeper function would just say hey express you can run the next function for this route if they got the password wrong then we could just say dot response.status throw a 401 error which means unauthorized and then let's say dot send and just say try again cool now in order to find out what we would actually want the secret password value to be do this with me before we send back our status in the else block i want you to say console.log request.headers.authorization cool so we've spelled out our middleware function now we just need to use it so let's go set it up for the admin url so after you've spelled out the url you can start to include functions and you can have more than one so after this comma you could just say password protected comma you know and then you have your next function so you can absolutely use a middleware individually for each url like this so if you also want to protect our api animals url right about here you could just say you know password protected comma but in our case i'm gonna actually get rid of those i know for a fact that i want to password protect every single url except for the base homepage url so here's what you can do the ordering matters here so after we've spelled this out i'm going to say any urls that come after this should just use our password protected middleware so just app.use and that's going to use it for all routes and then just our function name was password protected and just to be clear the ordering here matters if i would have included this line before the homepage route then even it would be password protected but because it comes first it will not have this applied so i'm going to go ahead and save this and then i want you to open up your command line so that we can see what's getting logged to the server's console so yes you can visit the home page url but if i try to visit slash admin perfect now let's fail the login on purpose so just type you know one two three one two three obviously that fails however in the server's console you see this value so the combination of your username and password that's getting base64 encoded and that's the value we see here so in order to determine what we would want this correct value to be i just want you to try to log in with the username and password combo that you would actually want to use i'm not actually going to push my app onto the web so i'm just going to choose the super insecure combo of admin and i'm going to also make the password admin so if i try to sign in with that it fails but now we know that the base64 encoded string for admin admin is this so what you can do is just select that copy it into your clipboard and then use that for your if check so if the authorization equal equals and then just use that value just paste it in cool so go ahead and save that and now if i you know refresh and try to log in with admin admin it's a match it lets me in perfect and your browser will remember that so if you refresh you don't have to keep entering it again and again however that's chrome if i open up firefox where i have not logged in yes i can visit the home page but if i try to visit slash admin perfect and if i enter the wrong password there's no way i am not getting in now obviously this would be susceptible to a brute force attack but setting up a perfectly secure login system is nine billion percent outside the scope of this video the point is we have implemented a very basic password protection with that set up we can jump back into react so let's try to connect the dots between when this button in react gets clicked on and how our server and database can actually add a new animal to make sense of what's going on here let's go look at the create new form react component so in our src folder in the components folder jump into createnewform.js so down in the jsx you can see that we have this html form and when it gets submitted it's going to run a function called submit handler so if we go look for that function it's got a little bit of extra code here because we're not just sending a simple form we're sending a multi-part form because we want to be able to send a file the photo that you can upload we can talk more about that later but really what i want to draw your attention to is ultimately it's just going to send an axios post request to the url of slash create animal so what we need to do is go into our server and create a route for when you send a post request to create animal so let's go do that so right now jump into your server.js file and maybe down below the api animals function or route i should say let's spell out a route so app dot and it's not get it's post so a get request is when your browser is trying to retrieve data a post request is when the browser is sending data so when the server receives a post request and the url is slash create dash animal then we just want to run a function so let's spell out an async arrow function so arrow symbol curly brackets in these parentheses let's have request and response now before we get too many steps ahead of ourselves let's just log to the console what the browser is sending to the server so we can make sense of what's coming in before we try to save it to the database so let's just say console.log request.body and then we can just send back so response.send thank you now before we save this and test it out i wish this was included in express by default but in order to easily access the data that the user is sending across we do need to go up towards the top and maybe before the password protected function just type this in with me app.use in the parentheses express.json that's a function we're calling it and then let's also include app.use inside there say express.url encoded in those parentheses have an object say extended false so what are these two lines doing this line is making it so that if a browser sends json to the server we can easily access that data and this line is saying that you know if someone instead of an asynchronous request if they just submitted a traditional old-fashioned html form well we want to be able to easily access that data as well now 9 times out of 10 or even 95 times out of 100 these lines are all that we'll need right someone's either sending an async request with json or they're just submitting a traditional html form however in our case we want the user to be able to send along a photo or an image of the animal and in order for the browser to send a file like that it needs to use a special form type called multi-part so i guess what i'm trying to say is that normally if you were just sending plain json data or a form we could go simply access request.body down below in our route but because the browser's sending a multi-part form we need to take one more step in order to easily work with multi-part forms in express we're going to install a package called molter you really only ever need this if you're going to let users send you files but to implement this let's open up our command line i'm going to jump into my secondary command line where i can install packages so i'm just going to say npm install and it's molter so m-u-l-t-e-r cool once we've got that installed up at the top of our server file maybe right below this line where we pull in express let's just say const multer equals require in the multer package and then right below that line let's say const upload equals and then just call multer again just to be clear you only ever need to do this if you're letting users upload files anyways now if we go back down to the route for create animal because this route in particular is dealing with a multi-part form we would want to include that upload middleware so after we've spelled out the url but before this first function here let's just include upload dot single quotes photo i'll explain what this means a little bit later on but essentially if you go look at the form that's being submitted the field where you can choose a photo it has a name of photo and so we're just making that available right you can only upload one single file anyways with this in place we can save this and now remember our goal we just want to see what gets logged to the console before we try to save anything into the database let me go back if i refresh the page for the animal name i'll just choose testing one two three four five species of hamster if i click create new animal and then go look at my server's console we see it's an object and it has different properties so photo is empty because we didn't do anything with it or i should say we didn't even choose a file here but name testing12345 species hamster so let's do this let's work on saving a new document into our database with the name and species and then once we have that actually working then we can worry about the photo feature all right now before we actually save any user submitted values into our database we need to be careful we have to assume the worst and that means that people will try to submit malicious values now if we were using a mysql database we'd want to protect ourselves from a sql injection attack in mongodb that isn't really a threat but instead we don't want to let users submit a value that can get interpreted as an object instead of just a simple string right because the object could contain mongodb commands in addition to that we'd also want to probably strip out any html from the values they're sending before storing it in the database now this act of sort of cleaning up the data before we save it we're not only going to want to do this for the create animal feature but we'd also want to clean up the data when you edit or update an existing animal right we want to clean up the name and species values so with that in mind i'm going to create a reusable middleware function we could name it anything we could place this function anywhere in javascript function definitions are hoisted so anywhere in our code can access it even if we write the function down here at the bottom so maybe below the create animal route let's have a function and the name doesn't matter but let's name it our cleanup parentheses curly brackets because it's a middleware we know that we would give it request response and next all right now in terms of cleaning up the data here's what i'm going to do first of all i want to make sure that the name the species and maybe even the incoming id for an update action i want to make sure that those are simple strings of text i don't want any objects accidentally getting through so i would just you know there's a million different ways to do that but here's what i would do i'd say if in the parentheses if type of request.body.name if that does not equal a string right so if it is something other than a string then i'm just going to set it to be an empty string so request.body.name should now equal just an empty string and then i'm going to do this same thing for species so change that here as well and i'm going to do the same thing for underscore id underscore id okay next i want to create an object that only contains the properties that i'm interested in in other words when someone sends a request to our server they could manipulate their request to have you know 50 or 100 different properties that they're sending over but really the only ones we care about are you know name and species so what i'm going to do is just say request dot clean data so another thing that a middleware function can do is just add a new object onto the request object you don't want to get carried away and do this too often and sort of pollute the request object but i'm pretty confident that none of the packages or plugins we're using are going to try to look for something called clean data on the request object but i'm just going to say that that should equal an object and i'm going to say name and this is a great place also for me to sanitize the value or strip out any html right i don't want visitors to be able to inject html into database because then in the future when we load that value and perhaps display it on our website yes it's up to our view and template layer to not just output unescaped html but i like double protection right i don't want malicious html even living in my database and i'm going to escape it on the front end i'm sure there are a ton of different packages that can help you sanitize a string but i've had really good luck with one called sanitize html so i'm going to open up my command line go into the secondary command line and i'm going to say npm install sanitize dash html go ahead and press enter okay back in our code up at the top let's pull that in so just const sanitize html equals require the package name was sanitize dash html now let's go leverage this variable we made up sanitize html so in this object we were spelling out for name i like to call sanitize html and you give it two things so the first thing is the string of text you're trying to work with so request.body.name first of all i'm going to trim that to get rid of any extra white space at the beginning or end of it and then the second thing we give it is a configuration object so an object i'm going to say allowed tags empty array i don't want to allow any html tags comma allowed attributes an empty object i don't want to allow anything so i'm being very strict here i don't want to allow any elements any attributes so this way a user can't include malicious html or javascript in the value that's going to get stored in the database at the end of this line add a comma and then just duplicate that line to save some typing on the second copy instead of name i would set this to species and then it would be request dot body dot species.trim cool okay and then after we've defined that object but still within the overall cleanup function so right here i would just call next all right now we just go use this middleware function so we look for our create animal route and right before our async function so right about here i would just add in our middleware function named our cleanup comma cool so now in this function we can actually trust those values let me show you what i have in mind so let's add a new line and say db.collection right we're working with our mongodb database we're ready to actually save a new document into the database so the collection we named it animals and then that has a method called insert one as you might have guessed you give this an object now instead of having to spell out an object property by property that's why i already created request dot clean data right it's already an object with only these specific properties that i would want to save into the database at this point we need to stop and think about what our server should send back to the browser as the response what i mean is when the user creates a new animal when they click this button to submit the form at that point all the browser is aware of is the name and species values that they chose right the browser has no idea what unique id value was just generated for that new document also in about 10 minutes from now when we set up the server so that it generates a newly resized photograph of the animal right the browser has no idea what the new file name of that jpeg is going to be so i guess what i'm getting at here is we would want our server to send back instead of just the words thank you we would want to send an object that represents the new animal document back to the browser so here's how i would do that on this line while we're inserting one into the database at the start of that line let's say const info equals and then let's await that so who knows how long it's going to take but we want to wait until it finishes now the question is what does the insert one method return right what's going to live in this info variable unfortunately it's not going to be the entire new document but info is going to contain the id of the newly created document so we can just run one more query right below that let's say const new animal equals a weight db collection animals and we're going to use the find one method in those parentheses you give it an object we want to find by the underscore id that's the property for the value let's create a new instance of an object uppercase i lowercase d parentheses for the value that's where we're going to use info so we're just going to say info dot and now it needs to be inserted uppercase i lowercase d so in other words when we create a new document mongodb gives us a little bit of info and now we're using that to query for the newly created document that's going to live in this variable new animal and then that's what we can send back as our response so that way the browser will know everything that's going on in the new database document so instead of thank you this would just be new animal before we save this and test it out we do need to go import a mongodb tool named object id essentially what's going on here is we can't just give this a simple string of text all right in mongodb the id is not just a simple string of text it's its own object type so in order for this code to work we would just need to go up to the very top on our first line of code where we're destructuring from mongodb just after mongol client say comma object lowercase i excuse me uppercase i lowercase d all right let's save this and test it out so i'll refresh i'll say animal name fluffy species rabbit create new animal and if i scroll down cool we see it here but that just proves that react is working that doesn't prove that it's fully connected with the server to really make sure that things are working you'd want to open up your database and click the refresh button on your animals collection awesome let me pull this up just a little bit it's falling off the edge of the screen but there you can see the new document fluffy the rabbit if you're curious how our react form component was able to update the overall apps state to actually include that new animal here well after this video i'd encourage you to check out a video on my channel that i uploaded right before this video it's all about state in react so we're not going to get super into that because that on its own could take over an hour for this video i'll just give you a bird's eye view so if we go into create new form right here is the axios post request to create animal so whatever the server gives back to us as the response right new photo on the next line of code that's why we gave this component set animals remember that's the function that allows you to update state in the future so this line of code is just taking the previous array of animals and then it's adding on you know to the very end of it an array with just the new animal document and this is what the server sent as the response so this way the browser is fully up to date right it's got the id potentially the new photo and actually speaking of the photo let's set up that feature right now so let's make it so that when the user actually provides a photo for this field we resize it and save it into the server let me explain what i have in mind so in our public folder we're going to have a subfolder named uploaded photos and we're going to resize the incoming photo to be a lot smaller right we don't need a 6000 pixel wide photo so our node server can resize the image and save the appropriately sized image into this new subfolder now we absolutely could create that new subfolder ourselves right now manually but if you are going to be distributing this software oftentimes git will delete completely empty folders so what i like to do if we go back into server.js is just bake it right into our application code that when it first loads up make sure that that folder exists so before we can set that up let's go install just two more packages so in the command line let's say npm install i'm a big fan of the package that's named fs dash extra it makes working with files and folders in node really easy and then we also want another package named sharp sharp is a great image resizing and image manipulation tool in node so let's go ahead and install both of those okay and now let's go use them so up at the top of server.js let's just pull in file system extra so i'd say const i just make up a name of fse equals require the package name was fs dash extra while we're at it let's just import sharp as well so const sharp equals require the package name is sharp cool so maybe right about here i'll just even write a comment to myself you know when the app first launches make sure the public slash uploaded photo photos folder exists so to make that happen we can just say fse it has a method named ensure directory and because we're only performing this action once when the app first loads up i'm just going to use the sync the synchronous version we need to spell out a path to where that folder would live and because we want our code to work nicely on windows as well and windows uses backslashes instead of forward slashes here's what you can do we can just pull in const path that's part of the official node runtime something called path so we don't need to go install this from npm it just exists in node and then we can use that here so we'd say path dot join you give it comma separated values and then it'll be a path that works regardless of whether you're on windows linux or mac so we just say quotes public comma quotes uploaded dash photos cool so to test this out you can just save this file nodemon is going to restart our server and notice it automatically created in the public folder the subfolder uploaded photos cool so now let's just go into our create animal route and actually you know process the incoming value of the incoming photo so here's how i would handle that at the start of our function body so right about here i would set up an if statement and the check would just be if request.file exists if that evaluates to true that means someone has actually included you know a file with the name of photo in their request so only if that's true do we want to run this code now before we resize the potentially huge incoming image let's first make up a file name that we would want to save it as so i'll just say const you know photo file name i'm just making up a variable name here equals i'm going to use backticks to do something dynamic and then you could imagine that it would be some sort of value and then dot jpeg so let's leave the dot jpeg but hollow out that value and then say dollar sign curly brackets and i'm just going to say uppercase date and then call the now method so this will be a value that's unique every single millisecond i guess it's possible that you know two people could visit the website at once and upload an image at the same millisecond i'm not sure if that's possible or not but again this is just a beginner tutorial we don't need to build something that robust all right now we can use that photo name to actually save a file but before we save anything let's resize it so i'm going to await and then we're going to use sharp so when we call sharp in these parentheses you give it the actual image data itself so we can just say request dot file dot buffer if you're wondering where request.file is coming from molter is taking care of that for us remember we added that package called multer for multi-part forms when you're working with files it's taking care of that for us and it's making the file data available on request.file so this is pretty cool we don't even need to store the original photo that's getting uploaded anywhere on disk it's just in memory and then we are resizing it and then the finalized image that can actually live on the hard drive so at the end of this let's now call dot resize and let's make it this is totally random let's say it's 844 pixels wide and 456 pixels tall at the end of that let's call jpeg in those parentheses let's give it a configuration object say quality only needs to be 60 right we want the file to be nice and small finally at the very end here we'd call a method called to file and then we just provide a path of where we would want to save it so the folder structure and the file name so let's use path dot join and then you just give it comma separated values so public folder comma uploaded dash photos comma and then the name of the file itself is just photo file name right the current millisecond dot jpeg cool on the next line still in the if statement let's just say request dot clean data dot photo equals photo file name in other words we've saved the resized photo to our hard drive and we're adding that file name onto the object that we want to store into the database right request.clean data so then in this code down below when we insert it into the database that photo property will just exist in the database document so let's test this out let's give it a save and go back to the browser i refresh let me choose a file so you would need to have an image laying around on your hard drive somewhere i'm a big fan of the website called unsplash but i'll use this picture of this dog and i'll just say example dog for the name species dog click create new animal if i scroll down perfect there's the image let's go actually find it on our hard drive right so mern project public uploaded photos there it is it's only 28 kilobytes so perfect it got resized and if we go look at our database if i click refresh right about here awesome notice that example dog now has an additional property of photo and it has that specific unique file name all right let's keep moving forward before we work on the edit or update an existing animal feature let's work on the delete feature we'll save the edit feature for last because it's the most complex so to get started on the delete button before we worry about the server side of things let's go look at what the client side javascript is doing when you click on a delete button so in the src folder you can look in components click into animal card around line number 71 so this area here that's the delete button so you can see that when it's getting clicked on it's just sending an axios request and more specifically it's not sending a get or post request it's sending a delete request in a delete request you can't send along an object with data you're just sending a delete request so essentially when you're spelling out which animal you want to delete you just bake that into the url that you're sending the request to right so this is sending a request to slash animal slash you know and then 123 abc whatever the unique id for the animal is that's it it's up to the server to make sense of that incoming delete request and url so with that in mind let's jump back into server.js and let's set up a new route for deleting an animal so maybe below this create animal route i would just say app dot delete right for a delete request the route was slash animal slash and now this is going to be different for each one right every animal has a different id value so what you can do is just say colon id and now it's a dynamic parameter okay after that comma then our function so async parentheses arrow symbol curly brackets in these parentheses be sure to have request response now because the incoming id of the animal they want to delete is going to live in the url instead of an incoming body of data that means that our cleanup isn't going to get to run on the id so just to make sure that that id is a string value and not in any way something that could be misinterpreted as an object right because i don't want a user submitted object getting anywhere near my mongodb database i'm just going to say if type of request.param params is how you can access the wildcards in your url so because we said colon id we can access that on request.params so params.id whatever you named it here if that does not equal a string then i'm just going to set it to be an empty string so request.params dot id equals empty string cool so now i'm safe to use request.params id in my actual mongodb code so on a new line we can just say db collection ours is named animals it has a method called delete one you give it an object based on underscore id we're trying to delete the item where new object id is whatever was in the url so request.params.id after that to end the request we can just say response.send you know good job or thank you our front end doesn't need any specific value we just need to end this request before we save this and test it out let's think about what should happen if you delete an animal that had a photo associated with it now we don't need to do this but i think it'd be cool if when you delete an animal we also delete its related jpeg from our uploaded photos folder so to make that happen here's what i would do right above this db collection line we just wrote i would look up the document based on the incoming id that way i can find out its photo value so i'd probably just say const i'll just name it doc i'm just making up a variable name you know for document equals await db collection animals find one curly brackets underscore id where new object id is request.params.id cool so now on a line right below that i can just say if doc.photo right so i'm saying only if the item in the database actually has a property called photo only then do we need to delete a file right if it doesn't contain that there's no file to delete so if that's true we can just say fse.remove and then you just spell out the file you want to get rid of so path dot join quotes public comma quotes uploaded photos comma and then the name of the file is doc.photo cool let's save this and test it out and really let's test it out specifically on that cat that i just created or excuse me this dog that i just created so refresh we only have that one jpeg in our folder but if i go ahead and click delete on that dog cool react got rid of it that photo is gone and if i refresh my database the dog is gone perfect at this point let's build the final feature of our client-side javascript which is the edit or update an existing animal so currently if you click the edit button yes it changes the interface so here you can choose an image here you can change the name and species but nothing is actually being sent to the server until you would click this save button so let's go take a look at where react is trying to send that data so back in the animal card component file when that edit form gets submitted when you click that save button it's going to call this function and around line number 28 we see an axios post request to slash update animal there's different ways you can handle this instead of a post request we could have used a put request and then include the id of the animal in the url i went with this route just to keep things simple just to not introduce yet another type of request anyways let's go into our server.js file and set up a route for update animal so in server.js maybe just right below our delete request we can say app.post when someone sends a post request to slash update dash animal comma let's go ahead and use multer so upload single we're looking for a field named photo after that comma let's use our reusable hour cleanup middleware comma and then finally we can provide our actual function so async in the parentheses request response arrow symbol curly brackets the first thing i'm going to do is differentiate between a request where they did and didn't include a new photo right so are they just trying to change the name and species or did they actually include a new jpeg so i would just begin with if and an else block the condition would be if request dot file right if that's true that means they they included a file that they're uploading i'll even write comments just to stay organized so if they are uploading a new photo down here i'll say if they are not uploading a new photo cool now if they are including a photo we don't need to reinvent the wheel we can just scroll back up and look in our create animal route and just borrow these three lines of code right that come up with the millisecond unique file name the sharp code and then adding that to our clean data object so i would just take those three lines of code just copy them back down here in the if block just paste that in cool and then still in that if block let's go ahead and actually perform that update in the database the reason i'm going to include that in the if block is because i want to retrieve a little bit of data about the old document that we're updating essentially i want to see if it already had a photo previously i want to delete that old photo from our hard drive so i would just say const you can make up a variable name i'll call it info equals await db collection ours is named animals we're going to use a method called find one and update in those parentheses give it an object comma the second argument is another object so the first object is you're trying to find a document in the database so we want to find it based on its underscore id new object id and that would just be request dot body dot underscore id so when react sends over the request with the new name and species it's also sending over the id for the one that's trying to get updated the second argument this is where we spell out how we want to change the document that we found so we can say dollar sign set colon and then just provide a new object so i'm just going to say request.clean data cool now right below that line i'm just going to check to see if the old document so when this operation runs it's going to give us back information about the previous version of the document before we updated it so i'm just going to look at that and see did it already have a photo if it did i'm going to delete that old outdated photo from our folder so i would just say if condition would be if info.value.photo if that's true just use fse to remove and then to create a system agnostic path it would just be path dot join public comma uploaded photos comma info.value.photo cool now finally after that if statement but still in our overall outer if i'm going to send back to the browser so response.send photo file name so our react if it gets a response that evaluates to true it's going to interpret that as the new name for the new photo right so imagine this was a picture of a dog but then you clicked edit the browser doesn't know the url for the new jpeg so we're sending it back as the response if instead we send back something that evaluates to false then react will know that it doesn't need to update anything extra so now let's work on this code so if they are not including a photo we would still want to find and update something in the database so to save a lot of typing you could just borrow this code so from db collection all the way to the end of the line right just paste that here i'm not even going to bother awaiting until it's finished because in this case the client doesn't need any new data right if they didn't include a new photo the client the browser already knows the new desired username and species so let's just end our response so response.send and just send back false cool let's go ahead and test this out so i saved that file back in the browser let me refresh whoops uh let's see what the error is if you go to the command line duplicate parameter name request request aha okay so around line number 71 when i spelled out the async function obviously the parameter should be request and response not request and request cool let me save that again and test it out so first let's just try updating an existing animal without worrying about a photo so maybe i'll add a few exclamations to the end of this name and the species click save actually refresh to make sure that it was saved in the database perfect let's try adding a photo to an animal that previously didn't have a photo so i'll click on pers loud choose a file choose this image click save cool so now in our uploaded photos we just have that one cat image let's try updating an animal that already has a photo so i can click on edit again choose a different cat picture so if i choose this photo click save cool it deleted the old photo now i just have that photo at this point that means we have completed the client-side javascript or the react portion of the project now we're going to move on to the final feature which is a little bit of extra credit here's what i have in mind if we go back to just the home page or i guess you could use this link right so the public just base url it's still using this super boring looking list so wouldn't it be cool if this public listing page could use the exact same animal card template so that it could list them and have them look like this better yet since our public front end doesn't need any interactivity it doesn't need client-side javascript wouldn't it be cool if our server could speak jsx and literally use that same animal card react component to generate you know static html on the server side so in other words the browser for this public homepage url it would not even need to load a single ounce of client-side javascript the server would just send it traditional old html but it could look exactly like this now if you've ever heard of something called next js you know that using a react component for both client-side javascript and server-side rendering that's not a new concept it's been around for a long time but i think this will be a cool experiment to actually set it up yourself or to see it in action yourself where there's not just a bunch of magic happening let's get started so just like the web browser doesn't speak jsx our node server environment doesn't speak jsx either so what's going to make this possible is webpack or i should say babel earlier i promised you we would look at the bottom half of our webpack config file so right now let's do that in the root of our project jump into webpack config don't worry we don't need to change anything in this file i just want to show you what's going to make server side react rendering easy and possible so this is just standard you know jsx transpiling this is for the client side the browser but then i also have something called server config so it's going to use our server.js file as the entry point it's going to output server dash compiled and this is why we installed that package called node externals when you're using webpack to bundle things up for the browser yes you want to include all the dependencies in the bundle when you're working with a server side file you don't need to bundle up everything into one file so node externals just makes it easy to work with you know third-party npm packages without having webpack actually bundle everything up okay and then down at the bottom instead of just exporting one configuration object we're exporting an array with both of them so we may not have even noticed it yet in this video but we have a file named server dash compiled.js so do this with me in the command line go ahead and press ctrl c to stop our task from watching us and then go into package.json and in our scripts area on our task that's named our server just change this from nodemon server to be nodemon server dash compiled so we can go ahead and hit save and then relaunch it right so in the command line npm run dev cool so what's the difference well now for just our base home page url we can use react and jsx on the server side so the browser doesn't need to run any javascript we're just going to generate a string of html on the server side let me show you how we can do this so jump into server.js and scroll up to the very top up where we're importing packages include these new ones with me let's say const react uppercase react equals and then just require in the react package let's also say const react dom server equals and then just require in the packages react dash dom slash server and finally let's pull in our animal card component file so i'll say const uppercase animal card equals require dot slash go in the source folder go in the components folder and grab the animal card file now just a quick tip our animal card file is using modern es modules or you know the modern syntax for exporting something whereas in this file we're in the node.js environment we're using common js it has a different way of you know requiring or importing and exporting objects from files so in order to get those two different syntaxes to play nicely together at the end here we can just say dot default and that way even though this file is exporting in a modern es module we can require it or import it here in common js cool so now we have all the ingredients we need right we have react we have react dom server and we have the component that we want to use now let's just go find our home page url route so for me that's around line 35 right a git request to just forward slash cool so we've already got a database query that will pull in all of the animals below that line but still above the response.render line so right here let's do this let's make up a variable name let's say const and i'll make up a name of generated html equals and now here's the cool part we can say react dom server and i know that in modern react there's something called render to pipeable stream that's ideal for a node environment and that's great you can probably get a bit better performance using that but i'm trying to keep this video simple so we're just going to use dot something called render to string parentheses to call that and now here's the cool part in these parentheses we can spell out jsx in between the parentheses we can drop down just so it's easier to type let's start with a div let's give the opening tag a class name of container inside that div let's have another div and give it a class of animal dash grid and let's give it a secondary class of maybe margin bottom three inside that div let's just loop through all of the animals from the database and we can reuse the animal card component so curly brackets for something dynamic in jsx just say all animals.map give this a function it only has one parameter so we'll call it animal arrow symbol and then we want to return something if we stay on a single line we just have one statement we don't even need to spell out the word return we would just want to return though an animal card component and then just give it all of the props that it would need so let's say key equals animal dot underscore id let's give it a prop of name that would equal curly brackets animal dot name give it species equals animal dot species let's give it another prop of photo equals oops curly brackets animal dot photo let's give it id id equals animal dot underscore id and finally yes in the admin side of things we wanted our animals to have the edit and delete buttons but for the public listing they don't need this whole bottom area with the buttons so i actually coded our component to where if you give it an extra prop of read only and you set it to true it just won't even display those buttons at all cool now maybe below this div so still in the container but below this animal grid div i'll have a paragraph and i'll have a link and it will point to the slash admin url and it will say you know log in or manage the animal listings cool so we now have this variable or this string of text or html called generated html you could just spell out an entire html document and just send that here so instead of using response.render you could just say you know response.send and send over a giant string of html but you can also mix and match so we can continue to use our ejs templates and check this out it's just instead of giving it the animals the raw data directly we can just give it you know generated html i like this approach because then in terms of you know your html boiler plate that can still live in the ejs file so we can save this go into your views folder and click on home dot ejs so in this file just get rid of every single thing in this file and let's actually to save typing let's just borrow the code from admin.ejs because it's already got our bootstrap and our css so on and so forth so just take everything in this file move it over into home.ejs copy and paste okay now we definitely don't need any client-side javascript this time around and we don't need this empty uh app div because there's no client-side javascript to render into it so delete that instead we would just use ejs so less than percentage you know generated html and to be clear here ejs is going to try to protect us it's going to try to escape whatever we give it so to tell it hey you can back off ejs you don't need to escape this you can just include a dash or minus symbol right here so that way the react generated html will actually render as html cool but let's go ahead and save that if we refresh awesome so the browser is not using a single ounce of javascript this is just old-fashioned server generated html which can be great for search engine optimization for accessibility initial rendering time it has a lot of different benefits and the cool part is that that one single react component file is now driving both this server generated page and our admin which is you know dynamic and client driven so i know this is obvious but it's just fun to drive the point home if we went into our animal card component you know and around line number 56 that's where the heading is for the animal if you change that from a heading level four to a heading level one click save that's going to update both the admin client side javascript and if we go back to the public server generated screen you get the idea so i think being able to share your code you know in both environments like that is really powerful this opens up so many doors and possibilities really quick at the end here if you didn't have any animals yet right so if i deleted every single existing animal and then went back to the home page this screen looks a little bit confusing maybe so if you wanted to add a conditional message that said you know no animals yet the admin needs to add a few let me show you what i would do so back in server.js maybe right above this line where we would start looping right above that i would just say curly brackets if the opposite of animals.length so in other words if the array is empty if there are no animals yet ampersand ampersand and then you can just include a little bit of html or jsx so i would just have a paragraph that says there are no animals yet the admin needs to add a few so you can save that for refresh cool whoops looks like i accidentally included that in the animal grid so just move that line to live right here right so inside the container but not in the animal grid cool so now you see that message but as soon as you add an animal go back awesome okay now that actually is the end of us working and building and coding this at the end here i do want to talk about a caveat and that is that a malicious user could very easily well first of all they'd have to have the admin username and password right but because we used a simplistic login mechanism someone could brute force login and if a malicious user had access to these admin urls they could crash our app pretty easily by just trying to upload a really huge photo file right that's like gigabytes large or maybe the jpeg file itself that they're uploading contains malicious code inside of it in terms of actually building something that doesn't have any vulnerabilities like that that's another topic for another day to give you a hint though in the real world if i was building something that the general public was going to be aware of so that you know a lot of people would be wanting to hack it i would never ever ever ever let people just upload files to my server like this i'm not saying it's impossible to build something secure like that but i would much rather use a service like aws or cloudenary in other words i'm going to trust people who have dedicated their entire careers to making sure that malicious users can't find vulnerabilities when uploading files so essentially you know you could generate a one-time use token on your server give that token to the visitor and then they would upload the file directly to you know amazon's hardware or cloud and area servers right and then it's the job of those services their entire job 40 hours a week is just to make sure that there's no vulnerabilities in terms of uploading files so maybe in a future video i can create a cloudinary tutorial right where we integrate our node server with you know letting users upload images to cloudanary that would be a much more robust secure solution but again that's another topic for another day cool that is going to bring this video to a close if you enjoyed this video you might also enjoy my premium courses over on udemy so i have a course entirely all about react we build the front end for a social networking app it's got live chat features you can follow users so on and so forth i also have another course about full stack javascript so this is the course where we actually learn about you know cookies and csrf protection actually letting users register for an account and you know validating their username and password so on and so forth anyways thank you so much for watching this video i hope you feel like you learned something and stay tuned for more web development tutorials [Music]
Info
Channel: LearnWebCode
Views: 43,588
Rating: undefined out of 5
Keywords:
Id: korRfKTDoxE
Channel Id: undefined
Length: 132min 0sec (7920 seconds)
Published: Thu Jun 02 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.