Complete MERN Beginner Course [2023] (TypeScript, Authentication, Deployment...)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
mobile development is for children all the cool people are doing web development so in this free course we will learn how to build a moon app from scratch Merin stands for mongodb Express react and node and those four together make a very popular text deck to build full stack web applications full stack means that we are building both the front end which is the part that you see on the screen in your web browser and the back end which is the server that your website communicates with and the server on the other hand has a connection to the database and so on but we will learn the details of this throughout this course we will also be using typescript in this course instead of vanilla JavaScript typescript is a superset of JavaScript so it's basically a like a layer on top of it you can use it anywhere you can use normal JavaScript but it adds strong typing to the language because if you build a medium size or a larger project in pure JavaScript than you are a lunatic because a normal JavaScript you don't have types and you can basically put every value into any variable at any time and it's just a matter of time until this whole thing explodes into your face typescript is absolutely Superior it's an awesome language and this is why we will use it in this course so before we continue let's take a look at the project we will actually be building here now as you can see the project is relatively simple but it will build a full Foundation that you need to build your own burn applications and I'm actually not a fan of these tutorials that adds too many features because usually no single topic is explained really properly the tutorial is really bloated and lengthy and no one actually finishes it so I like to focus on the important parts make sure that you understand these Concepts and then you can add more features on top of it later the goal of this course is to actually have you finished the project and we will even deploy it to real web server so you can run it on the internet and not just your local machine we will do that in the second video I will talk about this later and if you ever had trouble understanding the moon stack then this video will fix it because I will explain all the concepts that you need to know properly and as you can already tell we are building a Tinder clone no just kidding we are building a note-taking application and it will teach you all the crud operations so we will learn how to create newer nodes and add it to the database and the screen we will learn how to update existing notes how to delete nodes and of course how to display all these nodes on the screen we will also do some other stuff like simple form validation which is important so for example this title field here is required and only when we actually type something in we can save this node when we update a node this little text down here changes from created to the last updated timestamp we will learn how to navigate between different pages using react router Dom and for the UI we will use bootstrap which is a package that you can use for example with react that gives you a different UI components and design features and I know that Tailwind CSS is very popular at the moment but I still prefer bootstrap because I think it's easier to use it already brings stuff like modal dialogues for example that you have to build yourself when using Tailwind like this it's completely free it's in my opinion just easier to use and if we use CSS modules which we will do in this course then we don't have problems with clashes between different CSS classes so this makes the organizational of the CSS pretty simple in my opinion but if you don't know what any of this means don't worry we will learn all of this throughout this course so the navigation bar up here these buttons this model dialog that opens when we click a node all of this comes from bootstrap and we will also make our layout responsive so that when the screen size changes the layout changes which again is made easier by bootstrap so as you can see here at the full size we have three columns of nodes but when the screen gets smaller we have only two and then eventually we only have one column and also the menu up here collapses and as you can see this is a really nice view for displaying this website on a mobile phone so it's completely mobile responsive which bootstrap again makes pretty easy in my opinion entry will learn some CSS tricks like fading out this text here when the note gets too long so some of these little tricks and of course this Harbor Shadow effect and since this is supposed to be a full Foundation to build your own Moon apps we also handle authentication in this course using sessions and cookies so we can log out of our current account which makes all our nodes disappear and we can log into a different account or create a whole new one so because of my insane creativity I'm gonna call it ASD ASD the email will be similar and the password is ASD ASD okay this is a password suggestion this is not my actual password just making sure that I'm not leaking my personal data here anyway we can create a new account or this email address already exists so we also have validation for this on the back end so let's choose a different email address and try it again and we have our new account yeah let it go man which doesn't have any notes here so let's add a new note here as well which now belongs to this account when we log out and into our other account we won't see this node because each node is tied to a particular user isn't that amazing and again this is the foundation for you to later build more stuff on top of it this is the important pieces now we will talk about all these different features later in more detail and if you're wondering why I use cookie sessions here instead of JWT tokens I explain my reasoning behind this throughout the series but it's a nice and easy way to handle user sessions and it doesn't have some downsides that jwts have and after we have finished our project here we will deploy everything to a real web server only node which is a hosting provider you will find the second video only notes Channel and I will put a link to it into the video description below after you have finished this make sure to also watch the second video it will not be as long we will just deploy this whole thing and then you will have a real full stackdap application on the real web hosting then you can connect it to a domain and then you have your own website for your portfolio or you can build your own and project out of it whatever you want entry note was also so nice to provide a free credit for my viewers so you can go to leno.com coding and flow and you get a hundred dollars free credit available for 60 days again I will put a link to this into the video description below together with the link to the second video where we deploy everything now let's talk about the prerequisites of this course because this is not a foia beginner course we will not learn the absolute JavaScript Basics so we will not learn what the for Loop is or what a variable is I assume that you already know that but you don't have to know JavaScript for that to be honest if you know any programming language you will be able to follow along because they're very similar and I will explain the more advanced language features that we will use I will also explain how typescript works and we will install everything together if you know a language like kotlin for example also I think Swift is similar or Java then it will be very easy for you to understand typescript because the same thing at the end it's very similar we will also be using asynchronous JavaScript features so promises and async and the weight and I will again not expand this from scratch but you can just follow along in my opinion because these features are very straightforward and when you don't understand something either just follow along or Google it which is even better and again if you know kotlin for example then async await is very similar to kotlin coroutines and there are similar features in other languages as well the same goes for HTML and CSS I don't expand everything from the absolute ground up but you just need to follow along and unless you are a complete beginner and have never touched any programming language then I think you will be able to understand everything and whatever you don't understand just Google it I'm also a fan of not learning everything from the absolute Basics upwards because I think it's a boring approach to learning programming I much rather create a project and be okay with not understanding in every detail at the beginning and then you can still fill in the gaps later for example I never formally learned CSS I never learned the basics of it but I built actual projects that use CSS and when I later was wondering what a specific keyword or feature meant then I Googled it and learned it when I actually needed it I think that's a much more fun approach to learning programming than going through these beginner courses where you spent three weeks just learning the fundamentals of CSS that's super boring we will also install all the necessary software together so we will install node.js all the necessary packages we will set up our mongodb database you don't need to know anything about it and if something is unclear either Google it or you can also leave a comment below and ask other people or ask me I'm reading all of my comments basically I don't respond to all of them but I read all of them just one more learning tip for this course instead of just following along everything step by step I recommend that you build a project that's slightly different for example create a slightly different layout use different data types maybe even don't build a node app like I do here maybe build a to-do list app so that you use the same Concepts that you learn here but you apply them in a slightly different way I really like this approach because it forces you to understand what I'm explaining here and not just blindly follow along if you are a beginner and it's too difficult for you then you can also just follow along step by step no problem it's just a little learning tip I also want to quickly explain how a react Works overall so let's take a look at the app again when you use a react website then you will notice that it feels more like a mobile app almost rather than a classical website for example when we navigate to a different page you'll notice that the navbar here at the top stays in place and it doesn't reload so we are not actually reloading the whole page because a react app by default is a single page basically and all the contents within the single page are loaded by JavaScript script this is why when we switch back to the node screen you see this progress Bar for a short moment this is because we are not actually getting the full page sent from the server we are only getting the shell which is this page with all the static elements but without the data that we are loading from the server so without our nodes and then with JavaScript code we are loading these nodes and this is why we see a short progress bar and then all this pops up here on the screen just like a normal app our code is sending a HTTP request to the server and it gets back Json and then turns it into these nodes which you can see on the screen you don't need to understand this right now we will take a closer look at this later but if you're coming from mobile app development for example then this will feel very familiar to you because react websites are basically apps on the internet now since JavaScript is used to load the data this also means that react apps by default don't work without JavaScript so in the Chrome developer twitch we can actually disable JavaScript reload the page and you can see this little text here you need to enable JavaScript to run this app but this is usually not a problem because about 98 of all websites on the internet use JavaScript so it's very aware for our client to not have JavaScript enabled because it's required to view almost any website on the internet so let's turn this back on here and then we can see our website again now the so-called client-side rendering approach where the website loads more data from the server after it is already displayed in the browser has benefits and downsides you can Google them and read up on them if you want and there are also Frameworks that combine the best of both worlds for example next JS which is another framework on top of react where you have more control over what data you will load client-side and what pages you load servers out where all the data is already in the page that comes from the server I'm a huge fan of next JS it's my favorite framework for my own projects but it's quite an advanced framework and again it's built on top of react so you should learn normally react before putting hands on xjs and this course here will teach you all the foundations that you need to know okay and now the actual course starts and we will focus on the back end first so we'll build the server and the endpoints first then we will build our react website and connect everything together I will also put a link to the project on GitHub into the video description below so you can check out the code there and then I wish you a lot of fun and don't forget to like this video please and share it with someone that could need it it really helps the channel and it makes it more interesting for me to create more free courses in the future so it's a win for both of us alright have fun all right in order to write code we need a code editor and a very popular choice among web developers is Visual Studio code or short vs code which is a free code editor by Microsoft you can use this one you can use a different one it's up to you if you want to use vs code just go to a code.visualstudio.com or type the S code into Google download it install it the installation process is not difficult next we need node.js installed node is the n in the mirn acronym and node allows JavaScript code to run in a server environment so normally a JavaScript is meant as a language for web browsers so it only runs like in like Chrome for example but node.js brought JavaScript to a server so we can write our backend in JavaScript tool so again this is of course completely free you can go to nodejs.org or just type node.js into Google and here we want to download the latest ATS version ATS stands for long-term support and it basically means that you can use this version for many years without having to update it alright so we click this and download this and when it's finished downloading we click to install our file okay so now we just have to follow this wizard here next we read all the license agreement okay I've read everything next then we can keep this as it is next we can keep the defaults here as well add to path yeah looks fine to me particularly important is the node package manager which we later need to install packages and stuff like that but the default options here are shuts the files we click next again this option here should not be necessary for us so we can skip this click on next and then install and then we wait until this is finished all right looks like this succeeded so we click on finish and to check if this actually worked we want to open the command line so when Windows just hit the Windows key and type CMD and on a Mac it works similarly you probably already know how otherwise Google is and if you use Linux then you are a nerd anyway and you probably use the command line all the time we just want to check if note was installed properly so what you do is we type in node minus minus version and this should show us the latest version here we installed if it says something like node is not a recognized keyword or command then try to install it again maybe restart your computer maybe this helps otherwise Google installation instructions or leave a comment below so others can help you but if you followed along it should have installed it properly and when we type in npm dash dash version then it should show us the version of npm that we installed which is again the node package manager okay we can close this close this here as well before we start building our server let's first understand why we need a back-end server in the first place in short we use a back-end server for everything that we can't trust the front end to handle because whatever code we are right for the front end in our case our react code later is loaded into the web browser and everyone who is a bit technical or a programmer is able to actually look into this code even though it will be minified they can look into it and they can Tinker with it which means that we can't put anything secret or critical in there for example we can't put the credentials for our database into this code because users would be able to see this if they inspect the code we also can't trust form validation on the front end because even though it will be enforced if they use the website the normal way as it's intended they can still change it by tingering with the code and this way circumvent the restrictions we set up the back end our server on the other hand is like a black box that people can't look into because it runs on a different machine it doesn't run in the browser and the only way to get data from the server is by sending a message there sending a request and saying Hey zobo I want this piece of information and then the server says okay but do you have the correct credentials for that are you authenticated then the front end can send the password or whatever authentication method we use as an example and then the server ultimately decides if it fulfills the request or not but users can't go into our server and change code there or anything like that for Outsiders it's just a black box so to summarize our front end can't contain anything that's critical or anything that's secret as all goes into our backend the front end is only the user interface that communicates with the backend but it's not safe it's not secure all right now let's set up our node server and the first step is to create a folder somewhere on your computer where you want to save this project that's up to you and in here we create another folder which I'm gonna cut back end this will contain the code of our node backend project we go into this folder and in here we want to open the command line on Windows you do this by holding shift down and then right clicking and then open Powershell window here depending on your configuration this might open the older command line but it doesn't matter both are fine for what we want to do if you are on Mac or Linux you will also have a command line available just look up how you open it if you don't know how to do it there are instructions in Google okay let's make this here A bit bigger so we can see everything and in here we type in npm in it Dash wire and whenever we write something in the command line you have to write it the exact same way as I do or otherwise it won't work the command line is not very forgiving okay we type this in and press enter and it looks like it did something it created this package file here we don't see the file extension here in Windows right now but this is a Json file so the full name is package.json next we want to open this project with this file we just created and we could be old boring Boomers and open it through the escort but cool modern people open projects over the command line so we stay in here because as you can see we are still inside this backend folder that's important and then we could type in code and then space and period so code Dot enter and this opens this project in vs code now if this window here pops up we want to trust this project but this might not pop up for you and here's our package.json file which we created a moment ago this package.json file is basically the configuration for our project where we will also later have all the dependencies listed that we need all the packages that we use now since we typed in dash wire it used the default settings for all this meta data here and actually this stuff or most of it is only important if you want to release a library if you want to release a package for our server project that we use ourselves this is actually not important we don't need a description and the name and version doesn't matter keyword authors you can fill this out if you want but you don't need to we also don't need to specify a license because no one else will have access to our code and now it's actually time to install our first dependency oh that's exciting our first dependency will be typescript which we have to install in order to use this language instead of JavaScript so we want to open a command line again and we can do this directly inside the S code as well so we click up here on Terminal and on new terminal and here next to it you can see the shortcut for me it's Ctrl shift ER if you're not a German you probably don't have an ear can you use whatever shows up there okay now we have a terminal here and now we type in npm install dash dash save Dash Dev like this just type it the exact same way typescript or lowercase enter and this installs typescript in this project and as we can see this new entry here popped up in our package.json under this Dev dependencies queue dependencies are just packages that we use for our project for example later bootstrap is a dependency as well for our layout all these different libraries that others have made for us and that we can use and there are two types of dependencies normal dependencies and Dev dependencies def dependencies are the ones that we don't actually need in production we only need them while we are writing the code so we put this into the separate key here so that we later save space when we deploy this project to production because those ones here will be skipped those are only for development okay down here it also says new Metro version of npm available it's always good to update this so let's copy this command here and type it in you can paste it with a right click and press enter to install the latest version of npm we also see that it created two new entries appear in our file directory one is the package log Json which is related to the package.json we don't have to worry about this this is generated automatically and node modules contains the packages that we install the dependencies which is typescript in this case but there will be more in there later alright and a typescript project needs a typescript configuration file which contains some information on how a typescript should behave otherwise it won't work so we go into the terminal again and we type in npx this time it's not npm it's npx and the difference is that npx doesn't install packages it executes packages basically that's all we need to know so we type in npx TSC which is short for typescript but we have to type in TSC not typescript it might be short for typescript compiler I'm not sure actually just type in npxts here dash dash init enter and this creates a new file for us which is this tsconfig.json here let's open it and take a look in it a lot of scary stuff most of the options in here are commented out so they are inactive because they are optional and the ones here if you want to know what they are for you can read up on them we don't have to change anything in here right now it's all set up properly for us but we have to make some changes here later then we will get back into this fire okay now it's time to install Express and express is the e in the moon stack it's the framework that allows us to build the server basically so node.js is just the foundation where the code runs on and expresses the actual library that allows us to write the server code and the endpoints and everything so again in the terminal we type in npm so not npx this time npm again install and by the way there's a short form for install which is just I let's use this in the future without safe Dev this time because this is not a Dev dependency that goes in here like typescript it's a normal dependency which we need in production and then we type in Express enter and this installed Express here under this dependencies keyer for normal JavaScript project this is enough in a typescript project we often have to install also a package that contains the type so that our code works properly and typescript knows what types the different variables and functions have so once again we type in npm I for install types are def dependencies because we don't need them in production so again dash dash save Dash Dev add types slash Express type it the exact same way I did and press enter again which adds another entry in the dev dependencies the express types now this always installs the latest version of these dependencies if you watch this tutorial sometime in the future then these version numbers will be higher than the ones you can see on the screen and sometimes when these packages get updated things break especially when the number here at the very front changes if this happens some things I show in the tutorial might stop working because they change this meanwhile then the best way for you to go about this is to Google the changes you can read the release notes for the dependency on GitHub for example and try to implement the changes yourself if you can't get this to work and you can't figure out how to use the latest version then you can always install the version I used here in this tutorial so for example instead of just npmi Express you can also add at the end and add and then the version number which in this case would be 4.18.2 if you do it like this it will install this exact version and everything will work like it works in my tutorial but again it's better for you if you actually try to figure this out by yourself and now let's actually create our first little server so here on the left side in this file explorer we right click and create a new file TS stands for typescript if it was a normal JavaScript file then it would be dot JS but we are not peasants we use typescript here alright and for now just type exactly what I type here first we have to import Express into this file expresses the package we just installed so we type in Port Express from and then in quotation marks and in JavaScript and typescript code we can use single quotes and double quotes in most situations it doesn't matter I will use double quotes here just to keep it consistent and here we type in Express and semicolons at the end of a line are optional in JavaScript as well but it's good to practice to add them so that's what we're going to do here in the next line we write const app with const we create a variable that we can't change the value of later but again those are JavaScript basics and then we can't express like this and the app is basically our server this is where we later at different endpoints and everything we also have to define a port which is that to 5000 Port is basically a connection point on a server and you have to set this to a number some numbers are occupied already so there are certain numbers that people use by convention like 5000 or 8 000 but a lot of different ones will work you could probably type in 4993 and it would work as well but you will go fine with five thousand and also some web hosting Services require a specific port number so this always has to go into a consideration react for example users Port 3000 by default so we want to use different ports for both of them otherwise we can't run them simultaneously on our local machine okay and then below we take our app wherever there again and car.get and between the parentheses repairs a slash as a string so in quotation marks comma and then we pass an error function here which looks like this another pair of parentheses Rec comma address those are the two arguments that this function gets passed then we make a right arrow like this with an equal sign and a greater than symbol curly braces and in here we can write the code of this function so this is an error function here it's like a function without a name there's a similar feature in kotlin and other languages as well at the end of this get Curl here we put a semicolon before we forget it and in here we take this res cow dot sent and pass hello world as a string semicolon this is our first endpoint which we will call in a moment and we will get the string back but before this works we have to start the server which we do the following way below we call app.listen pass the port we defined up there 5000. and another error function but this time it doesn't take any arguments so it looks like this and this will start the server and this is basically just a callback and in this callback we want to show a lock message just so that we can see okay we actually started the server and there was no crash or anything so let's just write the log message in here which in JavaScript we do like this server running on Port colon and then we append the port number at the end again not the pulse port okay nice and nvs code by default you actually have to save your files it doesn't happen automatically so I press Ctrl s and now we want to start this whole Observer and normally a note if you want to start a file you type in node in the command line and then the name of the file so this would be server.ts the problem is this only works with JavaScript files because node doesn't know how to execute typescript by default it has to be compiled to JavaScript first and we do this with the following command npx again TSU enter and this turns this typescript code that we have in our project into JavaScript code as you can see here on the left it now created the server.js file and this is the JavaScript version of our server TS file this is automatically generated we don't have to understand this this is not how a human would write JavaScript it's how the compiler reads it with optimizations and everything we don't actually have to understand this file it's just interesting to take a look at it because this is the file we now can run when we type in node server.js this time and as we can see it now says server running on Port which is our own text that we typed into the Callback and here on Windows I also have to allow access that's fine okay and now our server is running on Port 5000 and now you can just open the web browser and type in localhost Colon 5000 into the URL bar and this is now our server here it says hello world congratulations you are now a note back-end developer the tutorial is over happy birthday no I'm just kidding of course this is just the beginning a real web server is much more complex than what you have set up here and by the way what we have said up here let's close this is a an endpoint for an HTTP get request if we open a website in a web browser it will do a get request if you have built apps with networking features before then you might know that there's also for example post request to send data to a server patch delete and so on we will use this other HTTP methods later to modify our nodes but yeah this is a get request and this is how we set it up by a culling.get on our Express app it's also a good idea to organize our code better because otherwise later when we compile our code we have this huge mix between JavaScript and typescript files for now let's delete this we don't need this right now we only need this when we actually run our server later in production so we delete this and for organization we create a folder in here which we call sr0 which is short for Source that's the source code of our project that's just a naming convention and we put the server TS file in there everything that's configuration for our project goes outside of source and into a source we put actual typescript files that contain the code for the different endpoints and so on and next we want to tell the typescript compiler that it should put these generated JavaScript files also into a its own folder so our project isn't clevered with it so we open the TS config file again and we search for the option that's called out dir so output directory we remove the comment here at the beginning so we activate this basically and we are append dist here at the end which puts the generated code into a folder called dist which is short for distribution and just because I have OCD and let's align this here again properly and save this file let's try running our npx TSC command again but first we have to stop our server while it's running we can't add any commands here so we press Ctrl 0 which stops our server no it's not running anymore and again we try our npx TSC to compile our typescript code you don't have to do this right now you can just watch me do it and now our code is properly organized into this this folder here which mimics the shape of our source folder and now if we want to run this file we have to type in node like before but this time just slash server.js because it's inside this this folder right so let's try it again the server is running localhost 5000 it's still there nice oh he was the old window but of course it's annoying to repeat this whole process every time we make a change to our code every time compile the project type in noise This Server and so on so we can install some dependencies that make this process much easier for us so let's stop the server again and delete this list folder here because we will only need this compiled code in production in development we will use something different the package we are used to automatically restart our server whenever we make changes to the code is called nodemon and as you can see on the npm Page by the weekly downloads it's a very popular package if you want to learn more details about this package you can check out its page here but it's pretty straightforward to use as you can see here we install it as a Dev dependency because we are only needed in development so let's copy this and paste it into command line and again it adds another entry in our Dev dependencies here now this only works with JavaScript by default but luckily there's another dependence here that automatically works together with nodemon to a transpile our typescript code into JavaScript on the Fly which is called TS node so again we want to install this as well and here's the command for that and by the way it is minus D with an uppercase D is the short form for dash dash safe Dev so we copy this paste it in here and style this as well and now instead of compiling our server TS file and then starting this server.js file that's generated we can just start our server TS file directly and we do this by typing in npx nodemon to execute nodemon and then our server TS file but it's inside our source folder so we type srz slash servo.ts and this now starts our server fire it works because we have TS node installed which compiles the typescript code on the flyer and not only that now if we make changes to any file the server automatically restarts so let's add the comma here between hello world because I think this is the correct way to write it save it with Ctrl s and as you can see down here it automatically restarts our server so now when I open localhost again we see the new version we don't have to compile anything manually it just works but we can make this even shorter we can go into our package.json file and add the script here a script is basically a shorthand to execute a command to be called this script start which is just a convention I think and then in quotation marks we type in the command that we want to execute and when we do it in here we don't need the npx we can just type in node mon and the same as before srz server.ts let's save this and try it out so I'm gonna stop the server down here with Ctrl Z and then I have to confirm it with a wire short for yes and now when we type in npm start we execute the script here which now starts not one the same as before nice we can also specify the main entry point of our server up here for our use case that's not necessary because on our Productions over later we will just run our server file directly but I think some web hostings need this so it's probably a good idea to still Define it and our main entry point will be a server.js file in the dist folder later this is where our server is actually started because nodemon NTS node are not suitable for production use let's save this again and there's one more thing we want to set up in this part and that's eslint so once again in the command line we stop our running server type npm install short I minus upper Castillo short for safe Dev eslint so we installed eslint to the dev dependencies enter and there it is with the latest version and then we type in npx eslint dash dash init which creates a new file which is a configuration file for eslint but we have to go through some short steps here in order to set this up need to install the following packages okay to proceed we type in y for yes to install this and then we configure this file and you switch options with the arrow keys on your keyboard how would you like to use eslint to check syntax and find problems that's reasonable what type of modules does your project use JavaScript modules import export this is what we use which framework does your project use react vue.js or none of these none of these because we are in node here does your project use typescript yes of course where does your code run browser or node as explained earlier this is running with node.js so we selected what format do you want your config file to be in and here we select JavaScript again and now it has to install some new dependencies which of course we do which package manager do you want to use npm which we have been using all the time and then it installs some stuff as we can see some new dependencies pop up and this newer.eslint rz.js file which is the configuration for the excellent now even though we selected node in the configuration it adds browser column true I don't know why I don't know if this is a bug but we should change this to node and save this and lint helps us find problems in our code some of those problems are errors where we just write invalid syntax and we can't run our code at all but some of these problems are just bad habits that we should avoid because they can cause problems later let's see an example of this one such bad habit is circumventing typescripts Knight safety or undefined safety so for example let's say the sport could be undefined for example because we get this value from somewhere else and we don't know if this actually contains a value or not this would work here because this method can work with an undefined Port but some functions would complain and I would say hey we don't accept and possibly undefined value here we need a number and one way to affix this is to actually check if the value is undefined or not just with a normal alt if statement but another way is to attend a compiler hey relax we know that this value will never be undefined which we do with this non-nine assertion operator which is an exclamation mark behind the variable this way we tell the compiler here we know that this port number will always have a value but as we can see here we don't actually know this we can make mistakes this way this is why it's a bad habit and eslint will tell us that this is a bad habit by running it so we type in npx eslint then the dot which executes eslin in this folder if I'm not mistaken right now dash dash exterior this way we Define the extensions of the files that we want to check and we want to check our DOT TS files so this is what we type in we press enter and now this checks our code and as you can see it found one problem forbidden online assertion this is just a warning it's not an error so our code would still run but this tells us here this is probably not a good idea and we should do something else with it so let's change the spec run it again and this problem will not show up again now of course it's a good idea again to create a script for this so we don't have to type this out all the time so now package.json file let's add a lint command again we don't have to type the npx this time just eslint period EXT dot TS and then we can run this with npm run lint now why do we have to enter run now and before we just typed npm start at node npm Run start this is because start has the shorthand so npm start is a shorthand for npm Run start however for other types of commands like lint we have to type it out like this npm run lint let's add our problem here again to see if it still works and yeah it works change this back because we are not bad callers right but it's still a bit annoying to always execute this over the command line it would be much nicer if the IDE or the code editor would show us this directly and there's an IDE extension for this so here NBS chord on the left side we can open this extensions tab and it's already here under the popular extensions eslint and this extension will check our code directly with our eslint configuration so we don't have to execute this in the command line so let's install those and see if this changed anything make this here bad once again and as you can see now we have this yellows quickly line and the eslint warning shows up directly in our code nice so this will save our behind in the future of course you can check out the other extensions as well there are some really cool ones in there we will get back to this later but for now we are done with this now there's one more file we want to add to our project and that's the git ignore file if you already have programming experience then you probably already know what git ignore is it's a file that defines other files and folders in our project that we don't want to commit to git this is important for example if you want to push your project to GitHub for others to see because some folders are just big and we don't need them so we save space and bandwidth by not committing them but there are also certain files that we must not commit because they contain for example database passwords and all these files have to be added to a disk it ignore file so we create a new file here in our project outside of the source folder and the name is dot that's important it has to start with this dot git ignore just as one word like this now how do we know what we have to put in there either we can design this ourselves but there are templates for this available on GitHub and as you can see it's from github's web your own account so those are basically official files we can copy this here copy raw contents and you can either look this up yourself or you can go to my GitHub project in the description below and go into the git ignore file there and copy its contents and then we just paste this whole stuff in here and save it this contains more than we actually need but that's not a problem it's better to have too much in here than too little and accidentally expose stuff that we don't want to expose as you can see the node modules folder is in here as well so if we Commit This to get then this will be ignored and it's not necessary because this contains only the code of the packages we installed but we can always install these packages from our package.json file here so here we have defined what packages we need and later for example when we pull this code on our web server without the node modules folder we just type in npm install and all the latest versions here will be installed and this node modules folder will be recreated and the main reason why we don't push this is just because it's a huge boiler and we don't actually need it our eslint and TS config files on the other hand are pushed to GitHub because they contain configuration that we want to keep when we work in the team right then everyone should use the same lint rules and typescript configuration so those are not in the skid ignore file because we want to push them usually okay the next step is to set up the mongodb database and connect this to our backend server but there's one more thing I want to clarify before we start with this and that is you might be wondering is this what we are building here a restful API is this a so-called rest API and if not what's the difference between a rest API and our server that we are building here a rest API is also a back-end server but it fulfills certain constraints and rest apis are usually servers that are accessed by many different clients and this is why they follow certain rules one of those rules is that they don't contain any state our server will later contains States because users will be able to log in and for each login there will be a session in our database that connects this user and lets the server know that this user is logged in and this is a violation of the restful constraints because this is not a public rest API we are building here it's our own backend server for only our own singer client by but you can build a restful API with the exact same stuff we are using here with Express and node the same code the same endpoints you can also use this to build a public API maybe that's an interesting project for you to build a public API that serves some data that people can get from your server just as an idea okay and now in the next section we will install mongodb okay the next step is to set up our mongodb database mongodb is the m in the moon acronym and it's the place where we put our data later like our nodes and also our user data and mongodb is a so-called schema-less database which basically means that we can put any data into any document we want in any combination and it will work that's the opposite of a database like SQL where you have a certain schema that you have to adhere to and all entries within the table basically have the same columns and the same data types and if you want to change this structure then you have to migrate this table a schema-less database is a bit like the wild west of databases but it's also how firebases database works for example it's also schema-less so it's a very popular concept and it works in many situations it has downsides and benefits like everything in life and if you want to learn more about the differences then you can look them up in Google but we will use this here and again it's a very popular choice and it works for many big companies and to host this database you basically have two choices you can either self-host it on your own server or you can use a service like mongodb Atlas which is a hosting provider for mongodb databases the benefit of using a service like Atlas is that it takes care of many things that you would have to do yourself otherwise like scaling security concerns encryption backups and so on so I'm a fan of using these Services because it saves us time the downside is that in production we have to pay money for this we don't have to pay money for this tutorial because they have a free tier but if you want to scale up of course this costs money but I think it's worth the convenience you get that's why we will use mongodb Atlas in this tutorial and to create an account there we go to mongodb.com Cloud slash Atlas or just type mongodb Atlas into Google it's probably the faster way and we click on startria and by the way this is the most ugly button animation I've ever seen but it's probably a rich company and it works for them so maybe we should take an example of that all right so we have to fill out some data here first name last name no company and here I'm gonna use email address that I've prepared just for recording so we have a completely new setup which is recording it's coding in floor punct.com and we pick a secure password which I've already prepared all right we agree the terms of servers and privacy policy which you can read if you want and create an atlas account and we have to verify our email so let's do that real quick okay so I've verified the email so let's go back to mongodb account remove this part here from the URL to get to the login screen it locks Us in automatically otherwise just type in your email and password you just signed up with and another queer thing about mongodb Atlas is that they give you this back end this UI to work with and you don't have to do this over the command line so let's start setting this up first of all as they say here the current IP address should be added to a white list so let's do this by clicking on this button here and it does this automatically we later have to go to the network settings again and add the IP address of our server but not for now and now we can actually create a new database by clicking on this button and then we have to do some setup here we want to start with a free account so we have to select the shared hosting option later if you are in production you can decide to use a dedicated or serverless configuration most likely dedicated but for now we use shared so we click on Create and we have to do some setup here we have to select where our database will be hosted because mongodb Atlas works together with these big hosting providers you can select whatever you want I'm gonna stick to Amazon a location for our database and it makes sense to pick a location that's close to the location of your deployment server later I'm gonna stick with Frankfurt which is here in Germany where I live cluster tier m010 box is the free tier which of course has some limitations but it's enough for playing around and it's also enough even for small production projects backup is not enabled in m0 clusters but that's fine and termination protection is a relatively new feature it makes sense it just adds an additional step before you can delete your cluster which is always good to have because you never want to delete this by accident we can give it a name the name doesn't really matter in my opinion you can give it something descriptive but I'm just gonna stick to a cluster zero and we click on create cluster and now it charges your credit card with 120 dollars no I'm just kidding it's completely free unless you upgrade to a higher cluster and now we have to do some more setup here how would you like to authenticate your connection via keep username and password so here we type in our username I'm gonna call it Florian and I'm gonna Auto generate a secure password copy it because we later need this in our code of course and we create this user now the user is created here we want to connect from a local environment and we already added our current IP address to this list so there should be enough and then we click finish and close and here is our shiny new database can you smell that that's the smell of a fresh database we can browse collections but we don't have any yet but we want to connect our code our backend server to this database so we click on connect then we have different options you can connect over the command line with a tool they have which is called Compass but we want to click on connect your application and then we want to copy the string here by clicking on this button because we need this in our code and then we open our code again and this time I will open the project one layer higher the last time we were inside this backend folder and open the project from here but now I want to open it from this folder here where we can see the backend folder the only reason for this is that this way we have the back end and later the front end folders both opened in vs code you don't have to do this you can also open them separately I do this because I want to push them to the same GitHub repository so you can look at the code later this is also where there is this dot get folder which probably doesn't exist on your side it doesn't have to you can ignore this so again I'm going to open this by shift right clicking to open the command line here and then I just type in code then the space and then a period to open this folder and we can close this and this is what I meant now we open this whole coding and flow Mount folder here so we can see the back end and later the front end both inside this project view now our mongodb credentials are of course data that we don't want to give to anybody willy-nilly it's sensitive data that's why it's a good idea to also not push this information into the GitHub repository in other words we want to put it somewhere in the file that's included in our git ignore and the correct place for this kind of stuff is the NF file which is included in the skid ignore we pasted earlier and in there you put environment variables which can be configurational that changes depending on where you run your server for example on localhost or on a real deployment but it's also the place where people usually put sensitive data like database credentials so what we do is here in the root folder we right click and create a new file which we call.nf the same name as you can read here on the git ignore and in here we want to put our mongodb connection string so we put a variable in here that we have to give a name you can color whatever you want I'm going to name it mongoa underscore connection underscore string and the convention for this kind of constants is to write them in our uppercase with underscores but you can also use candle case or whatever you want then an equal sign and then we paste the connection string we just copied and since this is just one string without spaces we don't have to add quotation marks here we can if we want but we can also keep it like this this part here in front of the colon is our username we just defined when we set up our cluster and we have to replace this part here for the password I'm just going to paste the password here because it's just for this course I don't actually use this in production but of course you should keep your password secret and only share it with team members or whoever is allowed to know it and let's also put our port number in here because this can also change between deployments so you usually want to put this into your end file so we just write Port equals and 5000. then we save this with Ctrl s remember in the S code by default you have to save your files and by the way you can see that node modules here is grayed out now which indicates that this folder is not pushed to a GitHub it might not be grayed out on your side if you didn't actually deploy this project to GitHub just as a node and NF will later also be grayed out on my side because it's included in the git ignore file but I did a little mistake we have to put this end file into our backend folder not here on the root folder because it belongs to our backend code so let's move it in here drag and drop very simple and now you can also see that it's actually grayed out because now it recognizes the git ignore file in the same folder but this is only necessary if you open this parent folder like I did if the backend folder is your root folder then of course the end file goes in there so just put the end file in your backend folder basically and now we need to install another package that allows us to load this end file because nodes doesn't do this by default so we want to open the terminal again but it's important that we are inside the backend folder so we type in ZD and it should be the same on Windows Mac and Linux backend CD stands for change directory we go in here and in here we want to install our new package so the same as before we type npmi .nf which is the name of the package that allows us to load n files and if you want to learn more about this package there is a page for basically all of them on this npm js.com website you can basically read about any package here as you can see it's a popular package as well it shows us the configuration options and so on but don't probably I will show you how this works but first we want to install another dependency npm IO this one is called mongoose and Mongoose is a object modeling for node.js so it's basically a package that makes it easier to work with the mongodb database so it's less of an Arcane language as the original as you can see it creates these objects and types and it's really cool it has a humongous documentation which can make you lose the will to live if you see how much information is in there but you don't have to know all of this and I'll show you the stuff you have to know of course in this course and just as a reminder all the packages we installed are inside our package.json file here they get added to the dependencies block and by the way in the last video before I push the code I swapped the order of Dev dependencies and dependencies because I think they should be at the top but it's unnecessary the order here doesn't matter okay and now let's go into our server TS file again and start this connection to our database so we want to add two more dependencies here at the top the first one is the dot nth dependency we just installed and we should import it as early as possible that's why I put it in the very first line this makes sure that our environment variables are available when the app starts so up here we type import and then in quotation marks Dot N slash config which is basically all that's necessary to set up and configure.nf in our nth file and we also want to import Mongoose to use it so again import but this time without the quotation marks here the same way we imported Express because this up here is actually just a shorthand over writingimport.if like we did for Express and then calling config on it by importing it like this we are automatically call this config I found it somewhere in stack Overflow so Mongoose will import the following way import Mongoose and it auto completes it by default isn't that amazing otherwise type it out as you can see it here and this allows us to use the Mongoose package in this file here in the server TS file and now we connect Mongoose to our mongodb database the following way and again I have this from the documentation or other tutorials but you can just follow my instructions here we call Mongoose dot connect and as you can see we have nice Auto completion in vs code and here we want to insert our mongodb connection string which is inside our end file so we copy the name of this variable and then we type process.nf to access our environment variables and the name of this variable now this shows us a warning because this environment variable could be undefined but connect is expecting a string that actually has a value we will take care of this in a moment here we call Dot then because connect returns a promise which is basically an asynchronous operation an operation that takes a moment and brief dot then we can Define what we want to do after this succeeded now later we will use async await which is some synthetic sugar around promises which makes them a bit nicer to use but we can't use async already on the top level in case you're wondering if you don't know yet what this all means just follow along so inside then we have to pass a function so we add another pair of parentheses then the right arrow as we did before and a pair of curly braces and we can also put a semicolon down here and here we Define what we want to do after this connection is exceeded let's write a log message with console.log which says monk was connected and we also want to start our Observer here after our mongodb connection was successful we could keep it like this following one after another but if the connection failed for some reason we don't want to start our server because it wouldn't work properly without the database right so we can actually cut this out and put it in here and to let the code editor format our code we can press shift alt F which would align it properly okay but we also added our port to the environment variable files so we shouldn't be getting it from here we should get it from the process end here as well so let's create a variable for our Port so we don't have to repeat process.nf all the time we write it as a const because this value shouldn't change and the port is process dot NF dot port and all uppercase but again as you can see the value could be undefined because we never have to guarantee that we actually put these values into our environment variables now app.listen and console.log they don't show a warning because they would accept an undefined Port the code will still run Mongols is not so forgiving they want the real value now there are different ways to handle this one way is to do what I already showed earlier when we took a look at eslint is adding this non-nine assertion operator this will be tell the compiler here we know that this value is not neither please just accept it as you can see here eslin doesn't like this because it's a bit dangerous but our code would run so let's try it out let's save the file enter an npm start and if everything is successful we should see Mongoose connected and then server running on the port blah blah blah we should also add a catch block here after then so before the semicolon actually we call Dot catch which is basically the opposite of the dot then for promises so we have then for when the promise was successful and we have catch for when there was an error and in here we can just call the console.error but without the parentheses because we are not actually calling this function here we are referencing it so catch will call this error function and pass the arguments that it gets and this argument is the error itself so this way it will print this to the arrow console which is basically the same as console.log just at its red text basically and a different place where we can see it depending on where we deploy it now what happens if we forget to Define this value here let's remove it for a moment save this file and try to render this without the valid connection string as you can see we get an error here the UI parameter must be a string and undefined and this is good we want to crash we don't want our server to start with an invalid configuration so it's good that this actually crashes right away however if we delete the port here and run this again with an undefined port then our server actually runs Mongoose connected server running on Port undefined and this is a problem because this will not work but our code still runs and there are situations where this could be even more problematic where an undefined value could do some real harm and we don't know where it's coming from so this is why eslint complains about these non-known assertion operators we should avoid them one way to handle this would be to just have checks for each of them like this port with an exclamation mark in front of it which basically means it's false here which is the case if it's undefined then we want to throw an error here to crash our server right away but this is a bit verbose and we still don't have a warning here because this listen function doesn't complain about the possibly undefined value so better way to handle this is use another package which is called invalid it's another popular package that is used to define how our environment variables should look which one we have in the dot end file and then it enforces this schema so if one is missing it actually throws an error and our server won't start so let's install this we have to stop our server with Ctrl 0 and then the wire to confirm it npmi and valid and it's a normal dependency because we want to use this in production as well and now what we do is inside our source folder we create another folder which we call uter short for utility code and utility functions and in here we create a new file validate nth dot TS you can write it like this in candid case but the name of this file doesn't matter it's up to you and in here we want to import then between curly braces we write clean and from the invalid package now why do we write this in curly braces here and not just the name as before this depends on how this clean end is exposed inside this package to explain it in simple terms sometimes there is a single default export which is when we import it like Mongoose with this one name and sometimes there are multiple things that are exported from a module like in this case where we can list them in curly braces and if there's another thing then we write the comma and Export this other thing as well entry will actually see an example of this right now because we will do a default export ourselves because from this file we want to export one single thing which is basically the zenitized version of our environment variables so here we write export default we want to export the same clean end that we imported here but we want to call it because this is a function so we don't actually export this function we export its return value again if this is confusing to you just follow along the first argument we pass here are our normal environment variables process.enth comma and still inside the parenthesis we add a pair of curly braces because then here we do the configuration to be more exact we want to list all the environment variables that we expect which is our Mongol connection string and our port so we paste the name Seal colon and then we call this Str shortfall string function which will automatically import this dependency here and this comes from the invalid Library as well this basically defines that connection string should be of type string later we also add the port after a comma here because this is a Json object and this time we call the port we could also use number or string but Port has a special type I think it makes sure that this has a certain length or shape and now since we export this clean nth curl here we can import it in another file and this will give us our cleaned up and sanitized environment variables so let's save this file go back to server TS and we want to import I put it up here and from from our validate and file here and now we have to pass the location of this file relative to the file we are currently in so we want to go into the parent folder which is Source then inside util invalidate INF so we write the dot to go into the parent folder and auto completion already suggests uter validate INF this is where we want to import it but this depends always on your file structure but other computation will help you with finding the correct one now since this is the default export here we can give this import any name we want and it will recognize it because there's only this one export we could also called as banana or chocolate doesn't matter but NF makes sense because it mirrors the name of the normal environment variable here and now it's pretty simple instead of process.enf we just want to call NF because this now relates to our clean end setup we did here now the port is definitely a number it's not possibly undefined anymore because this is what cleanenf takes care of I can also now remove this exclamation mark and the IDE will stop complaining because this is now guaranteed to be a string and now what happens if we actually forget one of these values let's try deleting the port again as we did before and restart our server and now it crashes right away with a nice error message here missing environment variable support undefined and this is exactly what we want because now we make sure that our server doesn't run with a wrong configuration instead it crashes right away so it doesn't even start this is better than having it used by someone already in production and then it just misbehaves okay so this is why this is a nice package let's restart our server with the port in here and everything should run Mongoose connectors are running on Port 5000 by the way this warning here is just a change that's coming up in the next major Mongoose version you don't have to care about this it doesn't play any role for our project we are building here let's actually try if we can still access our endpoint here at localhost 5000 we can still see hello world if the server is running however our code organization is not really nice here we should separate the parts that contains all the endpoints and the part that sets up Mongoose and actually starts the silver one reason for that is just good old separation of concerns but the other reason is that this allows us to test our server code everything that's contained in this Express app basically without connecting to the real production database we won't be writing tests in this tutorial because this is boring as hell but when you write tests in production you usually insert some dummy data into the database and then you will just wipe the whole database and of course you shouldn't do this in production unless you want to get fired this is why it's necessary to separate this code so what we do is at the same place where our Observer TS is we want to create another file so inside the source folder here we create an app.ts file and then we want to move some code from our server TS file over into this new appts file so we want to move the first line here Dot and slash config over there so we load the environment variables also if we start this app without starting the server next we want to move these two lines over there the express import and the express call here which creates our server app let's actually put this into a new line because this is not an import it's a function call and then we want to move this endpoint over there so we cut this out and paste it here as well because this is a zero endpoint this belongs to our server code and then in order to use this app in our server to call it and run it we have to export it here and again this is a default export which basically means that we just export one single thing from this file which is our Express app where we add all the endpoints on if you want to export this here and now we want to import this in our server TS file so we do this at the very top of our Imports import app again we could give this any name we want because it's a default export but app makes sense and it's inside the source folder as the app file and whenever we import a file we don't have to import the file extension as you might have already noticed and you have the rest basically stays the same its format this properly we still call app.listen now we call it on its imported app to spin up our server let's save the server TS file we don't have to export anything here and let's see if it still works so we can still access our endpoint if the server is running nice okay our mongodb is connected and now we actually want to put some stuff in there right and when we use Mongols we have to define a model for the data that we want to put in our database so what we do is inside our source folder here we create a folder called model or models actually because it will be multiple ones and in here we create a node.ts file and as you can tell this will contain our node model let me close this terminal don't need it right now of course this whole process of setting up models and schemas and everything is explained in this humongous documentation if you have some weeks to spare and want to learn is in more detail but I will show you everything you need to know right now so we need to define a schema and the schema defines what kind of data our node should contain so we write const node schema equals new schema which is this mongoose I guess Constructor or function here so it should import this party at the top and between these parentheses we add a pair of curly braces because this is where we put the configuration for the schema okay what data should our nodes contain each of them should have a title and a text and also this timestamp that indicates when the note was created or last updated so we put these fields in here title column then another pair of curly braces and you just have to get used to it when using JavaScript there are curly braces everywhere it's just curly braces inside curly braces inside curly braces but this is how JS works here we have to define the type so this is basically a configuration for this title field in our node schema the type will be string and you have to write this in uppercase not lowercase and we have to write it in uppercase for all data types in these mongodb schemas even though a normal code revitamin lower case this is because those are actually the constructors of these types I don't know why exactly but doesn't matter after type string red comma we quiet I can't write required call on true as the name implies this is another configuration that defines that each node has to have a title otherwise mongodb will not accept it comma and the next property text which is another string but this time it doesn't have to be required because we want to make the text optional and in JavaScript objects you can add trailing commas even if we don't add another field which is usually a good habit because it has some benefits When We compare changes in Version Control doesn't matter you can edit your can leave it out but I like to edit but the timestamps are still missing right so now we could add another field created it make it of type timestamp but Mongoose can actually add these fields for us and also maintain them automatically so we don't add them inside these curly braces here inside the schema configuration instead we go outside of this closing curly brace but still inside the parentheses add another pair of curly braces and write time stamps and we already get a suggestion column drawer this will automatically add the timestamps fields for created and updated to the schema rather than us having to manage them ourselves but again you have to put that in the correct place outside of these first curly braces here now for normal JavaScript this is everything that's necessary to set up the schema but in typescript we have to add another step because we later want to have a type for this node in our code available so that we get type safety and other completion for all the fields in here title and text and everything so below we write type which is basically a way to add another type alias in typescript so to create another type so to speak and the name of this type should be node but again you can name this anything you want it makes sense because those are notes and then we write equal sign and first schema type which is this name here this type we get from Mongoose again so it should add another import then we make anger brackets to add a type argument to this infill schema type type and in here we write type off as one word or lowercase that's important note schema in other words this creates this node type by looking at our node schema here and then we are creating a drumet this is something Mongoose does automatically for us and now we just have to export this whole schema so we can use it in our remaining code so again export default then we have to call model which is another Mongoose function so it adds another import we add another type argument so it creates a model of type node parentheses then a string which is the name of this collection and again we write note in uppercase this will later create a collection in our mongodb database but it actually turns this into a plural so by calling this node it will later create a collection with the name nodes you will see this in a moment just follow along combine the second argument as the node schema save this so to recap this code here creates a schema for our notes which each contain a title and a text and the timestamps and then recreate the type for typescript and Export this model so we can use it in our code and now let's go into our FTS file which is our server code and import this new node model we just created so import node model again we can give it any name since it's a default export from period slash models slash node and now let's create an endpoint that Returns the nodes that we put into our database just so we can see how we can interact with the database and let's reuse our existing endpoint here because we don't need this hello world in the future so instead of rest.send hello world we want to get the notes out of our database and then return them so we write cons notes equals then await note model dot find we call this without any arguments and carl.exec behind it okay so that's a lot of code what is going on here so first of all node model.finds.exec executes this find operation and then exact returns a promise we already worked with promises earlier here but here we use this then and catch combination as I already explained a weight is syntactic sugar around promises so instead of having to use these then and catch carbacks which adds this ugly nesting we can just write it in one line below each other like normal synchronous code and again I didn't use this here because we can't use this at the top level in express by default but we can use it inside this endpoint functions here but for this we also have to add the async keyword in front of this error function so the code knows that this is an asynchronous function and now this error here disappeared so in other words this will execute this find operation which is an asynchronous operation meaning that it takes a moment because we actually have to go into our database look it up and then return it and this can take a few milliseconds or maybe even a second this is why this whole process is asynchronous we don't want to have the rest of the server to wait just because we do this database operation this is where we use promises and isn't a way to make it a bit simpler again you don't need to understand this in detail you can just follow along and it's important that you don't forget this await otherwise we will not get the value of our nodes we will get this promise which can cause weird errors sometimes if you're not aware of this so yeah make sure to add this away here otherwise it will not work but we don't only want to get them from the database we also want to return them to the user So Below we write something similar than before we take our response object but instead of send we call Dot status and pass 200 here which sets the response status to a 200 which is the HTTP status for okay so everything went fine basically and when we work with our front and later we use different HTTP calls to indicate if there was an error or not and we don't send a response just in form of a text we send it in form of a Json which is basically a way to transfer JavaScript objects between the backend and the client you have probably already worked with Json before and in here we simply pass our nodes this will turn our notes into a Json that resents to the front end and now we can actually try it out we can access our localhost again we get a successful response and we see this empty pair of square brackets which means that this is an empty array which makes sense because we haven't put any nodes into our database yet so let's go into mongodb Atlas again and know something magical happened when we click on browse collections there certainly is a collection oh wow we just cut notes why is it called notes again because we cut our node schema node and mongodb or mongoose automatically creates this collection from it and it also automatically pluralizes the name so note turns into notes because the collection contains multiple documents now the database here is called test because this is what we defined in our connection string let's actually remove this and give this a proper name so we drop this go back into our code into our connection string and we go here behind mongodb.net but before the question mark retry writes and here we can set the name for our database let's call it cool underscore nodes underscore app save this and I think when we change the environment variables we actually have to restart the whole thing manually I'm not sure right now but just to make sure stop the server and run MPN start again let's access our endpoint again which would trigger the creation of the collection and then take another look in here refresh this and that is now our database here is called quillnotes app and we still have our nodes collection which is empty now we don't have an endpoint yet where we can create nodes but we can create them here manually so let's do that in the back end here of Atlas it automatically adds this idea because each node needs an idea and now we want to add the title let's call it my first note and the text we click this plus here at another field color text and rewrite subscribe to coding in flow and then we go ahead and click the Subscribe button under this video after you have done this we click insert to add our first node here and now when we access our localhost endpoint again we return our array with our one node in it nice and this is what we will later display in our front end amazing but before we go ahead and add more endpoints we should have a clue of how error handling Works in Express so let's just pretend something goes wrong in here which of course can always be the case maybe the database is down maybe we wrote some bad code whatever so to simulate this we're gonna throw and around here like this it's the same in Java and kotlin and so on with an arbitrary message we saved us and then we try to access our endpoint again which now shows us an error message the website is not available in beautiful German the website is and even worse this crashed our whole server when we look into the console here's our error and the app crashed and now our whole server is done we can't access any other endpoints anymore we get fired our life is over our wife leaves us all because we didn't handle errors properly so let's learn how to do this so we want to wrap this whole content here of this endpoint into a try catch block which looks like this dry curly braces catch Arrow curly braces and our USB s chords are the completion while the normal chord goes into the dry block and in catch we put whatever should happen if something up here goes wrong so if this throws an hour leg in our case what do we want to do first of all of course we want to lock this error so we write console.log and pass the arrow here if this error contains an error message we want to show it to the user or whoever accesses this endpoint if there is no message in there we want to show a generic error message so what we do is we create a variable and this time it's a let because we want to change its value later colored error message and rewrite an unknown error occurred and whenever I write this I feel like a real programmer because this is such a pro camera sounding message don't get confused by this error here this will disappear in a moment it's just lint complaining that this is a lead which we are not changing right now but next we check if error instance of error so we check if this error is actually the arrow type and this is necessary because this has the type unknown which means this can be anything because we can throw anything in our normal code we can throw an error but we could also throw Naya and so on this is why we have to check that this is actually the type error if this is an error then we want to set the error message to arrow.message because every instance of type error has this message property and then we want to return this it's a rest dot status this time the status is 500 which means internal server error and we want to return a Json just like we do for the happy path but this time we have to add curly braces to define a Json we didn't have to do this up here because nodes is an array and the Json method knows how to turn this into a Json array automatically but now we write this Json manually so we also have to add the curly braces we add an error field which will contain the error message so the user can later see this so now let's try this out again so our error is still in here we still have this Bazinga error that we are throwing but now when we open this endpoint we see this error message here because this is what we return but the difference is that now our server doesn't crash because we have this try catch block so we can still access our other endpoints our boss is happier our wife won't leave us and our life is just so much better but of course we don't want to repeat this for every endpoint because this is quite a lot of code so what we can do is we can set up an error Handler and the error Handler will automatically kick in when we have an error so it works the following way we go below here and it should be below our normal endpoint here we write app.use parentheses and to add another pair of parentheses because we want to pass an error function here so this error and curly braces but this function we'll take some arguments and in Express error Handler has to take a very specific set of arguments and it has to be these same arguments otherwise Express will not recognize it as an error Handler the first argument is the error itself and we have to set this to unknown just like the type up here now why do we have to Define types here but we didn't have to Define types up here for our rack and rest arguments this is because since we passed this as an argument to this get function typescript is smart enough to infer these types so it knows from the signature okay this is a request type this is a response type down here we don't have this type inference because what we pass here could be anything so we have to declare these types ourselves this is necessary in typescript but not a normal JavaScript the second argument is the request just like up here but again this time we have to define the type which is request and it's important that you import this one here from the Express package this is the request we want to be using and this automatically adds this request import up here Express is the default export this is why this is separate and those are additional exported types this is why they are in these curly braces if it didn't import it automatically type it out by hand the third argument is response again from the Express package and the third argument card next and it's of type next function from the Express package again the error Handler has to take exactly these four arguments with these four types and then what we do is we cut out this part here and paste it down here now a lint will complain that we are not using next and that we could remove it this is kind of a false positive because if we remove it express will not recognize this as an error handle anymore so we have to ignore this one here and just keep it the one thing we could do is we could click Quick Fix and disable this eslint rule for this line which adds this comment here and I think it's a good idea so you don't get confused later this way we know that this was on purpose okay so now how do we forward this catch block here to our error Handler works the following way we add the third argument up here which is next and it's the same type as down here it's this next function type in every route we either have to send a response the way we did up here or we have to call next which forwards this request to the next middleware middleware is basically a piece of code that knows how to handle a request on our Express server it's a concept from the express Library you can read more about this in the documentation but both app.get and app.juice create such a middleware the difference is that app.get and also post and these other HTTP verbs create middlewares that create these endpoints that we can call like slash and later slash nodes or slash user app.us are other types of metal Wells that we just use in our codes to either prepare our response in a certain way or handle this like our error Handler here and the error Handler is a very specific kind of middleware that basically kicks in when we have an error we will see more examples of these middleware Slater so if this confuses you don't worry just follow along and again to cut the next middle where we call this next function this is why we have this next argument up here but we don't want to call any middleware we want to call our error Handler middleware this is where we pass the error as an argument to this next function so let's save this and see if it still works so we access our localhost endpoint again we still have our error that's handled but now our error Handler here handles this because the error Handler handles the errors that have to be handled just sounded cool in my opinion and now we can reuse this because in every endpoint in the catch block we just call next Arrow and that's it and these middlewares are checked in the order that we Define them here this is where we have to put the error Handler at the bottom otherwise this is the first one that would kick in but we only want to get to this one if we actually have an arrow now one more thing I want to mention here if this was synchronous code meaning that we don't have this async and there's a weight in here because we don't do a database operations or other long running tasks then we actually don't need try catch because Express is smart enough to forward this error to the error Handler automatically however this does not work right now for asynchronous code this is why we have to add this try catch block and call next ourselves however they are going to change this in the next major version of Express right now we have Express 4.18.2 installed when this is five point something or higher then you can remove this try catch block because it shouldn't be necessary anymore this is an update they are planning so let's remove this throw error otherwise this endpoint will never work I'm going to comment it out so I leave it in here as a warning and that's a reminder for you and just to drive home this whole concept of middleware slits actually add another one right now when we try to access an endpoint that doesn't exist for example localhost 5000 slash blah we get this error message here but it might be a good idea to create our own error message that just has a better text than this one here and we can do this with another middleware that catches our requests that go to an endpoint where we don't have an actual route set up for it so again we add the middleware with app.use and again we want to have this below our normal routes because this is just a fallback but before our error Handler because we actually want to forward an error in here to our error Handler so it goes in between these two and in here we pass another Handler function so another pair of parentheses Rick risk next leg up here but without the end points because you want to use this everywhere that we don't have an endpoint set up for right arrow curly braces now this time we don't have to add types again because they are inferred automatically and to be honest I don't know right now why it works for these normal routes but not for the error routes but it doesn't matter we don't have to add these types here if we would have to add them the compiler would complain so to recap we get to this middle wheel if none of our rods up here fits so if we try to access an endpoint that we haven't set up so what do we want to do in this case well we basically just want to throw an error with a root not found message or endpoint not found so recall next and by passing an error we forward this to our error Handler right the same as we did up here so we create an error like this and we insert a message and point not found and now when we try to access an endpoint that doesn't exist again it forwards this to our error Handler and we see our endpoint error message now at the moment this will have a 500 response which is not quite correct they should have a 404 response which means not found rather than internal server error but we will improve this later for now this is sufficient alright and in the next chapter we will set up another endpoint for creating nodes so we don't have to do this over the atlas console anymore and we will organize our code better into a routes and controller files okay now let's organize our code a little bit better because if we keep putting these endpoints into this FTS file then it will be huge after a while right and we need more endpoints with more complex logic than this so we cut out this endpoint here and what we do is we create another folder inside source which we call routes and inside routes we created nodes dot TS file for our nodes routes and here we are paste the code we just cut out now before we take care of the import statements and everything we want to extract it even further because still this file could be difficult to read in the future because we have our endpoints and then all this huge logic in this Handler function so what we do is we cut out this whole part after the comma here and put this into yet another file so inside source we create another folder which we call controllers and this is a popular way of separating this and here we create another file called nodes.ears um you could give them different names you could call this nodes and this one notes controllers doesn't matter it's up to you but since this already has different folders I'm actually fine with having them have the same name and here we paste the piece we just cut out so this Handler function and we want to export this function from this file so that we can use it in our routes file so we write export const and this is what I explained earlier it's a different way of exporting something from a JavaScript module but instead of our export default where we export just one thing this way we export multiple things so we don't add default we just add export and then the variable of function or whatever we want to export we have to give this a name let's call it get notes because this is what this endpoint does equals and this function here and this time again typescript can't infer these types here because it doesn't know what kind of function this is so now we could either add requests and response and everything to each of these arguments separately but there's actually a more concise way of doing this we can give a type to this variable itself the variable that contains our function and then typescript can infer the types of these three arguments so behind get nodes but before the equal sign we put a column to define the type of this variable which is type request Handler here from the Express package we import this which adds this import statement here at the top and now typescript can infer the types of these arguments as request response and next function and we also have to import this node model here so let's add another import statement the same as we did before import node model from and the destination of this model file here by this time we write two dots because one dot would go into the controllers folder two dots goes into the parent file of that which is source so now we are inside source you want to go inside the noddle models folder and import our node model now the error here disappeared entry can also get rid of this because we don't need it anymore now we want to use this get nodes function in our nodes routes so here we import this function from our nodes controller the following way import then we make an asterisk so this little star icon which means that we want to import all functions that we put into this file there will be more later s nodes controller from and the destination which is the controllers folder and then here we call nodes controller get nodes but we don't add a parenthesis because we pass the function declaration itself we don't pass the function call And to clarify something we could also import it like we did before with these curly braces get notes like this and then we could remove this nodes controller dot this would also work you can do it like this if you want the problem I have with this is that this line here grows huge because there can be many functions in the controller so with this way of importing it we add them to this notes controller namespace and keep the support statement short but appear still shows us an error because the compiler doesn't know what app means because we are not inside this folder here anymore where we have this Express app so the same as an app we want to import Express in here from the Express package shouldn't matter if you put it below or above notes controller but this is the organization I like and then we have to instantiate the app but this time we don't want to call Express because we don't want to create a whole not Observer instead we want to use the one that we already have so instead of instantiating Express we create a router with Express dot router you can read more about this in the documentation but this is basically a way to set endpoints on a router and then we later set this router on our Express app here to add these endpoints it's pretty straightforward and then we want to replace app.get for router.get and again get means that this is an HTTP get request then we make this router the default export so we can use it in a different file and that's the only thing we need to export from this module so we write export default router semicolon save this and then where do we want to use this we want to use this in our FTS file we want to import our new router appeal and by the way we can delete this node model because we now handle this in our controllers import s again you can give this any name you want from the routes folder our notes routes file and then here between const app and our endpoint node font Handler the same place where we had this endpoint before we simply call s dot us to add another middleware we Define an endpoint and this endpoint will be added in front of this endpoint here right now we have localhost 5000 and this gives us our notes back but in production we want to have them at an endpoint that's a bit more specific right so the endpoint will appear slash API slash notes so later let's say our website is called quillnotesapp.com then we will get the notes from coolnotesapp.com API slash nodes and we want to forward this endpoint to our nodes routes so this is basically like a puzzle that's puts together we have this middleware that catches any request that goes to this endpoint which then checks the notes routes endpoints we have set up here and look which one fits in here we will later have more endpoints in here as well for example router.get for a specific node which then adds additional endpoints on this API node's endpoint if this is confusing don't worry you will understand it when we later actually use this let's just save every file that's still opened and then access this new endpoint so now the end point directly at localhost 5000 isn't found anymore because this is now not where we get our nodes from we now get it from slash API slash nodes and there's our node the same as before but it's better organized now and now we also want to add an endpoint where we can create nodes without having to do this manually in our mongodb Atlas backend now first of all we need to tell Express what kinds of data we want to accept as messages to the server and we do this in our FTS file before this route here at this exact point we add another middleware app.use and pass express.json and call this as a function exactly like this and this basically sets up Express so that it accepts Json bodies so we can now not only retrieve Json from our get endpoint we can also send Json to our server when we then add a post endpoint so let's save this and add another endpoint and our notes controllers file So Below get notes we add another export const which we this time call create node and the same as before it's a request Handler equal sign it's an asynchronous function because it does database operations curly braces entry can already add and try catch book here because we always need this when we do something that could throw an error and in catch we want to do the same as up here pass it to our error Handler middleware before we set up the body of this endpoint let's add it to our routes So Below router.get will write router dot post this time because this will be a post request we are sending data to the server in this case our node it will be at the same endpoint and this is possible because those are different HTTP methods so they will not interfere with each other even if they have the same endpoint if we wanted to get different kinds of data then of course we can't use the same endpoint otherwise the server wouldn't know what endpoint this is supposed to be and here we want to use our newer nodes controller create node function save this and go back in here to finish setting this up we present the title and text in the body of this request so first we have to get these values out of the body we can do this outside of the try block or inside it doesn't really matter but this shouldn't throw anything so I think it's more correct to put it outside create a cons title and we get this value that we send to the server from the request body so we take this request object foreign and then the name of the variable that we present to the server entry will call it title just like the field in the node itself and the same for the text we will send it as the text field in the request body then insert try block because this is now the parts that can throw an error we want to use Mongoose to create our node and we also want to save this new node in a variable so that we can send it back to the client and we do this so that we can later put this newer node into the UI and update the UI on the client and it's also useful to see the data we created when we get our response back so here we call await and again the await is very important node model dot create parentheses curly braces and I already add the semicolon down here and in here we create our notes and we actually have Auto completion for this why because this refers to our node schema we set up here so it already knows what kind of data this expects it expects a title which is our title up here comma and the text value and again the timestamps will be set automatically now create returns A Promise by default which means that we don't have to append this dot exec at the end which we had to do up here I don't know why they made this design decision that we have to edit up here but not down here but yeah it's not necessary and then if this should fail for any reason we get into our catch block if it doesn't fail we continue with the drive block so we want to send a response back to the client we set the code to 201 which is the HTTP code for a new resource created we could other than 200 doesn't really matter but it's better to distinguish them properly entry one is sent a new note back as a Json save okay and now this endpoint should be configured properly because we already referenced it in our nodes routes file and this on the other hand is connected in our FTS file so this should work now the problem is we don't have a client yet to send data to our server and with a web browser we can only do get requests we can send something to the server this is why we will use a tool called Postman which is really popular for they are working on server stuff in development because it allows you to do all kinds of HTTP requests without the need of a real client now don't get scared because it says pricing we can actually use it for free so download it for your operating system run this file and then you have to create an account before you can use it which is fine I'm gonna sign up with my recording account here again again you can use it for free and it's very popular tool among developers so you don't have to be afraid of this all right then log in to postman follow this sign up process here and then we see us on the other side then we want to create a new HTTP request and they have the shorthand here maybe in the future it looks different but somewhere there's an option to get a new HTTP request and it should look like this and here we select post because we want to send a post request we type in our localhost address localhost 5000 slash API slash nodes because this is the endpoint we set up and we want to send a Json body to the server so we click on body on Raw and then we select not text but Json and then in curly braces we have to define the Json here which should contain the title and a text right so we write it like this in quotation marks title colon my first endpoint note and the text this is fun and then we want to click Send and if we set up everything properly this post request should be handled on our server and it looks good because this is the response we got back as you can see here status 201 created this is what we defined in our endpoint and we get our new note back which contains an idea and all the data so let's look into a mongodb again refresh this and excitement there's our new note this time we created it through our own endpoint isn't that amazing and if you made it until here in this tutorial please go below and leave a like it's really important to me of course we can also run our get nodes endpoint as a get request here which gives us an array of our notes just like we got when we did this in the web browser let's also try creating a note where the title is missing because we defined in our mongodb schema that's the title is required right so this should give us an error if the title is missing let's remove this send it again and we get an error note validation failed title path title is required now this is not a very readable error message because this comes directly from mongodb but we will improve this later for this is nice so here that our schema is actually enforced however we can create a notificed the should work because this is not required in our schema and the succeeded so let's take a look into the database again and there's our third node without the text this time let's add one more endpoint for now to get a single note because it's interesting to see how we can access a single node so we go into our nodes controller again and just for organization let's put it here below get nodes export const get node singular this time of type request Handler an async error function with regress next semicolon try catch this is just the kind of stuff you repeat over and over again then before we set this up we go into the routes file add another endpoint here router.get this time we write slash and after that we'll write a colon note idea comma notes controller get node now this node ID is basically a variable which means that whatever we put behind the slash will be read by Express and put into the request object so we can read it in our get node endpoint and then look up the specific node for this idea so let's save this file and go into the get node function here again entry get this value is similar to how we got the values out of the body let's put it above the dry block const node ID equals we take our request object but this time we don't want to exist the board here we want to access the params and the params are these variables that we put here into the URL directly those are our strings basically and we want to take the note idea so it has to have the same name as we defined here with the exact same spelling and then we use Mongoose inside the try block to get this specific note so we create a const node equals a weight node model dot finds by idea which is a special Mongoose function where we can pass the idea of this model and it will find the specific document so here we simply paste the node idea this time we have to call.exec again to turn this into a real promise and then we want to do the same as up here return this node with a status code of 200 in the Json body but this time it's the singular node and not nodes save and now let's try this out we can either do this in the web browser or in Postman but Postman just formats this a bit better so I prefer this first of all we need an ID of a node so let's get all nodes and let's get this one here my first endpoint node we copy this idea add notes slash and then simply the idea because this is the structure of the endpoint we just set up and as you can see here this returns this exact node if we change a letter in here to a non-existing idea this fails for one because the snow doesn't exist but also because this is not a valid object idea we will add some checks for this later the important part is that this gives us the exact node for this idea later of course a user should only be able to access their own nodes but we will take care of authentication and stuff later and by the way these errors we get here we also can see them in the console because we are locking them which is especially important in production because if something goes wrong for a user you want to be able to go back into the log and see what went wrong so we see the error here as well now there's one more package I want to install here which is just a nice tool to have this one is called Morgan and it's just a locking tool so we can see all the requests to the different endpoints that were made on our server which is just nice information to know so let's stop our server once again and install Morgan the usual way and there's not much setup and worth in this it's just a simple middleware that we install in our FTS file and above Express Json right here we add another middleware with app.use but we have to import it first so up here we import Morgan from the Morgan package like this and this shows us an error here because it needs some type files this is sometimes the case when you use typescript with certain packages hover over this error and if you see something like this try npm is FDF if it exists or add new declaration type blah blah blah then you have to copy this part here is just installation command for another dependency which we install right now npm IR safe Dev adds types slash Morgan then this error should disappear we can start our server again and finish setting this up we simply want to call Morgan as a function and pass Dev as a string this just defines the type of information and the amount of information we printed the console you can read more about this in the documentation but this is pretty cool because it prints a concise log of all the endpoints that we access so let's try this out let's make a get request again and as you can see we now have this log message down here get request on this endpoint what status code resent back and so on and this is just nice information to have especially in production this is the endpoint with all the nodes yeah this is just something I wanted to add here and now we already have a real little server with different endpoints where we can get information from we can create new information really amazing of course we still want to add more endpoints but it's already a success but in the next section before we start adding more endpoints we will improve our error handling a little bit because as I already noted at some places we don't always return the optimal status code like here for our endpoint not found error sometimes the error message is not really good and really readable like the one we get from Mongoose by default so next we will take a look at how we can improve this because it's important and after that we will add new endpoints to update existing nodes and delete nodes okay so as I already said before we add more endpoints to our server we want to improve our error handling here because that's not quite optimal yet for one our endpoint not found middleware here which kicks in whenever we try to access the endpoint that we didn't set up like slash API slash blah for example at the moment returns a 500 status code because that's what we hard coded in our error Handler here so we basically use it for every error but different errors require different status codes 500 is the status code for an internal server error which basically means that something in our code went wrong and maybe we don't even really know what but an endpoint not found error should return a 404 code because that's the HTTP status code for resource not found so it's just more appropriate and it's better for the clients to work with secondly when we try to create a node without the title which mongodb doesn't like because we said required to draw for the title and mongodbier at Mongoose and fosters but if we try to do this it also gives us an error but with the default mongodb error message which might be difficult to understand for users so we want to provide our own error message instead and for this kind of HTTP errors there is a convenient package we can use so we open our terminal and ignore these error messages down here this is only on my site because I tried something a moment ago and did a mistake but if you don't know how to open the already existing terminal you can click on viewer and here on Terminal or use the shortcut that's right next to it this will open the terminal that you already created before if there is none you can also create a new terminal over this menu point up here that we used earlier anyway just open the terminal and then important we want to go into our backend folder again not into the root folder where we are right now this is where you see these error messages here I'm actually recording this a second time because I messed this up before so this is very important so we type CD slash back end to go into our backend folder okay actually without the slash just CD backend and then you need to make sure that the path looks correct so we are in our coding and floor learn course folder or however you called it earlier and then inside the backend folder here because this is where we want to install this new package so we type npm IO short for install HTTP minus errors and as usual you have to type the package name correctly otherwise npm will not recognize it we installed this and then we want to install a second one which are the type declarations again that we need for typescript to work with this package so again npm IR minus uppercase deal for def dependency add types slash HTTP errors type it out correctly and then press enter and this should have added two new entries here on our package.json HTTP errors in the normal dependencies and the types here and the dev dependencies we could also create our own HTTP errors instead of using this package but again this makes it more convenient so let's close the terminal with the same shortcut and then improve our code here we want to start with this part here instead of returning a normal error with this error Constructor we want to create a new HTTP error which we do with this function here from this package we are installed if this doesn't import automatically or if other completion isn't there then type in the import up here manually and this function also takes an error message that we already entered but it also takes a second argument which comes before the error message which is the HTTP status code that we want to return with this error and as I already said we wanna have a 404 status code for this one because 404 means resource not found which is appropriate for an endpoint that doesn't exist comma and the zinc argument is the error message just as before but the problem right now is that we hardcore the status codes down here on our error Handler so we have to change this code here as well below let error message we also create a new variable again a let for the status code we initialize this with 500 because this will be our file back if we don't specify a more specific status code then we delete this line here instead of checking if error is an instance of the normal error class we want to check if it's an instance of this new HTTP error because we basically want to use this throughout our whole server code so we remove this and write if and in between the parentheses of the if block we write is HTTP here which is another function of the HTTP Eros package but this one didn't import automatically so we do it manually so after create HTTP error we write a comma and again create HTTP error as the default import the other one is a non-default import so we have to add it between curly braces like this and then paste the name of this function again you don't have to understand the syntax here in detail just make sure to type it all the same way if autocomplete didn't work okay so is HTTP error down here is a function which takes an argument with a steroid serve this will check if this error is an instance of this HTTP error from the HTTP errors package if this is the case we want to take our status code variable and set it to arrow.status which we now have available because status is a field in the HTTP error class and the same as before we also want to set the error message so we take our error message variable and set it to error.message which the HTTP error class contains just like normal errors Alright and then the only change left is replacing our status code that we hardcoded down here for the status code variable which is either whatever status is in the HTTP error or a fallback of 500 for internal server error alright and now let's try this out let's save the code with Ctrl s open the terminal again and Run npm start to start our server and then I'm going to open an endpoint that doesn't exist again and as we can already see them because we installed Morgan previously we now have this 404 response here and we will see the same when we look into the Chrome Dev tools when we try to access an endpoint that doesn't exist status 404 which is just a better status code to return and displays an even more important role when we have different kind of Errors later now let's also improve the error messages for our node routes so we close our terminal go into the notes controller and let's start with create node here as I already explained at the moment when we don't pass a title we get mongosa's default error Throne which has an error message that might not be readable enough for the average user and also it doesn't have an HTTP status code associated with it so it will fall back to our 500 code for this reason instead of relying on Mongoose to check the title and throw an error we want to check the title ourselves in here and any other field that might be required this gives us more control over the error message and the status code and then the required field of mongoose itself is basically just a far back in case we mess something up but the first line of defense is the code in our own endpoint Handler okay but the problem right now is that the types of our title and text here is Nia because typescript doesn't know the type of these variables in the body here it also doesn't have to be a string that could also be a number for example but we can tell typescript what type of variables we expect in the body we do this by declaring an interface which we call create note body and then we make a pair of curly braces like this interfaces are very similar to types like we declared with this type keyword here in Mongoose the difference between interface and types are very specific and I don't want to explain all of them here but generally you want to use interfaces whenever possible because they are more flexible and there are certain situations where you can't use interfaces then you use types instead for example here in Mongoose we have to use a type because this is what in first schema type expects from us we can't use interface here but to declare the types of the single fields in our create note body here we use an interface and in here we just declare what variables we expect when we make this create note request and what types they should have and we already know what we expect we expected title of type string and a text of type string now we already know that the text is optional we don't have to send one so we add a question mark here which basically means that yeah we can send this text if we want or not so this might be undefined but we actually set the title to optional as well why because whenever someone makes a request to this endpoint we can't know if they actually send this data even though the title is required it might be missing from the request and then we want to decline it right but we still have these any types here because we have to actually use this interface in our request Handler here which we do by adding a type argument after request Handler which we do like this with a pair of angle brackets and then we have to declare four different types because this is all or nothing either we declare no type or all and by all I mean for the body for the URL arguments the fourth one are the URL params so there's a difference between a UI argument like our node idea and URL params which we have after this question mark and the fourth one I don't remember right now so and the body is the third argument for the other ones we want to leave them untouched basically which we do by passing unknown so unknown is used implicitly for all of them if we don't pass a type argument here we want to leave the type of the URL params and so on as unknown because we don't use these arguments here but we want to set the type for the body so unknown comma unknown comma create note body and then again comma unknown and when you hover over request Handler you can see at the order of these arguments we are passing here the params the response body request body and the query anyway and you might be wondering why do we pass unknown here and not any because any is unsafe any basically allows us to call anything on these variables unknown is the opposite it's restrictive so I think if we try to use the query params now which has Type unknown then we could not call anything on it I'm not sure it doesn't matter because if we needed the query params we would pass a type for them and not unknown but we only need a body right now but the magic is not visible when we hover over title and text because now they have types they are both string or undefined and again undefined is a possibility for both of them because we don't have a guarantee that whoever uses this endpoint actually sends both values over the difference is that if the text is undefined we don't care because it's not required but we care if the title is undefined so we go into our try block here because now we are playing around with errors and whenever we undo stuff with arrows we have to catch them so that our silver doesn't crash and we'll lose our job and everything remember here we check if and in between the parentheses we write exclamation mark title which means title is falzia which is the case if title is undefined then we want to throw a create HTTP error the same one we called in our endpoint.font Handler here because this creates an HTTP error which we then throw which then gets caught by our try catch block and forward it to our error Handler alright and what status code we want to use we want to use 400 this time and in case you're wondering where I'm pulling this from you can basically just type HTTP status codes into Google and you will find different lists with explanations for these different chords so every situation every kind of error has an appropriate status code and as you can see here for example 400 means bet request which is often used if there is an argument for example missing which is the case here we could use any stereos code here using the correct one as just a matter of making our API better usable for clients so it's a good idea to get this right and not use any arbitrary code entry also want to return an error method Shield note must have a title we don't need a return statement here to leave our code because a thrower leaves the try block anywhere and goes right to the catch block all right so let's try out our new error message here with Postman let's make a post request to our notes endpoint we still have the title in the board here but we want to put the text in the body and have the title missing which now should give us a better error message and that's not it because I didn't save the code yet so let's save it and try this again now it must have a title nice with the status code 400 so now we handle this error for this endpoint properly and not nearly villier like we did before okay but our get node endpoint here also has still room for improvement when it comes to error handling for one we don't really know if the node ID we passed here is even a valid node idea or if we are trying to use find by idea with some random value that doesn't make sense but even if the node ID is valid but doesn't exist the error we get back is just no but the short return of 404 response and a proper error message so let's improve this so let's start with checking if we actually get the notes back here or if it doesn't exist so we simply do an if check if exclamation mark node so if the node is neither or undefined then we want to throw a create HTTP error with a 404 code that says node not found which is much more readable than this noise we had before let's try it out let's save it and try to access the same endpoint as before which now shows the appropriate error message with a 404 code okay so this is already much better but what happens if we pass a value for the node ID that doesn't make sense because it doesn't adhere to the shape that these nodes IDs have to have because they need a certain length and certain kind of characters are allowed so if we just remove some of these characters here and try to access it like this we get our good old and unknown error occurred in a 500 response this happens because doesn't know how to uh handle this oddly shaped note idea it doesn't have the expected format here for find by idea but we can check it ourselves and then return an appropriate error message and Status quote if the shape is not what we expected so above the line where we call finds by idea we check if exclamation mark then we take mongoose is a valid object idea we could also import a spelled object ID directly then we don't need this stored in front of it but this way I think it's more readable because we know okay this is a function from the Mongoose package here we pass the note idea which is the URL argument if you remember it's this part here and this time we actually don't have to check if this value is present or not because if we don't enter anything here behind the slash then we don't get to this endpoint in the first place then we get to the normal get endpoint so we don't have to check if this value is null or not because if we end up in this Handler then we know that there is a node ID and it also has the type string by default so typescript knows that there is a value when we get to this endpoint but if this is not a valid object idea which is what this function here checks for returns true if Mongoose can cast the given value to an object idea or false otherwise so if it's misshaped like we saw before then we want to throw another create HTTP error a 400 response here is appropriate and error message will be a invalid node idea okay let's save this and try it out once again so we go to the same wrong endpoint here refresh this and this time we have a good error message invalid node idea and the 400 response so all of this is not really necessary but it's got practice because otherwise we end up with a silver with error messages that we don't understand and we never really know what's going wrong and it's also good to not let any values through it that we can't really work with because even though nothing really bad happens here besides an error that's not really readable it could cause problems in different parts of the code because we are working with values that don't have the type or the shape that we expect okay that's it for the error handling setup for now in the next section we will add endpoints to update and delete existing nodes very exciting okay now let's add end points for updating and deleting notes to our server so we go into our notes controller file and where we put it doesn't really matter but let's organize them in an order that makes sense so I put it at the bottom below create node we create an export const update node of type request Handler just as before and it's an async function that takes a request response and next function as arguments just like the other ones and in here we will also need a try catch block and this one will be interesting because it's basically a combination of our create note endpoint because we need to pass a title in the text but also our get node endpoint because we need the node idea that we want to update so let's next go into the routes file and add this new endpoint here before we forget it let's put it below router.post this time it's a patch request in HTTP patch request is used whenever you want to update a resource we set an endpoint for it which will be slash and then the same as up here call on node idea because we need to specify which node we want to update and we do this over this URL argument comma and then repairs notescontroller dot update node we saved this but of course we haven't implemented this function here so let's go back to our routes file we want to declare the body here the same as we did for create node so that we have types for title and text and we can check them properly so above this function we create an interface which we call update node audio and then here we Define the variables that we expect in the body which the same as before is an optional title and an optional text because we can't be sure that we actually get past these values by whoever calls this endpoint so I basically always make this body variables optional with this question mark they can always be undefined okay and I set up here in get node we don't have to Define an interface for the node idea because typescript knows that this is definitely a string because it's contained in the URL that we are writing out now we have to declare an interface for it why because we want to pass the update node body as the type to request Handler but we can't pass unknown for the URL params as we did up here because now we want to use them now we want to use the node idea that we pass via the URL so we can't set this type to unknown this time we have to set it to something specifically because again this is either all or nothing either we declare no type here in this request Handler or we have to Define all that we want to use so we call this update node params because those are the URL params and we expected the node idea to be passed over the URL programs of type string it has to have the same name as the argument here that we put in the URL and again we don't have to make it possibly undefined we don't have to add this question mark here because if we would not pass this value here we wouldn't get to this endpoint in the first place we wouldn't end up here because this requires a slash and a value for the node ID Alright and then we put these two new types on our request Handler so again a pair of angle brackets the first one is update node params comma unknown because the second one is the response body which we don't want to add a type to because we don't need it the third one is the update node body and the fourth one is unknown yet again because the fourth one is the URL query params that we are not using here either all right that now we can get these three values out of our request objects we create a variable node idea which is the part in the URL which we get over rec.params dot nodeid Auto completion works because we are defined it in this update node params type cons let's call it new title just to make the variable name a bit more descriptive because we are updating we are not creating a new node rec.body this time not params but body because we send the title in the body dot title and by the way in case you're wondering what kind of data you should pass over the body and what you pass over the URL it depends a bit and also it depends on convention we could also send the title and the text theoretically over the URL but this would be very unwieldy because it gets very long and we have to URL encoded and stuff like that so it's more appropriate to send the title and the text via the body and use the note idea as the identifier in the URL to a pinpoint to our exact nodes that we want to update okay and another variable for the text which is contained in request.body.txt so the first one is a string and the other ones are string or undefined and then we want to do some checks here to have appropriate error handling similar checks as we already did up here so we can actually copy some stuff we want to check if the node ID that we pass in the UL is actually a valid node idea just like we did for get nodes so let's copy this part and pastity on the try block then we also want to check if we actually passed the title which we already did in create node so let's copy this line paste it below but we have to change this to a new title because this is the variable name we can keep the error message to the same you can also change it like you can't update it node without the title or whatever but this here is fine then we want to get the node from the database so we write const node equals await note model dot find by ideal and repairs the node ID and let's not forget the exact color to turn this into a real promise the same as we did up here already in the get node endpoint and the same as up here we also want to check if this node exists and show a different error message if it doesn't so as you can see there's a lot of error handling involved here but this just makes sure that we always return an appropriate error message and code for all the different situations if we end up down here then everything was fine we can go ahead and update the node so we can take the node object that we already have here and just set the title to a newer title NZ node.txt to a new text and then below we'll save the changes but we store the changes in a variable again so that we can return it to the color of this endpoint which allows us later to update the node on the screen in our react app because we get the updated note back we don't have to fetch it again so we create a cons updated node equals a weight note dot safe like this this as the name implies saves the changes that we made to the node up here if there is any error that happens then it will throw we will catch it and return it to our error Handler there's also another way to update the node we could also do it with node model dot finds by ID and update then you can pass the node idea and it changes as a second argument this is also an option but this will look up the note again but we already have a handle to the node because we are fetched it to check if it exists right so there's no reason to fetch the node again and we can just use the save method here all right and now we want to return the updated nodes to the color so recall rest dot status pass a 200 code dot Json and SD Json body we return the updated note and let's also to our next error call down here to a card error Handler in case there is an error but here I did a typo I passed update node which is the name of this function it's important that we pass updated node which is the actual node that we get back after saving the changes okay let's also save the changes to this file and then try it out let's open Postman change this to a patch request and then let's take any idea of our notes Here let's use my first endpoint note we need the object idea because we want to update this we pass this here as the URL argument and we need to pass a body so now if the title is missing it should still show the error message that we need a title for the node node must have a title so this works as expected what other errors did we Define here invalid node ID Let's test this as well let's put a title in here let's change this to updated title but usern invalid idea send invalid node idea let's use one that is valid but not found so I replace the last letter for idea node not found but if we use the correct node idea then the update should go through and we should see the update reflected in our database so one more time the update went through we get our updated note back with the updated title and now when we look into mongodb again and refresh this we should see the changes update the title isn't that amazing but of course in the future we want to do this over our react app over our real website but right now we do it via Postman and this is already pretty cool okay then next let's add the delete endpoint which will be a bit shorter so let's put it below our update node endpoint function export const and by now it is the second nature for us delete node of type request Handler it's an async error function with our good old three arguments here we will also identify the node we want to delete by its ID in the URL so we create a const node idea equals request.params.note idea and this time since we don't need a body for the delete color we don't have to pass any type arguments here and we can use the default string type for URL Paramus try catch in the catch block because our error Handler over the next function and then in the try block we still have to check if it's a valid idea that we are passing here so let's copy this part here again then we want to check if the node actually exists you can do this step you could also just return a success response in both cases either if it was deleted successfully or if it didn't exist in the first place there are different opinions about this but I think it makes sense to throw an error message if this node doesn't actually exist because we expected that it was there but it wasn't so as the first step we look up this node and save it in the variable so await node model and again these awaits are important if you forget them then the return type will not be correct node model finds by ideal replace the node ID param and carl.exec then below we check if exclamation mark node so if this node is null or undefined then we want to throw a create HTTP error and since the note wasn't found we set the status code to 404 and the message will be a note not found if the note was found then we go ahead and call away node.remove which deletes it again there is an alternative for that which would be a node model dot find by ID and delete or remove I'm not sure right now which is the appropriate one you have to look into the documentation I think it's delete but since we already have a reference to the node it would be an unnecessary step towards hatchet from the database again okay so no dot remove and then Ria return a status code this time we don't need a body if we know on the front end that the deletion was successful we can just remove it we don't need the body of the old node for anything so instead of rest dot status this time we call send status with the code 204 which if I remember correctly means deletion successful or something like that it's important that you use send status instead of status this time like we used in these other endpoints why because status itself doesn't send a response Json is the card that's responsible for actually sending the response but since we don't send a Json body down here we have to call Zen status to set the status but also send it at the same time so in other words if you don't add Json then you send status save okay let's not forget to add this end point in our routes file here so our router dot delete this time delete is another HTTP verb and the URL will be slash and again the node ID entify the skull to nodes controller dot delete node save this and then try it out with Postman so this node ID up here should still be valid we change the verb to a delete and let's go through our different arrows so let's try and invalid node idea invalid node idea let's use a non-existing one node not found but as soon as we pass the correct node idea this node should get deleted and removed from our database so zent we don't get a response back because we only send a status code but the status code tells us that this was successful which means that on the front end when we get this back we know okay our note was deleted and we can remove it from the UI and when we look into the database and refresh it this node here with the updated title should be gone so refresh this and where is that moment our notice gun farewell old friend okay in the future of course we want to protect this via authentication we don't want to allow anyone to delete any nodes nearly villier any user should only be allowed to delete their own nodes but this is something we will add in a later section of this tutorial for now we will leave our server aside a bit because it starts getting boring right adding more and more endpoints that's lame in the next section we will actually start building our react app we will get back to the server here later because we aren't finished yet but now it's time to write some react code because that's fun all right to create our react app let's go into the folder where we also put the backend code let's put it in here as well you can also put it somewhere else I do this so I can push them to the same GitHub repository so you can find everything in one place now when you set up a newer vanilla react project then you should do this over the command line with this special create react app command which you can find in the docs or if you just type in create react app in Google but we basically just need this command here you can also type it out by hand instead of copying it let's do that let's go into this folder open the command line here and again on Windows you do this by holding shift down right clicking open Powershell here and then we type npx not M but X create minus react minus app then we have to give it the name I'm just gonna call it front end for organization and then to initialize this with typescript we also add Dash Dash template space typescript so the full command looks like this npx create react app the name front-end template typescript enter and now we let the magic happen it will install the following packages create react app blah blah we type in y to confirm this okay looks like it went successful now it saves 10 highest probability of vulnerabilities so it's probably the case that it doesn't install the latest dependencies we can do this later we can update them for now this is fine we close this and as you can see it created this newer front-end folder in our project which contains a lot of files that we know already from our backend we can also see it here in our project directly so we have a package.json file with dependencies we have a TS config file which is already set up properly we have a git ignore file with the most important stuff and we have the source folder here which contains the source code of the react project create react app also sets up some other stuff for example the whole tool chain that allows us to compile our code basically into production code which also minifies it so it runs more efficient and it can't be reverse engineered as easily this is all set up by this create react app command now first of all let's go back into the package.json file of our react app and let's try updating these dependencies here maybe we can get rid of this warning about the 10 highest rabbit here vulnerabilities first of all I want to point something out as you can see in react all dependencies are installed under the dependencies block even the types and so on and the dependencies we only need for development are here and not in the dev dependencies block you can put them in the dev dependencies block but I read their reasoning behind putting all of this here this is because when we later built the project everything that we don't use will be Stripped Away anyway this is not the case for our back end but it's the case for react apps this is where you can just put everything into the dependencies block and it will not make a difference so we don't have to do a install safe def we can just install everything as a normal production dependency and by the way eslint is also configured by default so we don't have to install this either but let's try updating our dependencies here but we are still in the backend folder we want to get to the front end photo as we go backwards one step with CD and then two dots if I remember correctly right and then we want to go into the front-end folder and I'm actually not sure where the vulnerabilities are coming from so let's run npm audit which checks the dependencies so where is this coming from I don't really know because I think the dependencies are actually up to date already I just checked them a moment ago so let's run npm audit fix to try to fix them automatically no it still didn't work but here it seems to be caused by react scripts so maybe there's something wrong in the latest dependency we could run npm audit fixed false which were basically set it to an older version but since this is a tutorial and you might watch this in the future where this is not the case anymore let's just keep it as it is Let's ignore this for now if you watch this in the future there might be not these vulnerabilities anymore otherwise you can run npm audit fix false which will set it to the appropriate version so this vulnerabilities disappear but for this tutorial we will ignore this but let's actually run this app because we can run it with the default setup we type npm start and the react app runs on Port 3000 by default as you can see here so now you can either type in this localhost address but it actually should open it automatically and this is our brand new react app this is how it looks by default the cool thing about developing react apps is that we see changes that we make to the code instantly so let's close the console here let's actually close all the tabs because most of them are from our backend code let's also collapse the back end folder and then let's go into app.tsx before I explain what all of this means let's just make a little change in here let's change this text to subscribe to a coding in flow and as soon as we save this it changes over here so this is a lot of fun in development because it's really fast you can see the changes instantly in the browser okay whenever we work with react we have this TSX files if this was not a typescript but a normal JavaScript project this would be called jsx and jsx or TSX is kind of a mix between HTML and JavaScript so we get this weird mix here where we have yeah HTML tags but we can also write JavaScript in these files entry act as a so-called declarative UI framework to understand what this means let's look at the old approach the imperative approach so usually on websites we have an HTML file that contains the basically the structure of our website where our buttons are where text is and so on in this example here we just have a button but of course a real HTML file has a body and different components and so on and then we have separate JavaScript files so we don't have this mix between HTM and JavaScript that we just saw a moment ago we usually have to separate it and in our JavaScript files we can interact with our HTML files and we can make changes to the text of buttons or other elements for example so in JavaScript we have stuff like variables because JavaScript is a real programming language and when we want to change something we look it up like in this example we look up the counter button with this get element by idea function we can set an on click listener on it and here we can Define what we do when we click the button and imperative means that we are basically micromanage what happens we say okay we want to increment the counter variable and then we want to go ahead take our button change the text inside it with this inner HTML card here by changing this we change the text contained in this button and then we Define what we want to set this to we want to set this to a current colon and a new count this is how a programming worked in the past basically the downside of this is that it's easy to forget stuff like changing the text properly of course this is a simple example but if you have a real app where many different things change in many different places at different situations then this is easy to get wrong and add bugs in the future because we always have to micromanage what we change at which point in time right declarative UI Frameworks changed this concept a bit and react is one of them jetpack composes another example of a declarative UI framework on Android I think Swift UI is one as well and flutter too with declarative UI we are defined one time what kind of data is an element on the screenshot contain and then it's basically updated automatically so this is basically the same button example as before but this time it's react code so imagine that this is a jsx file or TSX so we can put all of this in the same file the JavaScript and the HTML code and in a declarative UI we are defined one time what kind of text this button should contain so as you can see we have this button tag and here we have count colon entry passes count variable now the difference to imperative UI is that when we now increment is counter and we change this current variable this text here will update automatically we don't have to go ahead and there change the text or the HTML of this button to this new value nowhere here in this code does this happen because it happens automatically that's called declarative because we declare how the layout looks the UI and then react takes care of keeping it in sync with the data it depends on so whenever the current changes react knows that the text of this button has to change as well and it basically recharge this whole button on the screen and this is okay because react takes care of making this efficient under the hood and the main benefit of this is really that it's easier to keep our UI in sync so if we have many different places and different variables different states then we just have to declare how the different components look and what data they should contain entry Architects care of keeping everything up to date as long as we declared it properly and because we have this mix between HTML and JavaScript we can also do stuff like putting for Loops directly into our HTML and saying okay depending on the size of a variable we want to add more or less items to our layout for example so we can do some really cool stuff it also allows us to work create reusable components that we can use in different places in our app because we don't have this arbitrary separation between HTML and JavaScript which actually was never a good idea because it's a separation of Technologies and not a separation of concerns as it should be but jsx or TSX fixes this by allowing us to work riding this mix between HTML and JS and we will actually rebuild this example in a moment so let's go back to our react project first of all let's install bootstrap or rather react bootstrap which is this UI library that we want to use it just makes it easier to create uis that actually look good it's completely free and I think it's easier to use than Tailwind CSS for example so here are the installation instructions we basically want to copy this line npm install react bootstrap and bootstrap so those are two dependencies so open the terminal here cancel the execution with Ctrl Z make sure that we are still in the front end folder and paste this command while this is installing we take a look at the instructions again we have to import this part here this Imports the CSS so that our elements actually look good there are also different ways to install this or customize this but the rest here doesn't really matter for us we just want to copy this line and you can get it from this URL or take a look into the code in the description below of my project on GitHub there you can also copy it from and Twitter reporters we put this into the index TSX file here which is another TSX file just like our app TSX now the order of the CSS Imports is important so we put it all the way at the top here and import this bootstrap Min CSS now index TSX basically initializes our react app for this it uses another file in the public folder here which is called index.html as you can see this is basically the structure of a normal website this is a normal HTML file and this is where our react app appears later basically so this is our page that we load when we load our react app down here we have this root tag and index TSX looks up this root tag and it renders our react app at this place and the react app is the app.tsx file that we made changes to a moment ago we don't really change much in this file besides little things like importing the CSS because we want to do this very earlier in our code we could also do this in the app TSX file but we actually want to do it before we initialize the app itself and here we also see something that we saw earlier already this text here you need to enable JavaScript to run this app if you remember in the beginning when I disable JavaScript in the browser without the same text this is handled by this no script tag here and if JavaScript does work then we see our normal route where our app is rendered in this index HTML file also contains metadata about our website so as you can see we have this title tag here we have a description somewhere and we also have stuff like the preview images for social media now you can read more about this by just Googling or reading the documentation but let's make some little changes in here let's change the title to a quill Notes app and let's change the description as well which is this meta tag here website created using Create react app this is what we see for example later in Google search when our website shows up there let's change this tool tutorial project by coding in flow because of course you always have to give appropriate credit then save this now when we run npm start again and look at the page again after the test started we can see the changes to our metadata now the title says Square Notes app we can't see the description but again we would see it in Google search for example the little fav icon here on the top left this little icon you can see here is also something you can change in this index HTML file there's a path icon text somewhere this one here there are generators for this kind of icons that you can find in Google but we will leave the rest here untouched also interesting to notice the public folder here this is where you put files like images that you want to use on your website we won't add any images but these react pictures here that we saw on the page are inside here you can delete them if you want you can also leave them there it doesn't matter and if you want to learn more about these different folders and file types that I don't explain here then of course everything is explained in detail in the documentation and now as promised let's rebuild our button example our button clicker that we saw a moment ago on the slides for this let's go into the app TSX file because this is where the code of our actual app lives basically of course later we have different pages and different components and we create separate files for them but they are all put here in one way or another we will talk more about the syntax of these react components later but for now let's ignore this and the first thing we need for our calendar is a variable of course that maintains the current count now the first idea would be to just create a let counter and initialize this with zero but in react we need a special type of variable for the state of a component because we need to notify react that it has to redraw the UI to display the new value so we don't use a normal variable we create a state like this const then we make a pair of scrap brackets and then here we write click count which is just the name we give this variable comma and the second variable in here is set click count so we always have a variable and then we have basically a function with the same name but just set pre-appended to it outside of the scrap brackets we write use state which should add this import statement up here if it didn't edit manually and we initialize this with zero and because typescript has Type inference as usual it knows that click count is a number because we initialize it with a number so this weird syntax means that your state basically returns us a little array with two values and create destructure it like this we take the first value call it click count and the second value which we call that click on one is the value itself and one is used to update the state and we do all of this here at the top of this F function before the return statement because the return statement Returns the actual UI element okay and then we want to put our button somewhere let's remove this learn react link we don't need it anymore instead create an opening anchor bracket button which creates the HTML element entry One Import button here from the react bootstrap package which adds this import statement we close this and in between this text we can now Define the text contained inside this button so for example if we just write click zero times and save this we see the change in our UI this is the bootstrap button just for comparison if we didn't use bootstrap but the normal HTML button it would look like 1993 but we use these special styled bootstrap buttons but of course we don't want to hard code the zero here we wanna show our click count so instead of 0 we write a pair of curly braces because this is how we put a variable in between these two pieces of text and in here we pass the click on when we save this it still says 0 but this time it's coming from this state up here and now as I explained the magic of declarative UI is that when we update this click count over this set click on function the text in here will change automatically we don't have to micromanage this like in the imperative approach and we want to change this value on when we click the button so in the button opening tag we can add an on click function like this make sure that you get the spelling right candid case with an uppercase 0. and in here we want to pass a function we pass an anonymous function like this pair of parentheses a right arrow like we did in our server code and since this is only one line we don't have to add another pair of curly braces instead we can just call the function that we want to call directly we want a car that click count and we want to set this to a click current plus one two add one to the value that we already have let's save this and try it out now when we click our button the state gets set to a click count plus one so zero plus one is one and since we updated the state react notes that it also has to update the content in the button and this time it's really difficult to mess this up in the future with that how this button should look what data it should contain and react takes care of updating it properly okay we Now understand declarative UI and you can put react developer on your resume but of course if you want to learn more about react in your short stick with this tutorial because the next step is to actually fetch the nodes from our backend and display them in the UI somehow okay so before we can fetch the nodes to the front end we need a model for the nodes on the front end as well so we create a new folder in our source folder here in our front-end folder so in our react code and we call this lowercase models not uppercase and then we create a file in here we right click new file and we call it node.ts attention this is not a TSX file this is not this weird HTML JavaScript combination it's just a normal typescript file because all we put in here is one interface that we want to export so that we can use it in other places we call it node and this will contain the shape the structure of our node type that we receive and use on the front end okay so every note we will get from our server will contain an idea with an underscore because this is how a mongodb automatically saves IDs underscore idea and it will be of type string now technically the idea in mongodb is a different type it's this object ID type that we used before but what we will receive from the endpoint will just be a string and that's all we need to work with every note will have a title of type string the text of type string but the text remember is optional so we add the question mark here because there might be a text in the node or not and then the timestamps are created at and the spelling has to be correct because this is the name with which mongodbier stores these timestamps and this will also be of type string because rotary receive is basically a string representation of the timestamp and the reason why everything is a string is because we receive Json from the back end and Json doesn't have where we elaborate data types there is no date type in Json for example but string will suffice because we can pass everything from the string that we need okay and then updated it which is also of type string let's save this because this is all we need in here all right and then let's go back into our app TSX file because instead of a borrowing counter we want to retrieve our notes here and display them in the UI so let's remove this line here with the click count and replace it for another state so another const with the square brackets and these two are variable names in here we call it notes and the equivalent as the zetter function is z nodes there's always this pair between the variable and the zero when you use State and react equals use state and this will contain the nodes that we display on the UI in form of a array we want to initialize it with an empty array because at the beginning when the site is opened there isn't any data in there yet we have to fetch it from the back end first but this way typescript doesn't have enough information to infer the type properly so when we hover over nodes it's of type never array so we have to tell typescript what type the state has to be later and we do this as usual with a pair of angle brackets and the type will be our newer note type we created in the models folder but it will be an array an array of notes and now nodes has the correct type here okay but now the question is where do we load these nodes we can't just put it directly in here inside the body why because if you remember I explained that react basically redraws this whole component whenever something in it changes and it does this by executing this function again so now when we do something in the function body which is called a zeit effect so something that doesn't belong to the rendering itself but something that happens in our normal app flow and we do it directly here inside this body then react will execute it on every render every time this function is called which of course isn't what we want it's way too often instead we want to load our nodes one single time when the app starts in this on click Handler down here we didn't have this problem because this only gets executed when we click the button we are not calling this function in the body of our app component we call it only when we click something so this is an appropriate place for these side effects but we don't want to have to click something before we load our nodes we want this to happen automatically and for this we use something called us effect as usual if it didn't import properly added up here next to you state it's a react import and this is a function that takes another function as import so we make a pair of parentheses and put another pair of parentheses inside it and the right arrow so an error function and a pair of curly braces like this refuse effect we can execute side effects outside of the Year rendering of the component itself in here we have control over when it executes and how often as you can see the documentation says accepts a function that contains imperative possibly effectual code in here we want to load our nodes so we basically want to do const response equals await because it's an asynchronous operation we have to load something from the back end this can take a moment and to fetch data in react or in JavaScript in general we have this fetch function available that takes the URL and some configuration and here we pass a string and the URL where we want to fetch the data from that's HTTP colon slash slash localhost colon 5000 because that's the address of our server in development slash API because this is how we configure the endpoint right slash nodes and then after the string we write a comma because here goes some configuration for this request for this fetch call and in between curly braces we write method colon and then get as a string in all uppercase this configures that we make a get request with this Fetch and not a post or a patch but a weight complains because we only can execute a weight inside an async function but when we try to make the function and use effect an async function we get this lint warning effect callbacks are synchronous to prevent race conditions but they also tell us the solution put the async function inside and then they are basically doing this so we remove this async here again and we simply have to wrap this inside another function which we can then make async so we create an async function which we call load nodes doesn't take any arguments and then we take our line here cut it out and put it inside and then we can simply call this function below to execute it this way we don't have to make the use effect itself async and display react is happier also this fetch car can throw an error if something goes wrong so we have to wrap this into a try catch block so we create this try catch block cut out this line once again put it in here and in the catch block we will simply lock this error and show a message to the user we related to the more elaborate error handling but for now that's sufficient zor rewrites console.erlaw pass the error which we are printed to the error console and then we can also call alert and pass the error here as well alert opens a little pop-up window in the browser it's not very beautiful and it's not a great user experience but for development this is sufficient okay then we go be a load the fetch line again because now we want to get our data out of this response we are still inside the dry block so everything went well we create a const nodes and then we have to add another weight because passing the data out of the response is another asynchronous operation then we take response and carl.json which passes the Json body out of this response and when we take a look into our nodes controller we remember that real return our nodes as a Json to the front end so this is what we get out of here when we pass this Json and then recall set notes which is our state function here and paste in your notes this way we update our state and wherever we use these nodes in the UI this part now gets updated by react and we can display this new state one more thing that's important we have to pass a dependency array to use effect we do this down here after the function which is the first argument that we passed rewrite the comma and an array with two scrap brackets in here you can pass variables that whenever they change they will execute this use effect again if we pass an empty array like this then use effect we'll only execute one time at the beginning this is exactly what we want however if we would pass no array at all this would again execute on every single render and this is pretty much never what we want because this is the same effect as if we put it directly inside the body without the use effect so if you want to execute something one time you pass an empty array like this okay and we haven't designed a layout for our nodes yet we will do this later for now let's just display the data that we get back in the form of a string so what we do is we remove this whole header here because we will create our own layout later and we want to display the value of our state variables so we make a pair of curly braces and in between we write Json and uppercase dot stringifier which as the name implies can turn a Json into a string such as that we see that we actually get some data back and here we pass our nodes then we save this and we are try to run this first of all since I closed everything I have to start the servers again both the front and and the backend so ICD into the backend code Run npm start here to start a server and then I'm gonna create a new terminal so if we have a separate one for the front end and again you can do it via this command here a new terminal here icdn to the front end and Run npm start here as well and then react will open this on localhost 3000. and let's see what happens so this is the alert dialog that we wrote here which means that there's an error that happened so let's look into the developer console which is a good habit to get used to anyway as a web developer let's refresh this to see the error here it is in beautiful red and it says course but we see the actual error message in the console failed to fetch access to a fetch at our server endpoint from our front end address has been blocked by course course stands for cross origin resource sharing and it's basically a security mechanism that doesn't allow our front end to fetch the data from our server because they are on different addresses localhost 3000 and 5000 count as different addresses now there are two ways to get around this either we have to configure on our server that we are allowed to fetch data from this address but this problem actually doesn't exist when both the front end and the back end run on the same address and later in production we will actually deploy everything to the same URL just that our server code will be behind this slash API endpoints but later in production we will not have this course problem we only have it now in development because we have these different localhost addresses but there is something we can configure in reacted that will make it look as if the request is going to our own address we will do this in a moment with something called proxy first I want to clarify a few other things first of all why did Postman not have this problem why was Postman allowed to fetch these resources this is because the security mechanism is actually enforced not by our server but by the browsers so Chrome for example implements the security feature and every browser can decide if they want to adhere to this or not and Postman just ignores it basically because it's a development tool Postman knows that we don't need a security mechanism when we use it because it's not a real browser we're not actually observing the web like a normal user the other thing I want to clarify is as you can see everything gets executed twice we see our error messages drives and when we refresh this we should also see the alert message twice don't get confused by this react just renders everything twice in development as a reasoning behind it that is written somewhere it makes debugging easier apparently but yeah it executes everything twice so don't get confused by this this will not happen in production it's just a development feature but yeah now let's go back into our project and implement this proxy I was talking about for this we go into the package.json of our front end which was generated automatically earlier and somewhere in here we put another key I'm going to put it above the dependencies which is called proxy colon and then we basically just pass the URL of our server in form of a string so HTTP colon slash slash localhost colon 5000. we saved this then we go back into the ftsx file and just remove this part here because now the proxy knows that these relative URLs will be added to this URL and this way it also doesn't have problems with calls because it recognizes this as its own URL basically this is just how this proxy works then we have to save everything and we have to restart our front end otherwise this proxy doesn't go into effect so we open the terminal of the front end press Ctrl Z confirm it and Run npm start again and lint complains about some unused stuff but it's just because we haven't deleted it you can do this if you want but it automatically opens the page again and you can see our notes array from the square bracket you can see that this is a Json array and it contains our first node and our other one and even though our website wouldn't win a design price yet it's already a queer feeling that we receive our notes from our own server on our react front end right and this is the raw data and we can then use this raw data to put it into good looking components and display them in the UI this is what we will do in the rest of this course one more thing I want to clarify this proxy approach works because we have our own server and our own front end if you want to build a public API where different clients can access it then you might have to set up course properly to allow these different Origins and you can do this very easily with this course package here you can install this on the back end with npm install course and then the setup is explained here it's a very popular package over 5 million weekly downloads but we don't need it because we are not building a public API but just in case you want to build something like this and by the way if you were got to this point and haven't liked the video yet then I really don't know what's wrong with you leave some support I put out a huge course for free and you can help by just leaving a like on the video because it helps this video grow better and reach more people thank you very much okay to make our notes better looking than this string representation here we have to create a component for our nodes a component that contains the layout of each node Zoom we go into a desert bar here into our front-end folder and inside source we want to create a new folder which we call components and this contains all kinds of single components as opposed to stuff like models or later our Pages which also go into a different folder we right click on our new components folder create a new file and colored node.tsx this time so this is this HTML JavaScript file and not just a normal typescript file and react components come in tour forms either a class or a function I've actually never built a component as a class because this is the old approach this is what I used in the past before I started learning react now these components are all created in form of functions and the app itself which is our front page basically is also a function so such a function creates a piece of UI basically and we want to do the same thing for our node component now we will type our dysfunction by hand once and then we will install an extension for the s-code that gives us a shortcut for that so we can either write it like this function or we can declare it as an error function and the extension we will later use also creates error function so let's keep this style so we create a const uppercase node equals and then we create an error function like this a pair of parentheses a right arrow and a pair of curly braces and then below we want to export this function so we write export default node and now in here we can declare the UI for a node and then we can use this in different places in our app but in order to display the data of each node we have to pass the nodes to this component right otherwise where do we get the data from so to declare what types of data this node should receive we have to create another interface again this is only necessary in typescript and JavaScript you don't need types so you can just pass everything nearly Billy but we don't want to do that we want to be a bit more descriptive but safe and you can call this interface anything you want I think a good naming convention is the name of the component itself and then props appended to it props is what we call the arguments that we pass to our component I think it's short for properties and we want to pass a note to it what kind of note our node model so we write note and import this model's node type here now it's a bit confusing that our node model and our component here have the same name and this can also cause problems but I don't really want to name them differently but we can use an alias for the name so what we can do is we can go up here behind import node and write as note oops node model this way we keep the name of our node interface here as it is but we use it under a different name inside this component so in here we change this to node model as well gonna add a trailing comma it's not necessary but I like that and then we add this as an argument to our node function here and we use this destructuring syntax where we write a pair of curly braces the name of the variable the name of the parameter which is the same as up here node and outside of the curly braces we write colon note props and if we add any more arguments up here to the interface then we also add them to this list so comma and then the next one and now we can use this node data inside this node component and what we want to do is we want to draw some cards on the screen from the react bootstrap package because they look pretty good you can read the documentation with all the features that are available all the styling options but for this tutorial you can just follow what I write here so in this function body here we want to return something because what we return is the UI that gets drawn on the screen we put it between parentheses because this allows us to write something below it Beyond many lines and this just makes these parentheses necessary so that the return statement knows what belongs to the return here we write open the anchor bracket uppercase cut and we import it from react bootstrap close this which automatically adds the closing tag and here we put a card dot body tag close it as well and then another one in here cards dot title and for the title we want to use the title of the note so we make a pair of curly braces and in here we write note which is the node model that we pass to the component dot title let's leave it like that for now see how it looks and then add the rest of the notes to it arguments that you pass to a component like our node here worked the same as state whenever a state changes react knows that it has to update the UI that depends on the state whenever an argument that we pass to a function changes react knows that it has to update this component as well which means that if we make a change to a this node object that we pass to this node then react knows that it has to withdraw this component and show the latest data let's go over to the ftsx file again first of all let's change the name of our node model here as well so we don't have this clash between the model type and the component name we change this to node model as well and then we change the name here in your state and then instead of just stringifying the notes we want to turn our notes into this note card we just created so we keep the div add a pair of curly braces then we take our notes which is our data the node model array and Carl dot map and map is not something specific to react but if you're not familiar with it map allows us to take some data like the array of our nodes here and turn it into something different this is exactly what we want to do we want to take our raw node models and turn them into a node component objects and we do this with map and since we are in this TSX or jsx file we can write normal JavaScript in here we can add Loops we can add map calls and so on this makes this whole thing very flexible because now we can map our data directly to this HTML components so map is a function so we add a pair of parentheses and then we have to pass an error function this error function takes an argument which is each node object in our array so we write node and the right arrow so this way we get past each single node of our array and now we can decide what we want to transform it into we want to write this in a new line so we add a pair of parentheses just like we did over in our other component in a return statement and now here we want to create our node component so we write opening angle bracket node which comes now from our components folder this is the node TSX component we just created we close this with a slash and a closing angle bracket and this still shows an error because this expects an argument which is the argument that we defined up here it expects a note where do we get this node from we get it from the map card here so we pass it in between now one more thing whenever we have a list of stuff like this our list of nodes we have to add a key to the object as well this key property is there automatically we didn't have to add it to our node it's just added by react by default now sometimes lint complains about this but this time it doesn't I'm not really sure why but we should add the skill otherwise there will be a warning in the console later equal Zone curly braces and for the value of the key we have to pass a unique identifier for each node this is just necessary for react to know when it has to redraw this node and what is a unique identifier now the idea is always unique to each node so let's use that one so let's save this and see how it looks so I open our localhost again and we have our two nodes it's still not beautiful but something happened on the screen this is supposed to be a card this is the card's title and this is our two notes so now let's improve the styling so let's go back into the node TSX file and finish the styling here first of all we don't only want to use the title value in here we want to use more values and instead of writing notes.title note dot text and so on we can use the same destructuring syntax we used to appear to unpack these single Fields basically that's just a simple JavaScript feature what we do is we write const a pair of curly braces after the closing curly brace you write equals note so we are unpacking this node property here and let's see if we have other completion yeah we have because I already added this equals node and then we want to list each field that we want to use here in our component we don't need the idea but the other ones supervised title comma text created at comma updated at comma and now we can just write title here instead of note or title which I just like more because we already know that we are inside the node component so this word is enough in my opinion so below a card dot title we add the card dot text again you can see these different texts and the combinations of them in the bootstrap documentation here we want to write the text let's save this and we see the changes immediately only this node here has a text but of course we also want to style these notes with CSS we're going to change the shape the colors we want to add Shadows later and so on so we have to write some CSS now we could put the styling into the app.css file that we already have there's already some default code in here that we got when we render create react app command but I don't want to write Global CSS because this later makes it difficult to organize your CSS properly because there can be clashes between different classes with the same names instead we want to use CSS modules so what we do is first of all we delete this app CSS file so we selected press the delete key and delete the sucker we also have to remove the import statement here from the app TSX file so it compiles again and then we want to remove this class name app here because we just deleted this whole CSS file so let's remove that as well and we still have this index CSS file which is imported in the index TSS file here but we don't want to delete this we want to make this our Global CSS file because even when we use CSS modules we want to have one single Global CSS file for some stuff that we just want to set up once globally and not for each component like the font throughout our app for example so what we do is we change the name of index CSS by clicking on it and pressing F2 on the keyboard or right click rename whatever you want let's call This Global CSS to make it clear that this is a global CSS file going to the index file change the name here as well and this will be the only place where we are allowed to write Global CSS code and let's actually add something new in here let's set a background color for our whole app so in the body tag we add background colon and then a pound symbol or for your Zoomers out there a hashtag f-a-f-a-f-a which is this very subtle light gray that you can now see here but now for our node component we create the CSS module so that the CSS of our node component can't clash with any other CSS and let's create a separate folder for our CSS files so on source and our front-end folder we create a new folder called styles first of all let's put our Global CSS in here we might have to update the import in our index file to a slash Styles slash Globus CSS okay it works again and then we create a new file in here which we call node Dot module.css and as the name implies this is how we create a CSS module with the name Dot module.css in here we want to create two classes which we do with a DOT this is CSS syntax note card and candle case and another one called card text this is the tour pieces that we want to style for now before we set this up let's save this and add it to our node component so in our node.tsx file we add another import statement let's put it all the way at the top import styles which will be the name of the variable of our CSS modules you can also give this a different name from and then the path of our node module CSS file so dot dot slash Styles slash node Dot module.css and now we can use the CSS module in here and it won't clash with any other components it will be ignored by other components unless we are imported there as well we want to use one of the classes here for the whole card so we add something to this card opening tag class name but instead of a string we add curly braces and pass Styles dot note card which is the class name that we adjust added here to the node module CSS and we want to use the other class here on the text so we add class name here as well Styles Dot card text with the same spelling as in our CSS file we save this and then we go back into the node module CSS file now we can style our node in here let's start simple let's set a background color on each node and you can use whatever you want I'm going to use this conzig which is this yellowish color and I also want to style the text and to show you what I want to do exactly let's open the database again and I'm gonna add a text here to the node that doesn't have one yet so text colon and then I want to write a text over multiple lines so this is line one this is line tour let's keep one line free this is line four save this and see how it looks in our front end when we refresh this okay as you can see it's all in one line even though I put it in separate lines in our database but we can fix this with this white space attribute and we set this to pre-lions if this and now it's formatted like we added it in our database now our cards don't have room between them yet which of course we can do with the margin attribute it will look like this later but we actually want to add this margin in a different place later so I'm going to remove it again and if you want to know where I learned these CSS attributes from I just learned them through Googling I never formally studied CSS I didn't go through a list of all attributes I just look up and Google whatever I want to do like this white space pre-line and then you can find it somewhere the other thing I want to point out is you might be wondering why this is called kala's name and not just class because a normal HTML the attribute is just called class this is because we are in this TSX file here and class is a reserved name in JavaScript code this is why they changed it to class name instead otherwise this wouldn't work alright so we already learned some CSS styling our nodes at least look a little bit more like notes now we are not done yet we will finish up the CSS in the remaining tutorial okay to put our notes into a nice grid we will use another component from react bootstrap they provide these grid helpers here which are rows and columns and containers that make it easy to create a responsive design and automatically adapts with the screen size so again you can read the documentation but you can also just follow along we go into our app TSX file once again because this is where we map the nodes and here we want to shape them into a grid now first of all we want to change the diff to a container which is a bootstrap component let's not forget to change the closing tag as well this just adds some padding and zenders the notes on the screen then in here we want to set up our grid which we do the following way we add a roll which again is coming from the react bootstrap library and it's adding all these import statements up here and we do some configuration in here we have to Define at which screen size how many rows we want to show in our grid and you can change this however you want but I tried it out and I found this the best configuration at rapid small screens we want to show one column add medium-sized screens and we have these different properties for these different screen sizes MDM we want to show two columns and on large screens we want to show three we close this and we cut out the closing tag and put it below our map call here now when we save this I think we should already see a difference here you can see how it grows and shrinks we don't have three nodes yet so let's add a third one let's do that with Postman real quick so we do a post request to our notes endpoint we need the title let's call it node three let's also add some body text this is line one let's just add one line here the centers and let's create a fourth note as well and it says this is line one I actually don't know how I can add multiple lines here not sure if I can just do it like this probably not so I will add more lines later in our database create a fourth note go into our database backend here refresh this I just want to make the fourth note a bit bigger so I go into the text here this is line two this is line three and save this take a look at our front end here again and now we have more notes and because of our row setup here the layout changes depending on the size of the screen it's not perfect yet but we are getting there to add some margin here between our elements in the grid we add a class name to the row tag which this time will just be a string we use this g-4 class which is a class from the bootstrap library that adds some room between the single elements in a grid we could also create our own class in our own CSS component but we might as well use these predefined ones here let's again change the size and see how this looks okay there's still no room horizontally between the notes we add this by wrapping the single nodes that we map in here into column elements so we go inside this map call here inside the parentheses Andrea wrap the note into a column again this is a react bootstrap import cut out the closing tag and put it below our node here now we also have to move the key from here to the outer element so we cut this out and put it in the column now there should be some horizontal spacing between our notes as well as you can see the slices are different so this doesn't look good yet we will fix this in a moment we want to get all of these notes at the same height the question is where do we put the CSS of course we could put it into the node module CSS file here so it will be applied to every node however I want to keep the styling of these notes a bit more flexible and give the outside component control over how each node looks the same is the case for stuff like the Box shadow that appears when we hover over a node I don't want to bake this right into the node component because then every place in our app has to display it the exact same way instead I want to declare The Styling on the level of this page here and then just pass it to the node also it's a good way to learn how to pass class names to a component so what we do is we create another CSS module in our Styles folder which we call notes page.module.css we will use this on the page that displays our nodes at the moment that's the app TSX file but later this will be a separate component in here we put a node class and a node colon hover class this is how you define the styling of a class in CSS when you hover over it with the mouse now before we fill this with actual styling let's use this in our app TSX file so we go in here we import The Styling import styles from and the path is here dot slash Styles slash notes page Dot module.css and then we want to style our node from in here this way as I explained this page defines the styling of the node and not the node itself or at least part of it but first we need a way to pass a CSS class to our node component so we go inside the node component and we add another property to the node props which we give the same name as the normal class name attribute here but we make this optional so we can pass a class name to this component or we can omit it and it will be of type string and then we want to add this class to our Cartier to the outermost component so we can style it from the outside we already have a class in here so how can we add another one we can change this to a string and we do this with a pair of back ticks like this because backticks allow us to put variables inside the string so we wrap this styles.note cut into backticks and then into a curly braces and we add a dollar sign here charging this way we put a variable in here and this allows us to add another one inside the string so again dollar sign charging curly braces and then we pass class name which is this property here but we must not forget to also edit up here to actually add it as an argument to the component this now allows us to pass another class name from the outside if we want to allow the color of this node to style this node then we go back to our app TSX file after saving this and now we can add this newer class name property here which is optional so we can edit or we cannot however we want and here we now want to pass the class that we defined in this notes page module.css let's take a look at it again we want to use this node class here so apts X let me move this over here so that it's easier to reach here we want to pass Styles dot note save this and then we can style this node from the notes page module so what we'd want to do is first of all we want to set all the nodes to a fixed height of 200 pixels so it looks already better in our grid we want to give them a Min width as well which means that when the screen gets very small they can't just shrink indefinitely which at a certain point looks ridiculous like this we want to set the Min width to a 150 pixels and now they can't shrink below the size I also want to add a box Shadow which I'm going to copy paste you can pause the video for a moment and type it it out by hand so add box Shadow colon and then pause the video and type out this stuff here or copy it from the GitHub repository below this adds a shadow to the hover State it's very subtle but it looks cool but we also want to add an animation so it's not so abrupt we add this to the note tag with the transition attribute and then we write box shadow the duration which is 200 milliseconds so a point to a s and then we use this ease in our animation here and now it animates to this box Shadow when we hover over a node one more thing we also want to change the mouse pointer toward this yeah this little hand icon that indicates that we can click something because later when we click a note we want to open it so we add another attribute cursor pointer and now we have this pointer cursor when we hover over a node nice but we aren't done with the CSS yet let's see what happens when the text of the note gets longer than these 200 pixels so once again into our DB just going to add some more text here this is line five this is line six line seven let's add another empty line line nine that's a lot of lines refresh this yeah and it goes beyond the note which of course doesn't look great we will fix this on the CSS level of our single nodes so we go into the node TSX file once again and we want to add another class to the card body because this is where we have to fix this so class name will be Styles Dot card body we saved this and go into the CSS module of our node this one here and add another class for the card body I'm going to put it here just for ordering we set overflow to Hidden this removes the text that goes beyond the body but this now it doesn't really tell us that there are small text in here right so I want to add some nice effect which we do the following way mask image colon linear gradient and in here we can yet specify a gradient 180 deg for degree the color will be a hashtag zero zero zero that may be black but with a 60 gradient to it comma and then we write transparent which creates this gradient effect here when we save it as you can see now this kind of indicates that there's more text below it I just like this effect this way we can give each note the same height but still not just cut off the text in this ugly way next I want to add the timestamp here at the bottom of each note so let's go into the node TSX file once again and here I want to add a card photo below card text we add another tag cards.folder and in here we want to see the created add timestamp for now okay this doesn't look great yet because this is actually the wrong place we have to put it below the body here okay the first one doesn't have a timestamp yet because we created it at the very beginning directly in our database also the timestamps are not formatted yet so it's not really readable and we also want to show the updated timestamp if the note has been updated so we still have to make some changes the first change is adding another class to the footer which again is a class from the bootstrap Library which is called like this text muted it just makes the text a bit more gray again we could do this ourselves in our CSS module but there's no reason to not use bootstraps predefined classes for that next I want to format the timestamp properly but I don't want to do this directly in this component because that's not really a good separation of concerns and we might want to use this in a different place again later so let's create another folder for that and our front end folder in Source we create a utils folder for all kinds of utility functions let's add another file in here which recall format date dot TS a normal typescript file and in here we export one single function with the same name format date it will take one argument which is the date and form of a string so let's call it date string of type string and it will return a string we don't have to declare the return type in typescript but I like to do this because it gives us a bit more safety because now this will not compile until we return a string from this function and here we want to return our date but in a nice format and again I found out how to do this through Google and stack overflow return new date we initialize this date with the date string that we pass and then we can format it with DOT tool locale string this one here and to this we can pass some configuration the first piece is a string like this e n minus u s the U.S in uppercase which if I remember correctly formats this refer you as styling there are also other languages Chinese for example but in most situations you want to use the US styling comma and I put this in the new line take a look at the exact syntax I'm using here because that's important the first argument is a string the second document is a JavaScript object with two curly braces and here we can do a further configuration of how we want to style this date stream until you just have to follow along we Define year as a string and we are set it to a numeric we set month to short and those are just the different options we have to display the date for example a year with just the last two digits or all four the long name of a month or the short one this is just the combination I found looks good day numeric our numeric minute numeric and we don't need seconds here so this is fine now we can use this function in our node component but we want to display either the created timestamp or the updated timestamp depending on which one is newer so let's put this logic here inside the body of this component above the return statement we create a LED created updated text of type string if there should not be a comma by the semicolon below we check if updated ad is created and created at which means that the note has been updated because when we create a new node updated add and created it will have the same value when we updated node updated it will be a greater so if updated ad is greater we want to show the updated timestamp so with that created updated text tool updated colon and then the formatted date string so we call our format date function and paste the updated add timestamp if updated add is not greater so in the else block we want to set created updated text tool created colon and the formatted created at timestamp now remember that whatever we put inside this component body without a use effect will be executed on every render this is okay because format date is a cheap operation we can afford to execute this on every render but if this was more expensive you should use something either a use effect or something else called us memo which you can read up in the documentation which is basically a holder for this expensive operations but cheap simple operations that are very fast can be done directly in the body of a component just be aware that this gets executed on every single render okay and then down here we don't want to display created yet we want to display our formatted created updated text and when we save this it now looks much better again the first one has an invalid date but later we will not add any new nodes with invalid dates so we don't really have to take care of this case because it's just in our development setup here but let's try updating a note to see if the timestamp changes properly I want to update node three which has this ID here let's do it over Postman so it's actually recognized as an update we do a patch request to the notes endpoint to denote with this idea we keep the title as node 3. and there this is an updated note body send this update it went through refresh this and now we see our updated timestamp because now the updated timestamp is greater than the created timestamp really nice our notes already look pretty cool the layout is responsive the next step is to add a way to add nodes through our front end rather than having to do this via Postman all the time okay so let's do that next okay so we want to add a way to add new nodes through our front end and we already have all the endpoints on our server in place for that for creating reading updating and deleting notes and now we just need some kind of form in our react app where we can enter a new node's title and text and send them to our server first of all let's organize our fetch code a bit better so when our ftsx file we have our fetch call at the moment where we get our existing notes from the server and I like to put this low level code into a separate file for better organization so that we don't have these endpoint strings and this method get in our react components but rather a clean function that we can call so what we do is we go into our source folder in the front-end folder right here right click and create a new folder which I'm gonna call Network and in here we create a new file which recall notes underscore API dot TS not TSX it's not a react component it's just a normal typescript file and you can give this any name you want but I think this won't make sense and in here I want to move the fetch curl from our get request here but there's also another problem this code has right now by default server responses like 400 and 500 which mean that something went wrong are not handled as Errors By The fetch call so they don't end up in the sketch block here but they should because these status codes mean that something went wrong and in this case we want to show an error in the UI because we don't have any real data to work with so we have to do this ourselves if we get these status codes from the server we have to throw an error ourselves but to see the problem let's just throw an error from our get nodes endpoint here so in our backend code let's just throw a create HTTP error with 401 for example it doesn't really matter I will remove this in a moment this is just for presentation and now when we try to access our front end through localhost we don't see an alert that we are normally do in our catch block here instead we just see an arrow in the console notes map is not a function which happens because we don't actually get an array of notes back since we throw this error in our server here I don't know what we get back now undefined I guess and our react app can't work with that but the correct way to handle this is to actually throw an error when we get an error response like 401 but again we have to do this ourselves first of all let's get rid of this error code here then we go into our notes API file again and what we want to do is we want to create a wrapper around fetch a wrapper that uses fetch but throws an error if the status code is 400 or 500 so we create an async function we don't have to export it because we will only use it within this nodes API file and I'm gonna call it fetch data which is similar to fetch but it's our own function you could also call it Fetch with error I guess but I like this name this will take the same arguments as the fetch function itself so when we look into fetch here we can see that it takes an input request in four and an optional init request in it so let's add the same arguments here input column of type request info and an optional init of type request in it this way we can call this function like the normal fetch function so the next line is const response equals a weight fetch so we execute the fetch color itself where we just pass the input and the init that repairs to the fetch data function and then we do a check if response dot okay which is this property on the return type of the normal fetch Carl andresponse dot OK will return true if the response is between 200 and 300. if it's between 400 and 500 this will return false so only if the response HTTP code is okay we want to return the response else we want to throw an error so that we end up in our catch block now our errors also have a Json body right when we look into the backend appts file we set up our error Handler in a way that the error gets sent back through the Json body so let's read this here so that we can lock it and also maybe display it in the UI depending on the error so we create a const error body which we get with a weight response.json the normal way like we also get a real body out of the response const error message equals error body Dot error why error because this is the key we set on this Json body here so those have to be the same and then we want to throw an arrow and for the message we will just pass the error message here now later we will get back to this function and distinguish between different kind of error codes and through different errors which we can then handle differently in our UI depending on the type of error but for now this is sufficient now let's put our fetch note skull in here So Below we write export async function because we want to use this one from the outside and let's call it fetch notes it doesn't take any arguments but it will return a promise of type node array now adding this return type here is optional but I like to edit because this makes sure that we are actually return the correct value from here and not mess anything up when we change the code later and all async functions have to return a promise because async is basically just syntactic sugar around promises so whenever you create a function that is async and return something the return type is automatically wrapped into a promise and then we want to take the code from over here these two lines cut them out and paste them in here just with a little change we don't want to store the Json body in a variable we want to return it we want to call fetch data instead of the normal fetch so that 400 and 500 responses are treated as arrows and we have to import a note type here so let's just use autocompletion and it should add this import statement let's save this go back into our ftsx file and call our newer shiny function here instead so first of all I want to import our notes API file and I import it manually because I want to import it in a special way I don't want to import each function separately I want to add them to a namespace so we do the star asterisk symbol write s nodes API from and the folder is dot slash network and the notes API file and now here we can write coins notes equals await notes API Dot fetchnotes and now we have this clean function that we can call here and we hide the low level fetch code here inside this separate file I just think this looks better and it keeps these components clean but let's see if our error now works properly so I go into our endpoint again and I add this Arrow here once again which of course I will remove in a moment let's open our page here again refresh it and now we get our alert message here which we do in the catch block because now 401 and also 500 responses throw errors and end up at the correct place now let's also add a function to a create a new node which we put into our notes API file as well let's create an export async function create note and this of course has to take input the node title and the text now we could put this as separate string arguments in here but I actually want to create an interface for that because we use the same types later in our form and this way we don't have to repeat title and text again all the time and when we make changes we have one single place to change it so we put an export interface in here export because we want to use this from a different file later let's call it node input and every node needs us a title in form of a string and the optional body text which is a string as well and then we can use this type here as the input parameter like this this will also return something I promise because it's an async function and it will return the note we created when this was successful so a promise of type node so we create a const response equals await fetch data not fetch but fetch data the endpoint where we create new nodes which is the same for getting nodes so slash API slash nodes comma and I put a configuration into a separate file because this will be a bit longer so we add a pair of curly braces the method this time of course is post and we have to add some headers to our request to indicate what kind of data we are sending so we write headers colon add a pair of curly braces then we add a string as the key and the spelling has to be correct otherwise it will not recognize this header content type like this with the same casing colon and the content type will be application slash Json this just helps the back end what kind of format our body is in of course we are sending a Json going to add a trailing comma here we don't have to but again I like trailing commas and then we want to pass the body itself and since we can only send string back and forth between our server and our front end we are one a stringifier the node that we pass here so we write Json in our uppercase Dot stringify and pass our node then I'm going to put the semicolon here because we are not Savages okay and if this went successful in which case it didn't throw then we can just return response.json which should contain the newly created note which we can then put into our UI okay and now we want to add some kind of form to input new nodes and send them to our backend and for this we will use bootstrap models which are these dialogues here that we can open and we will create such a model with some form input in it I think it's just a quick way to insert new nodes so let's go into our front-end folder and create a new file in our components folder right in here let's call it add note dialog and this one is a TSX file again and I said the second time we create a react component we want to use an extension for that so we click here on this extensions tab and I think we should find it when we search for react or react Snippets actually should be this one here this gives us these different shortcuts we can use to create stuff like components and your state and stuff like that so let's install this but of course you don't have to if you don't want you can also just keep typing them out manually like a peasant okay and now we can just type sfc which creates this functional react component going to paste the name here and then we have the return statement and the export and everything let's start by creating a minimal version of this dialog just to see how we can show it in the UI so between return we add a modal tag from the react bootstrap package close this and here in the opening text before the closing angle bracket we press show this has the same effect as passing shower equals true like this whenever you want to pass through you can also just pass the name of the property then in between these tags we add a modal.header where we add the close button to the tag to add this little X in the top right corner where we can close this model later and in between here we add the model.title when this tag is just responsible for formatting the title properly with the correct text size and everything and the title will be a add note let's keep it like that for now and display this model from our app TSX file and the way this works is that we need a state that tells us if the model should be shown or not and the little animation for opening and closing this all happens automatically we just need to 10 react if it should be shown or not so below our notes State here we create another state the same way we call the variable show at node dialog and the zeta function will be a set show at node dialog in camera case and we initialize this with us State faults and again typescript can infer the type because we pass false which is a Boolean so it knows that this variable here is a Boolean and then we can just add this dialog like every other piece of UI into our return statement here where we draw the UI on the screen we do this within the container block because it needs some text on the outside can be a container can be a div doesn't matter then we add a pair of curly braces and now we can do a little yeah react syntax that might look a bit weird at first but this is how you can draw UI components conditionally on the screen we take the name of our state show add notes dialog and add two embossance which means that whatever we put after that will only be a drawn on the screen if show at no dialog is true if it falls it will not be drawn and here we add our add node dialog which right now it doesn't take any arguments but let's try it out first of all I still have the 401 array of course we have to remove this then since we don't have a button to show our dialog yet let's initialize this withdrawal just to see our dialogue here on the screen and there it is right now we can't close it because we don't have a way to set show at node dialog to false yet but you can already see that this is displayed on the screen here let's set this back to false we will show this later when we click our add new note button and I want to mention something instead of writing it like this with this variable down here we could have also passed this variable as a property and used it as the value for this show property here so then we could remove this part here with the two ampersands and pass show as node dialog as a property the reason I do it like this is because when we do it the other way then any input in this dialog will be maintained after we close the dialog so let's say we type in a title and a text and we close the dialog and open it again the title and the text will still be there because this date is contained in this dialog component depending on your situation this might be what you need but in our case I want to clear the whole form whenever we close the dialog because if you will try to enter a node and close the dialog I assume that you will change your mind and you don't want to store the input that's right I write the syntax like this since this will completely remove this component from the screen the state inside this component is also lost just as a little explanation why we write it this way and don't use this show property here instead we hardcore show to true and handle showing or not showing from the outside like this now let's actually go ahead and add the button that can open this dialog so we don't have to hard code the state here to true so what we do is inside this container here above our node grid we add a button which was a add new note the button gets an on click attribute where we pass an error function like this and this will call set show at node dialog and set this to true this way we display our dialog then we save this we go into our dialog and we add an interface because we want to pass some data here interface add note dialog props we want to add a way to a close the dialog now when we click outside of the dialog or we click the close button all of this will be detected inside here we just have to pass it to The Carling component to tell okay change the state back to a z show dialog false and we do this via a callback this might be confusing at first but this is just how you do it in declarative UI if you've been coding with jetpack compose on Android for example then it works similarly with these callbacks on dismiss is a function that doesn't take any arguments and it doesn't return anything so write it like this added here as the actual argument on dismiss we destructured this as we have done before and use our add no dialog props type here and then on this model tag we have this on height callback which will be a cult whenever we do an action that closes the dialog this includes clicking outside of the dialog but also clicking this close button for example and here we just want to forward to our on dismissed callback and since this doesn't take any argument we can just pass the function as a reference directly by its name and we don't have to pass an error function we could also write it like this this would have the same effect but since this doesn't take any arguments this is basically a shorthand for the same thing we save this and now of course we have to pass this new property to our dialog here so we pass on dismiss which this time again is an error function because we want to call such show at notes dialog and set us back to files so let's try this out we open our page again and The Styling is not great at the moment we will fix this later but our button is still and we can use it to open our dialog so this sets the shower dialog state to true and when we click the close button or we click outside it sets the state back to false and this is how you show a model dialogues in declarative UI now let's finish our add note dialog and for forms we also have bootstrap components that we can use they just look a bit better than the usual HTML forms you have they look like this of course you can change the styling if you want but yeah you can do a lot with them okay so let's add these form components to our add node dialog we go below the model header and I like to put a space in here the space has nothing to do with how the motor looks later it's just in our code and we add the modal body for the main part and in here we want to put a form and we use the form from the react bootstrap package and then we create our form like this and I've pulled it into a split screen again so we can see how this form comes into a reality so we need a form dot group and again I know all of this from the bootstrap documentation the idea explain how you have to structure this the form group will take a class from the bootstrap Library which is called mb-3 this just adds some margin at the bottom of each input field in here inside the form group we add a form label which we call Title okay so that's the first piece of form on the screen below the form label we add a form dot control which is the actual input itself this takes a self-closing tag because everything that we pass to this component is a property when we save this we already see the input field but we have to Define some configuration here this is the same for react forms but also normal HTML forms we have to give it a type which we set to text this just helps the browser know what kind of input this input field expects for password for example we will later set the type to password which automatically hides the characters we can add a placeholder set this to title which adds this additional little text Insider field that is only there until we insert some text that's it for this input field for now we will later add some more stuff but not right now instead We'll add another form group below the first one this will take the body of the node the text itself again it takes a class name mbr3 it gets a label which was a text and we add another form control this time we don't set the type to text instead we do this we write ask equals text area but as a string like this which creates this larger input field where we can change the size of it this is just another type of HTML input we can also Define the rows number which sets the default the size of this input field so by default this has a size of five lines basically again we set the placeholder to text and that's it for this component for now the last thing we need is a button to submit this form right and I want to have this button in the folder of the model it's just a better look in my opinion Zorb below the modal body we create a model footer and in here we put a button that was a safe or submit or whatever you want and this button takes some properties as well we want to set the type of the button to submit and this is not an arbitrary string this has a special effect if we put this button inside the form here inside this form tags then submit tells the browser that this button is supposed to send this data so it has an effect when we click it automatically without us having to add an on click listener this is the property that tells HTML components that this button is responsible for sending the form but since we put this button into this footer here it's disconnected from the form as you can see it's outside of it this way the browser doesn't know anymore that these two are connected but we can fix this with another property with the form property we can add an ID here let's say add node form and then we can set the exact same ID on the form itself this way the browser knows that these two are connected so we set an ID here and it has to be spelled exactly like down here at node form now this button is connected to this form right now this won't do anything because we still have to Define what happens when we submit a form but now these two are connected I think when we click it by default the page will refresh this is how this behaves by default but we will change this in a moment now handling forms manually especially in react can be a bit trickier because you have to synchronize it with the state you have to handle different error States and so on and also you don't want to retract a UI too often when your insert some new text this is why you usually want to use a package for that which handles the form stuff and the most popular one for react is react hook form there's also another one called formic which hasn't gotten any new updates in almost two years I think so this is the one you want to use it's really good again you can read the documentation if you want but I will show you how this works so as usual we open the command line and we go into our front end command line here stop the execution for a moment and install react hook form then let's start our server again close the terminal and then let's finish our add note dialog by using react hook form first of all we add another property that we pass to this form we also need a callback when a note was saved successfully because then we want to add it to the UI we want to add it to our list here so we add another callback called on node saved which is also a function but this time the function takes an argument so we write node colon which is the name of the argument and the type of the argument is node in uppercase but it won't return anything and then we add the second card back here as the argument to our component then to use react talk form and here we go above the return statement and there is a special hook we can use this hook returns different kind of data and functions that we then use in our form so we have to destructure this single barrier boots by creating a const adding a pair of curly braces and then we list them in here before we do that let's go behind it and write use form which is the name of the hook so it adds another import statement and we have to give this a type which is the input type of our form here and this is why I created this node input interface in our nodes API file earlier and exported it there because now we can reuse it here and this is a functions that we have to call it and now we should have Auto completion in here I think so yeah the first one is called register you will see what we use this for in a moment the second we need is handle submit and then we need the form state which we want to further destructure which we do like this colon another pair of curly braces this just is the beauty of JavaScript syntax and in here we have an arrows field comma and this is submitting callback this one okay that's a lot of stuff to add but just type it out like I did here then below we create a function that actually handles submitting a node and calling our API endpoint so it's an async function because we do our async request and we call it on submit which is a naming convention for whenever you do something in response to submitting a form you can also call this whatever you want it will take input in form of our node input type then we add a try catch block here because we do our back end request which can always go wrong we lock the arrow in case there is one and we use another alert now in a real app you can use a more beautiful UI elements than an alert dialog because it's a bit disruptive and we will actually do this later in a different place but for this here this is sufficient okay when we create a note we will get the created node back as a response so we create a const colored note response a weight notes API which of course we have to import here import Star as nodes API from dot dot Network this is just write an error where where the location of the package itself is we already have one up here but with the syntax we can't combine the two we can't cut this out and put it in front of these curly braces okay so await notes API dot create node where we forward the input which is the title and the text okay so on and if this succeeded we want to cut our unknown saved callback and paste the note response toward the color of this component which right now is the ftsx file this represents the successfully created nodes there and we can add it to the UI the next step is to go into our form tag here again and add a second property to it which will be on submit as the name implies this is called when this form is submitted which happens when we press our submit button because it's connected to the form right and in here we want to use this handle submit function that we get from the use form hook sounds a bit complicated at first but those are just steps you have to learn because it works the same way every single time so in here we want to call handle submit and pass an argument to it which is our own on submit function so this is a bit weird syntax but this connects the form to the react hook form package so on submit is the Callback when this form is submitted entry pass handle submit which hence the inputs to a react hook form first which then does some stuff behind the scenes and cuts hour on submit function which executes this part here so pay attention to the syntax seal even though we have parentheses and calders this is not an error function so we do not write it like this we write it like this why because this gets called at initialization not when we click submit I guess it creates some return value that it then uses in here I don't know how this exactly Works under the hood but this is the syntax you have to use okay and the way we connect each form input to a react hook form looks also a bit weird but again this is how it's supposed to be done we add a pair of curly braces here inside this form control component then we do a three dots which means that whatever comes after it gets destructured into its single components so we add one thing here which is this register car but this basically gets separated into a many different properties that I get added to this component to the phone control this is what the syntax here means it takes register and it separates them into its single pieces basically register is a function that takes arguments the first argument is the name of this input field which has to be one of the properties that are contained in our node input here that we used in use form so node input contains a title and a text and auto completion already tells us that we have to use one of them down here because this is what connects this input field to this value and react hook form later knows that when we submit this this is the tidal value that it will send to our onsubmit function here again it's a bit complicated at first but this is how HTML forms work and react the second argument to register after the string is some configuration we can pass in form of a JavaScript object so we add a pair of curly braces in here you can for example set up form validation for example you can use this required key and pass a string here for example required the string is what will later be shown in the UI if we try to submit this without input by adding this required property in our form control for the text we won't use required because this one is optional so here again we are at register like this and just pass the name which this time is the text okay but for our required field we also want to have some feedback right we want to have this little red text below the input field that prints this required text so inside the form group we add another component which is called form.control.feetback and this gets a property as input which we said to invalid there are two types of feedback valid one which is the screen text when something when successful and invalid which is this red text and in here we want to get the error message where do we get it from we get it from this errors property of use form so to use a variable in here we add another pair of curly braces and we pass arrows Dot and we get Auto completion for our two input fields title and this error is undefined if there is no error so if you didn't try to submit empty input so we have to add the save call Operator here which is this question mark and then the dots behind it which means that we will use this message where you hear only if title is not undefined or null and otherwise this will return undefined and we use this message property here which contains the error message itself which is this piece here okay but we only want to show this input if there's an actual error for the title right we handle this with another property on the form control this one is cut is invalid and we have to set this to a Boolean we want to show the error down here only if there is an error for the title right remember this is possibly undefined only if it's there we want to show this piece down here so what we do is we write two exclamation marks which takes a value like our Title Here which is of type field error or undefined and turns it into a Boolean true or false so when we write arrows.title if the title arrow is undefined this will resolve to false if the error title contains a value this will be resolve to true this is why we use this for this invalid property here so invalid will be true if there is an error for the title and if not it will resolve to false and it will hide this piece down here react hook form can also do more sophisticated validation than just this it can also recognize certain patterns like email addresses we will not use that here you can read the documentation if you want to get more into it but I just also want to note that front-end validation does not replace backend validation because whatever we enforce on the front end can always be circumvented for example by sending a request with Postman to the back end instead of using our neat forms here this is why it's important to have the validation on the back end as well like we have in our notes controller and all these different places where we check if the required fields are actually present so this is just for better user experience but whenever something is important and has to be taken care of then you have to do it in the back end also this is pretty where both you will later extract this stuff into reusable foam components so we don't have to repeat this over and over again but for now this is fine okay and there's one more property up here that we haven't used yet and that's this is submitting Boolean I want to use this in the button down here I want to disable the button as long as the form is submitting so that we can't click it tries right we don't want to submit the phone twice accidentally so we can add a disabled attribute to this button and set it to this is submitting Boolean so as long as the form is submitting this button will be disabled okay let's save everything but now let's try it out and we still have an arrow here because we haven't passed the unknown saved callback here yet let's do that now but let's keep it empty for now I just want to try it out quickly and then we'll take care of this so we pass an empty function here save this and now beer should be able to send a new note to our back end so note from react front end this is amazing let's try it out when we send this the dialogue will stay opened because we haven't taken care of closing it yet but the save button should be a great out and disabled for a short moment it will be very fast because we are on localhost and we don't have to send the data through the internet but it might be visible for a short moment and yeah it was visible for a very short moment so let's take a look into our database and let's see if the new node is still and there it is not from react front end really nice so this is our first note we created through our own website instead of Postman now let's finish up the dialog let's hide the dialog after we have sent the note and let's also add a note to the UI here because right now we have to refresh the page before we sealed and actually just realized that I wouldn't have had to look into the mongodb database because we can see it right here but now we want to make it so that the node appears immediately and we don't have to refresh the page first so the first thing we do here inside the skull back is we set show add notes dialog back to false so the dialog disappears and we also want to add this node to the UI this is why we have this function block instead of just one line we want to add more stuff here we already know how we update our state right we have to use the set node scale here and update it with the newer nodes array but we don't get the whole array sent back from our backend we just get our new node so what we do is we call that nodes we pass an array here with scrap brackets and then we write dot dot dot nodes what this does is it creates a new array and it adds the nodes that are already in our node State into this array so all the single nodes that we already have on the screen are added to this new array and then we want to add our new node to it the new node is the argument that we get passed from this one node saved callback remember we declared it up here and here when we call on our saved we pass our node response so we can add the name for the variable here we can give it any name we want and this is the node model that we are pass when we are called this function so after the comma down here we pass our newer node so to recap this creates a new array it adds all the existing notes to it and it also adds the new node to it which will then be displayed in the UI Zoom let's make this bigger and let's try adding another note this is a newer react node blah blah when we save this the dialog should close and we should see our new node on the screen but first of all let's try the input validation so when we try to save this we see our required text when we type in something the required text disappears this is really cool it's actually try sending a note without the text this should work and we save it and it is added to the UI nice or just one more thing I want to show you what I mentioned earlier when I type something in here and I close the dialog and open it again the next time the input is gone this is by Design This is how I wanted it this is why I handle the dialog like this as I explained earlier if you want to keep the input you can use the show property here like I explained earlier and now I wanna add some margin to the bottom of this button and Center it on the screen so we add a class name to the button and again we have this class that we can use from bootstrap which is called mb4 which adds a little bit of margin here at the bottom but we still want to send that is on the screen so now we could add the class to this button and put the CSS code in the notes page module CSS file but for a certain kind of CSS attributes that I use over and over again I like to create utility classes that I put into a separate CSS file so let's do that now let's open the sites bar and add another file to the Styles folder which we call utils.module.css this contains a reusable utility classes and I'm gonna cut this one block Center I've actually not seen this name anywhere else used but it makes sense to me because here I want to use two attributes display block and March and left Auto and margin right Auto these attributes together will display whatever we use this class on yeah in a way that it is centered on the screen because margin Auto does this it sets the margins ordered as an equal amount of either side so let's save this copy the class name and use it in our app TSX file so let's duplicate this line and we can do this with shift ielt and pressing the down key or just type it out again we call this style utils and we import this due to its module.css and then we can use it on our button now we do the same trick as before since we already use this bootstrap class we replace this for a pair of curly braces a string with back ticks use mb4 in here and add our other class as a variable so style your tits block Center which now centers this button on the screen and you can reuse this block Center class in other places if you want so the layout is still not finished completely we still need some room here at the top but we will do this later when we add our navbar and also we don't have any loading or error or empty States yet so right now when we load nodes from the back end it's very fast because we are on localhost but when we do it over the actual internet it may take half a second or so that's why we have to add some kind of progress spinner while the nodes are loading we also want to add an error state if the nodes can't be loaded we don't just want to show the alert dialog we want to show something in the UI and it also makes sense to have a special kind of text or message that shows when there are no nodes in our database so that the screen isn't just empty it should say you haven't added any notes yet or something like that we will implement this in the rest of the video but the next step is to add a way to update existing nodes and delete them so that's what we will do next okay let's add a way to delete nodes next for this we need another function in our notes API file so let's put it here at the bottom export async function we colored delete node and it will take an argument which is the ID of the node we want to delete and in here recall a weight fetch data the delete endpoint is slash API slash notes slash and then we want to append the node idea at the end of it right because when we look into our nodes routes this is how we set up this delete endpoint so we can simply add a plus here and append the node idea which is a string anyway we don't have to work URL encoded in a special way we can just append it doesn't contain any special characters and then we add the configuration as usual where we set the method which this time is delete this function won't return anything we also don't get anything back from the endpoint but we have to await this fetch call otherwise arrows won't be propagated to the outside so the weight is important to delete a node I want to add a little a trash bin icon here to each node and for that we can install this react icons package yeah which contains ideas different icons here from different other packages that you can use so let's add this in our front-end terminal we install react icons this dash dash saved by the way is not necessary you had to add this in the past but not anymore so you can ignore this okay we start this again then we want to go into our node component the nodes that we draw on the screen so this one here the node TSX file and I want to add this icon here to the title of the note so it's right next to the title so what we can do is we can go below the title value here but within the card title tag and just add our icon but we will have to import it manually the IDE doesn't recognize it so up here we write import we restructure this and write MD delete with the same spelling the same casing from the react icons packet we just installed slash MD MD is short for material design by the way so this is the material design delete icon by Google and then we can use it down here open the anchor bracket MD delete let's close it see how it looks might have to refresh this okay we are not quite there yet first of all we add the class to the delete icon for which we use bootstrap classes again the first one is text muted we used this before this just turns the color into this grayish color which I think looks just a bit better and then after a space we also add MS Auto which adds the margin starts with the value auto to the icons which should move these icons to the right but only if the container of the title actually supports this so we have to add a class to the card title here as well class name and we will use our utility styles again which we have to import first so Style utils utils module.css and we want to add a new one there so let's go into the YouTube's module CSS and add another class which we call Flex Center which contains the following attributes display Flex which is flexbox again you can learn more about this through Googling a line item Center justify content Center and a gap of 4 pixels type out all of this let's copy the class name and add it to our node title here so the style youtubes.flex Center which applies this and this yeah send us the text and this icon properly and because we added the flexbox now this MS Auto here Works which adds the spacing to the front of the icon and moves it all the way to the right looks much better doesn't it but we actually want to do something when we click this icon we want to delete our node right so we can add an unclick attribute toward the MD delete component and here we pass a function like this and we want to do a two things we want to trigger a callback so that whoever uses this node component notes that a note was deleted with a certain idea right so what we do is we go up here to the interface the note props and we add another color back here let's call it on delete note clicked and here we will forward the whole node that we clicked so that the color can later decide what to do with this information in our case we will get the ID out of this node and then the delete request to our backend with this idea and this function won't return anything let's not forget to add it down here to the parameters and then we can color it in our on-click card back here on delete note clicked where we pass the note what's the note that's the note that we are passed through the component itself so we pass this back to the color of this node but then I also want to add a second line here later when we click a note we also want to open it so that we can update it by default our click on the delete icon will go through so it will trigger both the undelete node clicked but also our other callback later to open the node for this reason we want to add another line that swallows this click so to speak so on click actually can take an argument which is often just called ear it's this mouse event from The Click we can Define it in here or we can ignore it like we have done before this time we want to use it and we want to color something on this e variable stop propagation which this allows this click to go through so we use it upright here and our other on click Handler below this icon won't be called later again I found this all through Googling I don't put this information out of my behind I have to figure this out myself so you just Google something like don't let click through react or something along those lines and you will find these answers okay let's save this and go back to the ftsx file because now we have to pass this new callback to our node component here so let's put these arguments here into a separate lines and let's add this new card back below on delete note clicked and we could either handle it right here but since we do an API calling everything let's put it into a separate function which we will call delete node we haven't created this function yet but we will now do so above the return statement so we create an async function with the same name and it takes the note that we want to delete as import ant try catch Block in here as usual if something goes wrong we print the arrow to the console and we are open an alert dialog and in the try block we want to call await notes API our delete node function that we created earlier which expects the idea of the note we want to delete so we pass note dot underscore idea if this doesn't throw an error we stay in this try block so now we want to remove the node that we just deleted from the UI and this works similarly to how we added a new node here with the set nodes column just that we know when to filter our nodes and remove the one that we just deleted so again we call Z nodes this time we pass nodes dot filter as the name implies this allows us to take the nodes array and filter certain nodes out of it filter takes a function that takes an argument we have to give this argument a name let's call it existing node and then we make such a right arrow this filter function will go through each node of this array and pass it to this callback one by one and then we can decide what we want to do with it and we have to return a Boolean from this function true if we want to keep this note element in this array and false if we want to remove it so what we do is we write existing node take the idea and we compare to the node ID we just deleted if we know that it's the same idea then we want to remove it so we write not equal to like this with an exclamation mark and two equal signs note which is the node that we just deleted dot idea so to recap this deletes the node through our delete endpoint and then if it was successful it Fitters our existing node and removes the one with this ID we just deleted so that we update our UI and reflect the newest changes so when we save this our preview here compiles again and a short break now right let's try it out let's delete a node let's take not the last one but this one here click delete and its gun and the UI is updated and it should also now be deleted from our database so let's look into the atlas backend refresh this and there should be five notes left right node four and then this is a new react node and looks correct to me so the leading works the next step is to update notes but before we do that I also want to add a little icon to the add new note button here a little plus icon now that we already have the react icons package installed that will be really quick let's go into our button tag here and add this icon to the content of the button but we will have to import this first so let's go up here import this one is called fa plus from the font awesome package from react icons slash F A and then we can use it here if a plus with a self-closing tag and there it is now it's not aligned properly yet so we have to add another class to our button here and we can use our Flex sender utility class that we already created so let's add another class like this style utils Flex Center which aligns everything properly because it turns it into a flex box it applies the line item sender attributes and everything and the little space here in between the icon and the text is caused by this gap of 4 pixels here this is why I added this earlier okay looks pretty cool if you ask me okay now let's add the way to a update existing notes for which we need another entry in our notes API a file here let's put it between create node and delete node export async function update node which will take two arguments it will take the note ideal of the node that we want to update and denote input let's call it node where input doesn't really matter but it's of type node input so it contains the title and the text that we want to update our node with this function will return a promise of type node if everything goes successful it will return the updated nodes which we then display in our UI okay so we create a const response it creates await fetch data the usual way the update endpoint is slash API slash nodes slash and denote ideal similar to how we did it for the delete endpoint comma and configuration which we put into a new line the method will be patched this time we need the same HTTP header up here because we send Json data and the body is the same as well we then the stringified version of our node input and the line here below is the same as for create node as well we want to return the Json body of the successful response which should contain the updated node to update an existing node I actually want to reuse the add node dialog that we already created earlier we want to change the name from add note dialog to add edit nodes dialog because adding new nodes and updating existing ones looks very similar so it makes sense to reuse the existing model we already have and by the way this is why I kept the name of this onnode saved callback generic I didn't call this onnode edit because I already knew that I want to reuse this for editing notes as well so I called it safe so what we do is first of all we rename the props here I do this with the F2 shortcut or right click rename from add nodes dialog to add edit node dialog props let's also rename the component itself but this doesn't automatically change the file name so we have to do the separate layer to add edit notes dialog.tfx update Imports always automatically update Imports make sense entry might have to use this save all filets command here to save the files where this import has changed okay then we want to pass an optional argument to this add edit nodes dialog we want to pass the note to add it to it which is an optional argument of type node which is our node model the way this works is that we can pass this node to edit to it or not if we pass one then we know that we are not adding a new node we are updating an existing one if we don't pass this node to edit then we know that we are creating a new node so let's not forget to add it down here then we want to make some changes throughout this dialog here first of all we want to pass a configuration to use form which we do by adding a pair of curly braces between the parentheses of the series form color let's put this into a new line because one thing we can do in here we can Define default values like this so what we do is we set the default value of title to a node to edit save color title so this will use the title of the note we are updating if we pass this argument if not this will resolve to undefined and we can handle this case with these two vertical pipes which is a logical or this exists in most programming languages if the node to edit repairs is undefined then we want to use an empty string as the default value because then we just have our usual add node situation where we don't want to have any default values already in the input fields comma entry do the same for the text note to edit text or an empty string then in on submit we have to distinguish between the situation where we want to create a new node or update an existing one so what we do is we create a letter variable for this node response here so we write let note response which will be of type node but we don't initialize this yet because now below we want to check if not to edit which means that it's not undefined we forwarded it then we want to set node response to await notes API and make our update node color where we pass the node to edits idea and the node input right the title and the text if we don't have this node to edit idea we are in our usual create node saturation then we want to color create node and store the return value in this variable and then we just do our unknown saved callback in either case when we created a new node and when we updated an existing one just a few more changes we have to do here in our add edit notes dialog we want to change the title and make it dependent if it's an update or an ad situation so what we do is we add a pair of curly braces we check if not to edit ID has a value which we can do with this ternary operator so node to edit question mark if this value exists then the title will be edit node colon if this value does not exist we use the title add node and let's also adjust for completion update the idea of this form we could keep it at node but I'm perfectionist so let's change this to alt edit node form and not forget update here in the button component as well save this but we don't have a way to open this edit dialog yet right so next we need to catch this click on our nodes here on the Node component and then open this dialog in response to it so let's go into the notes component once again which I have to find First this one here and we want to add another card back here on node clicked let's keep the name generic let's not call it update node or something like that because this way the color can decide what they do in response to a note being clicked maybe they don't always want to open the updates dialog maybe they just want to show the text so we keep this decision to the color okay this is a function that looks exactly like the delete function here it takes the note that we clicked and forwards it to the color we could also put this edit dialog directly into this component this would work theoretically but we want to pass this card back to the outside instead because this way we keep our code more flexible and how we use these nodes this is called hoisting by the way hoisting means you're taking state or callbacks and moving them one level higher to the component that uses this component where you put State and where you handle clicks always depends on what exactly you want to do and how flexible you want your code to be okay and we want to trigger this callback when we click our node right so what we do is we are going to discard tag here and add an on-click attribute to it which takes an error function that just calls on node clicked I haven't added it here to our parameters yet so let's do this at this position we want to cut this down here and we want to forward the node that we clicked the same as we did here in the delete callback now let's wire everything together in our ftsx file this now expects the onnode click callback but first of all we need a state where we store this node ID that we clicked so let's add another state here at the top let's put it below show add node dialog because this decides if we show the edit version of our dialog so we create another state const let's call it node to edit and the setup function set in order to edit and we always have to change this to camera case which is a use State and we have to set the type of this explicitly because we initialize this with Nile so the type of this is node model or null because we use null when we don't have a node that we want to update right now this is what we also start with then we go back down to our node component which is already complaining here and adds dismissing on Note clicked callback and here we should be able to just pass the name of the setup function of our new state so Z note to edit because this is a function that gets passed a node model and Z node to edit is a function that takes a node model so if I'm not mistaken right now the syntax should work otherwise we could write it like this note right arrow and pass it here but since these functions have the same signature this should work as well but first we have to set up the second dialog so here we did show add node dialog to Amazon science below we want to do the same but this time with node to edit if this value is not null we also want to show our add edit nodes dialog just with a slightly different configuration first of all we want to pass the node to edit this time which is this one here and since we have this check up here with the embossing sign we know that oops it's not null down here because otherwise we would not get inside this block and typescript is smart enough to smartcasters it's smart enough to know that this can't be null down here so we can pass this value then we want to define the on dismiss callback like we did up here just that we don't want to sit show at no dialogue to false instead we want to set notes to edit back to another which will also hide this dialog because of this checkup here and the last thing we need is our onnote saved callback which the Sim is up here forwards as the node that reserved just that this time it's not a new node it's the updated note it's the same variable basically but we can give it a different name we can call it updated note and then Define what we want to do with it first of all we want to set note to add it back to Nile here as well to close the dialog after we save the changes and then we want to update the UI and what we want to do is we want to take the node that we updated but put the new data in there without having to refresh the page first we want to do this with the value we get returned from the API so again we call Z nodes which is our state setup function and then recall notes dot map earlier we used notes.filter to remove a node from the nodes array with nodes.map we can take each single node and transform it in some way now we want to leave most of the nodes untouched we only want to transform the one that has the ID of the node we updated to put our new data in there so nodes.map which again takes an argument which we call existing node as we did earlier when we deleted a node then we want to check if the idea of the existing node is the same as the idea of the updated note then we know that this is the one we just updated and we wanna display not the old one but the new one in the UI I have to make this a bit bigger again so what we can do is if existing node ID is the same as updated node ideal question mark in this case we want to return the updated note colon otherwise we want to return the existing node so this might look a bit complicated at first but it completely makes sense we call our Z nodes state map our existing nodes by checking for the idea for each of them and if the ID is the one we just updated then we want to display the updated note and put it into this array otherwise we want to put the same old node as we had before into this array okay let's try it out let's make this a bit smaller again and let's try updating a note so when we click this node it should set the node to edit states to the node we just clicked which opens this dialog with the edit node State and the default values already inserted let's change the title and the text updated note 3. we updated this note through our react app when we click save the save button should be disabled again for a very short moment while the update is running the changes should be saved in our database through our server and because of our map call we should see the updated state in the UI so save and after a very short moment everything works properly here's our updated note and when we refresh the screen we still see the Zim because this data is stored in our database properly somewhere here is our updated node 3. with the latest updated timestamp really cool also I don't know why the ftsx file has two spaces instead of four by default but it looks a bit cramped in my opinion so we can change the stone here indent using tabs you don't have to do this but I want to use the default tab size of four and when I format this again looks better in my opinion okay this works really nicely and the next thing we want to do is we want to put this loading and arrow State into our UI to take care of situations where something goes wrong and we also want to organize our code a bit better so that we don't put everything into our ftsx file okay so right now since we are on localhost loading notes is really fast so there's almost no delay and we see our nodes on the screen instantly when we actually deploy this to a server this will take a moment so it makes sense to add a progress bar while the nodes are loading and it also makes sense to add some text in case loading went wrong so we show something like a code and load your data right now we are just showing the alert dialog and of course that's also an option but it's a bit annoying to the user so how you display these errors in the UI is up to you if you show a dialogue or an error message embedded on the screen you can decide this yourself I just want to show you different options so what we do is we go into our ftsx file and at another state for when the notes are loading let's put it down here below the nodes state we create another state that we call nodes loading and set nodes loading for the setter and we initialize this state riff true this time because as soon as we open the page the nodes try to load right so we can set this to True white array then we add another state below which we call show notes loading error and then the setup which I'm going to copy this and change this here to camera case which we initialize with a state of false we don't want to show this right array only when something went wrong now as you can see I give this error a very specific name I prefer long variable names to be more descriptive I don't just want to call this show error because this could be any error we want to use this error specifically for when loading the nodes failed so I give it this long name and we handle all the states down here when we try to load nodes so what we do is as soon as we load nodes we set the error we are showing the error to false because we might want to add a retry button or something like that and when we retry loading the notes we want to hide the arrow if there was one right and we want to set loads loading no notes loading to true because as soon as we call this function here we start loading our nodes and only after this run we are finished we want to replace the alert dialog here in case something goes wrong and set short notes loading error to true which will contain a generic error message by the way you could also display the error you get from the back end by extracting it from this error variable I just want to show a generic error message instead it always depends on how much information you want to give to the user and then we also have to set nodes loading back to false now we want to do this in both cases when everything went well and when there was an error so we put this into the finally block try catch finally set notes loading back to false okay so now we have the state and now we use this data to display different UI elements on our page for this we will have to put some conditional Stone here into our UI that decides if we show our usual notes grid here or if we show something else now to keep this a bit organized let's put this into a variable that's something we can actually do we can cut this out go above our return statement here create a variable that's colored nodes grid and we can set it to the piece we just cut out and then we can use the stone here in the place where we had the chord before but now I want to check in between curly braces if notes loading is true then so we use these two Embers enzymes as we have done before we want to show a loading spinner which is another component from the bootstrap Library we had some configuration here we set the animation to border and the variant to primary which just sets the color and we close this with a slash and a closing angle bracket this will be shown why the notes are loading you could see this for a very short moment but we are not quite there yet the second line we add another conditional if show notes loading error is true then we want to show some little text in the UI for which we can use this paragraph HTML tag which basically adds some text with a little bit of margin below something Rand wrong no there's no apostrophe here something went wrong please refresh the page okay this will show in case there is an error you will see this in a moment and finally below we want to show the notes themselves if there was no error if the notes are not loading and if they are not empty so another pair of curly braces here we write exclamation mark notes loading if the notes are not loading anymore and exclamation mark if show notes loading error is false as well and again to emboss enzymes then we show the component itself and I actually want to add another conditional down here because I want to show a little text if the notes array is empty so what we do is we add this pair of emptier angle brackets which is a so-called fragment in react a fragment basically allows us to put more than one components or HTML tags in places where we could only put one and we need it right here because we want to add another pair of curly braces for a conditional and if we remove this fragment this will complain because the syntax is not valid you can't put curly braces into another pair of curly braces you have to use this fragment in between and here we want to check if notes dot length is greater than zero so if the nodes are not emptier then I put the next part into a separate line question mark which is a ternary operator then we want to render the notes grid and Below colon if notes that length is not greater than zero which means that our nodes array is emptier then we want to show another paragraph you don't have any notes yet and I'm really bad at spelling so to recap why not loading is true we show a spinner if there's an error we show the error message if both the loading State and the error are false then we either show the notes grid if there are nodes in the array or our empty State here now let's make some changes in our nodes controller in the back end just to see these different states you don't have to do this you can just watch the video here go into the back end and the place where we fetch our nodes first of all let's see the loading State again we still have to Zender this progress bar on the screen we will do this in a moment but let's try throwing an error here create HTTP error doesn't really matter which one we throw refresh this something went wrong refresh the pitch and let's also try returning an empty array as if we didn't have any nodes in our data set refresh this again you don't have any notes yet okay let's not forget to rewrote this and now I want to Center everything on the screen horizontally and our app TSX file now we could use our block Center class that we used here on our button but then we have to add this to each element separately so let's actually handle this in one place instead by adding a class to the whole container of our notes page so let's add a class name here styles.nodes page we haven't created this class yet we will do this in a moment and also one on our grid here we will need this in a moment so let's remember this g-4 change this again to a g-4 but also add the second one Styles dot node grid or in the closing back tick here of the string has to go here okay let's go into the notes module CSS file once again and set up these new classes here let's put it here at the top the first one is the notes pitch we want to set display to flex and flex direction to column because with flex we can use align items again and send everything yeah which puts everything below each other which should now also be the case for our spinner yeah and our error messages and everything it's all send out now the reason why I also added the second class for the node script is because if there are now only one or two nodes in our array it doesn't fill the whole width we can't see this right now because we have so many nodes but this looks weird when we have fewer nodes and we can fix this by setting the width of the node squid to 100 so this will always take up the full width it has available you can check this out by just deleting all nodes but one or two and try it without this width 100 and with it we see a difference okay now we already have a nice front end and loading States and error States and everything we are not quite done yet but the next step is to add user authentication to the app this will be very exciting because in the future users have to sign up here in our app and then every user will just see the nodes that belong to them and also only delete and update their own nodes rather than everyone being able to change every note in our database okay when a user signs up on our website of course we want to save them in our database this means we need another Mongoose schema so let's create one but first of all I'm gonna close all these tabs here because I'm losing all overview then we go into our back end folder into the models folder and we want to create another one in here which we call user.ts this will look similar to what we already did here in our note schema so rewrite const user schema equals new schema parentheses curly braces put the semicolon here and configure this every user needs a username at least in our app of course you could also just use an email address if you want of type string remember we write this type here in uppercase and with that required to true because the username is not optional and we can actually duplicate this line on Windows we can do this by holding shift and ielt and then pressing the down arrow key like this because the other two fields are similar the second property is an email also type string required Journal and a password but we want to add another setting to the email and password configuration here after required rule we want to set a select column faults for both of them so I copy this and add this to the password as well this means that when we retrieve a user from the database by default the email and the password will not be returned to us we have to request them explicitly this makes sense because if you retrieve a user for example on a public profile then you don't want to return the email address and password even though the password will be hashed but you don't want the stuff to be visible to the outside right and even if you don't show the user data in the front end it might be in the Json response you get from the server so with select faults we make sure that this is not returned by default if we just request a user from the database it will only contain the username unless we request the email and password specifically you will see how this works later so let's finish setting up our schema we create our type user for typescript equals in first schema type we have already done this before as the type parameter we passed type of in our lowercase user schema and then we add our export default model add the user as the type parameter here parentheses pass user as a string the name of the collection later comma and the user schema this is nothing new for us we've already done this in our node schema and then we save this and next we need endpoints where we interact with our user data where we can create users by designing up where we can log in Fetch user data and so on so let's create another controller for this stuff so now our controllers folder here we right click and create a users.ts file let's start with the sign up endpoint so we create an export const which we call Design up which is of course of type request Handler but when we sign up the user we have to send some data we have to send the username email and password that we just required in our user schema so let's create an interface for the sign up audio interface sign up body we need a username again all of these values here are optional because we don't know if the use of our endpoint actually sends this data so we have to be safe email of type string and a password of type string and then we add this type argument down here unknown comma unknown comma sign up body comma unknown is in typescript a beautiful language and this is of course in async function that takes a request object a response object and the next function and then we add the body as usual at the start of this callback we want to get our data out of design our body so we create a const username equals request dot body dot username the same for the email and for the password but I'm gonna call this password Raw instead of just password because for security reasons you should never store passwords in plain text in your database you need to Hash them we will see how this works in a moment and to make sure that we don't accidentally save this raw password in our database I give it this name here so this makes it very explicit and makes it less likely that we accidentally use it like the hashed password okay and the rest of this card back here happens in the try catch block let's call our error Handler down here through the next function and then take care of the try block as usual we want to do some input validation here so that we get proper error messages and not just rely on the cryptic error messages of the database so first we want to check if any of these variables here are missing so we type exclamation mark username two vertical bars for a logical or so if there's no username or if there is no email or if there is no password wrong in the request then we want to throw a create HTTP error with a status code of 400 which means bad request which is appropriate here and error message was there parameters missing and we also want to keep the usernames and emails unique so that no two users with the same name or email address can sign up and there's actually another schema attribute for that which I forgot to add earlier so let's do that now for username and email we go after the required true and by the way you can hold IELTS down and click somewhere to create a second cursor like this and now we can add another attribute to both lines at the same time let's set unique to true which as the name implies make sure that we can only ever insert a single user with the same username or email address into the database let's save this and go back to our controller as usual we don't want to rely on the error message of the database we want to insert our own check here as well so we have more control over the status code and the error message that we show to the user so let's try to retrieve the user with this username out of the database and then if there is someone we know that the username already exists so we create a const existing username and cut a weight we have to import the user model here import user model from dot dot slash models slash user then we continue down here user model dot find one which as the name implies returns us one single document if the filter fits in between parentheses we add a pair of curly braces write username colon this is the field in the user schema we are searching for and then we want to search for the username we passed here so again we write username as the value and don't forget the exec here if there is a username found we know that this username already exists So Below we do a check if existing username then we want to throw another create HTTP error with status code 409 don't remember what is meant right now I think something like a clash I looked this up before preparing the tutorial so 409 should be appropriate and an error message username already taken please choose a different one or log in instead of course you can write any error message here that you want then we want to do the same for the email address and again we could skip this because our user schema already enforces the uniqueness of the email address and username but this way we have better error messages and better status codes below let's do the same again for the email we create a const existing email awaits user model dot find one email colon email exec then we check if existing email we want to throw another error again 409 the user with this email address already exists please log in instead nice so if we get to the point here below then this user doesn't exist yet and we can go ahead and save it in the database now as I already said we don't want to save the raw password in the database because even though your database is locked by a password usually there can always be something bad happening and your database leaks and then you don't want to leak the raw passwords of audio users so instead as a process called hashing which basically turns this password into an unreadable string of characters you can Google the exact mechanism behind it but it makes it so that even if the database leaks no one really can do anything with the passwords of course there's a package we can use for that which is called B Crypt it's a very popular one so let's see D into our backend folder and run npm install bcrypt which is spelled like this and we also need a type package for it so we type npm IR -d for Dev dependencies add types slash bcrypt like this and install it as well okay and then we can go ahead close this and save our user here so we create a const for the hashed password I'm going to call it password hashed equals then we use bcrip to Hash our raw password and this is an asynchronous operations area write a rate bcrypt dot hash which is a function but we have to import bcrypt first so up here import B Crypt from the bcrypt package the first argument is the raw password and the second argument is the resulting rounds salting is another security mechanism to make it harder to a reverse engineer these hash passwords because there is actually a way to figure out a real password from a hashed one if it's a commonly used one through something called rainbow tables and sorting is another security mechanism that makes this yeah impossible basically so if you write it like this then your passwords will be saved and then we can save this data as a new user in the database so let's create a cons new user because after signing up successfully we want to return the user to the front end immediately equates await user model dot create parentheses calibrases we store the username that we are sent to the endpoint we store the email as it is and we store our password hashed not a raw one and then Ria sent a status back with the code 201 and the Json body will contain this newer user we just created next we have to set up the route to this controller right so we create another file in our roads folder which we also call users.ts so we need a router here so first we import Express from the Express package we also want to import our user controller import Star as user controller from dot dot slash controllers slash users and then we create a router constrada equals Express dot router and then below we create our first endpoint for our users controller which will be a post request because present data to our sign up endpoint the URL is slash design up and we want to forward this to user controller DOT sign up don't forget to add a default export below export this router save this and then we have to register this new route in our app TS file so let's go over there the same as we did for our notes routes we need our user roads so import user routes from routes slash users and then we added down here either above or below it doesn't really matter put it above app.use slash API slash users comma and our user routes okay and now we should be able to reach our sign up endpoint since we don't have a sign up form yet let's try it out in Postman first so we want to do a request to our server slash API slash users slash sign up and we have to pass a body here because if we try to send it like this it saves parameters missing which is our own error message we set up so we need a username gonna give it my name needs an email address let's set this to a Florian at test.com and we need a password I use my favorite password which is one two three four five let's send this and see what happens okay so it looks like we got the user back this is our hashed password Here by the way let's also take a look into the database so we have our new users collection again this takes the name of the schema which is user and pluralizes it and our data is in here this is our hashed and soldered password now let's try signing up with the same email or username again which shows us our error message here let's also see if the unique key actually works by removing our own error for a moment so let's remove these checks for existing email and existing username just for a moment I'm going to comment this out save this try this again this should still not work an unknown error occurred and in our logs we should see our mongodb error here duplicate key error collection this is what we want to see so this is basically a fallback security mechanism that happens because we are that is unique key is here in our user schema so let's just go to have these two lines of defenses because of course we can always mess up our own server code here so it's good if the database itself also enforces this constraint and of course if we use a different username by the same email address we should still see an error here a user with this email address already exists please log in instead nice and we will later show this error message in our front end in our react app but of course inserting the user in the database is not enough we also have to keep the user locked in somehow right and we want to do this right after a user signs up because why should they insert their login credentials again if they just enter their own password for user authentication we will use sessions through this Express session package here there are basically two popular ways of keeping a user logged in either sessions or JWT tokens JWT tokens are used in a lot of tutorials but they are actually quite hard to use because JWT tokens are self-contained which means that once a user has it they can always log in with it there is no way to invalidate an existing JWT token but in validating a session after user signed in is important for example when they want to change their password then they should be locked out in all the other places right because maybe their password has been compromised this is a problem that this self-contained token spring and the usual way to handle this is to keep these tokens will be short-lived usually one hour and then they have to be refreshed before they can be used again this way when you change the password then the user Can Only log in for the rest of that hour until the token expires but then you also have to implement a refresher mechanism which can be quite complicated or another way to handle this is to keep the tokens long-lived but Implement some information in your database some kind of Blacklist where you enter tokens that have been expired but then you're basically just rebuilding sessions in a sub-optimal way what you must not do is giving a user a token that lives for like a week or a month and then you have no way to invalidate it that's a security issue but if you have your own server that can store data then I actually prefer just using sessions because they are much easier to use possession works so that a user has some kind of key stored in a cookie and there is a corresponding entry in your own database on your server for each session and then when you need to invalidate the sessions for a particular user then it's just a matter of deleting this database entry and that's it these session cookies are not self-contained as opposed to what JWT tokens so yeah this is in my opinion much easier to implement you will see how easy this is in a moment let's install this package now so we need this install command here go into our terminal cancel the execution for the back end for a moment and install Express session here we also need the types for Express session again so npm IO Dash Dio add types slash Express session install this as well and we need one more thing our session information has to be stored somewhere and there are different adapters that you can use for that they are listed somewhere down here there are different ones we are going to use the mongodb one so we store the session in our existing Atlas mongodb should be this one here connect Bongo in a real app I actually recommend that you use something like Reddit because our mongodb database is a remote database it's not on our server directly and it's on atlas's server right this means that it takes a moment to store this information in the database if you want something that's really fast you can just install a radius database on your own server and then this is just a bit faster but setting up Reddit for development is a bit complicated so for the ease of this tutorial we will just use the mongodb one because we already have this database set up and you can also use connect in your production app you don't have to use the Reddit one it's just a little bit faster so this is also an npm package and we want to install this here as well npm install connect Mongol let's do that and then let's start the server again because we have installed all dependencies we need for now and then when a user has signed up successfully before we return the response we want to establish the session and this is really easy with this package we just take our request object on which we now have the session keyer and here we can store some data and what do we want to store we want to store the ID of the user that just signed up because this way we can identify a user so we store this user ID property here and we set it to the ID of the new user we just created right so underscore idea in normal JavaScript this would be enough but as usual typescript complaints because it doesn't know about this user ID field here on the session object because we decide ourselves how this is called so we have to do a little bit of extra configuration what we need to do is we need to create another folder here in our backend folder not in that Source but right at the root folder because this is not our normal source code which we call it types and in here we can put stuff like our own type definitions that we sometimes need and again I figure this out through a Google and documentation you always find these Solutions in Google somewhere and here we put a new file which we call session dot deal dot TS and these DTS files are these type definition files which help typescript recognize variables and stuff like that and whenever we install these add types slash packages then we are installing DTS files basically just that they are residing inside the node modules folder okay and here we will need Mongoose because we want to store the object idea which is a mongoose type so we import Mongoose from mongoose and then below we write declare module the same name that this package has where we want to add this type tool so this is Express session curly braces and now we can basically add our user ID variable to the existing Express session type by writing interface in here we call it session data and you have to use this exact name because this is how the type on Express session is called then we add another pair of curly braces and now we can add our user ID field by declaring its type so Mongoose dot types dot object idea so that's it for this file we have to make a little change to our TS config file as well so that this is actually used here because otherwise this will not work properly so we go into the TS config file and we search for the key called type Roots which is down here we uncomment this here we tell typescript where the type definitions are by default this should point to node modules types but now that we set this explicitly we have to enter this ourselves so in here we put a string node underscore modules slash add types comma and then we end the second one which is our own types folder now so we just type add types which points to this one here we just created and this now tells typescripts that it can find type definitions in both places the node modules folder which are the ones that we installed and our own one and one more thing we have to add all the way at the bottom because this happens outside of this closing curly brace here so there should be two closing curly braces down here we go before the last one at the comma and adds this TS node key which is necessary for TS node to recognize these types remember TS node is what we use to automatically restart our server in development whenever we save the changes and here we add the silence key and that is the true and again I found this through a stack Overflow because the session key didn't work then I looked this up and then you find all these necessary steps there okay we save this let's not forget to save the changes to our users controller and then we have to go into the FTS file once again because we still have to configure our Express session package here but this is just a little bit of code and then we can use our sessions throughout our whole server the Press session is another middleware that we have to register here but the place is important we want to register them before our routes but after we read the Json body so right here we write app.use and here we want to call session okay Auto Import doesn't work so we have to import it manually import session from Express session which is a function that we can call and add a pair of curly braces to do a configuration in here the first thing we have to set is a secret this liquid is used to assign the cookie that the user receives so this is basically their key to identify their own user session so each session has an entry in the database but also a cookie with a secret key is stored on the side of the user in their browser there should be a random string now as usual we don't want to hard code sensitive data right into our code we want to put it into the nth file so we open our backend and file and add another entry in here which requires session secret the name is up to you and then we just set this to a random string you can type in whatever you want just don't use any reserved characters this should suffice but this has to be an equal sign not a column I always mix this up okay and we also need to add this to our sanitized and file right remember we have this validate and f file here where we want to registered this new key as well so that we make sure that we actually have this available at runtime this is a string let's go back into the app TS file and import our validate and Theorem so import enf R from dot slash uter slash validate INF o and then down here for the secret we pass nth dot session Secret then we set Reserve to false entry that save uninitialized to false as well this is some configuration that is necessary that I don't want to explain here you can hover over this or look into the documentation and it tells you what this means it's just not important here then we need to configure the cookie that will be stored on the user's browser so cookie colon curly braces entry set the max Edge how long this cookie lives this is up to you again you can make this long lift because we can invalidate sessions from our side even if the cookie hasn't expired yet I'm gonna set this to one hour here you can also make this longer and I later also want to try out what happens when this cookie expires but that's something we want to do later but the cool thing we can do is we can set rolling to true this means as long as the user is using our website this cookie will be refreshed automatically so if the user enters the website within this one hour they will stay signed in and of course if you say this to a week for example then they will stay signed in if they use this website within a week which I think is really cool because if a user doesn't use your website I think it's a good idea to lock them out eventually and lastly we need to set a store store is where the session data will be stored if you don't pass anything here the session data will be stored in memory so it will work until you restart your server then your sessions will be gone this can be enough for development but definitely not for production but also for development it's good to actually store the session data somewhere and for this we want to use our store that we installed so we have to import this here import store or the completion takes care of the rest and then we want to use it down here bongostore.create parentheses curly braces and in here we can pass a URL which is just the same URL that we also use for the rest of our database connection which we stored in the environment variables in this connection string let's save this and now we could create a new user and see how this cookie is stored we can actually see this in Postman but I don't want to create a yet another user so let's implement the lock and Route first and use that one that so we go into the user's controller and Below sign up we export another function here export cons login of type request Handler it needs a body so we create an interface this is second nature for us by now lock and body we send a username and a password it's hard to type and talk at the same time we don't need to send an email this time because we are not creating a newer user account we are just signing into an existing one down here unknown comma unknown comma login body comma unknown and if I'm too fast for you then you just have to step up your game come on man type faster async Reckless next and we create our error function okay I'm slowing down a bit we want to extract the input from the body so a const username equals rack dot body dot username and design for the password and then we add our good old friend the try catch block and call our next function down here which we have to do a every single time in the try block we want to do some input validation if the username is missing or if the password is missing we throw a create HTTP error status quo 400 error message parameters missing now before we can check if the passwords match we first have to figure out if there's actually a user with these credentials with this username in our database so we create a const user to an await user model find one for the username we entered and since the user is signing in we want to send them back all their data including their own email address and remember we set select to false by default so they will not be included here when we call find one but we can include them explicitly by adding dot select parentheses and then we pass a string here and in the string we write a plus and then the name of the field we want to include so plus password then is space plus email and then outside we append our exec this adds the password and email to this find one request which is necessary because by default we exclude them okay so if the user doesn't exist we want to throw another arrow so if exclamation mark user we want to throw a create HTTP error the response will be 401 which means unauthorized and the error message was a invalid credentials now I keep this error here generic on purpose I don't say this user doesn't exist you can do it if you want but for security it's a good idea tool don't tell whoever is trying to log in that this user doesn't exist because it makes Brute Force attempts more easy right this way when a user types in a username that doesn't exist they don't actually know if this user doesn't exist or if the password is just wrong but this is up to you you can implement it this way you can also tell an error message that this username doesn't exist but if we found the user we can go ahead and compare the passwords so we create a const password match equals a weight and then we have another b-crypt function that we can use compare which can take the raw password which we are sending over the login body and it can compare it to the hashed password of the user from the database so even though this password Here is hashed and this one is raw decrypt knows how to compare them and tell us if they actually match this is the cool thing about this Library it hides all this complexity from us okay so below we check if exclamation mark password match so this is a Boolean that we are getting back if this is false the passwords don't match we want to throw another error we actually reuse this one here in valid credentials if we get below this if block then everything went well the user exists the passwords match then we can establish a session which again we do a with request dot session we set the user idea to the ID of the user but with the underscore that we just compare the passwords with and lastly we want to return this user to the front end with a status code of 201 and we send the user as the Json body so we can use it in our front end right away let's save this and register this new route in our user routes file So Below sign up we create another user.post slash login and we forward this to usercontroller.login and then let's try this out in Postman so I opened Postman change the endpoint here to slash login we don't need the email address anymore let's remove the password for now to see what happens um yeah we also have to remove this comma here parameters missing let's add the password back in but let's make it wrong invalid credentials let's make the username wrong invalid credentials and now let's use the correct credentials okay and we are getting a user back not only that we are also getting a cookie back this connect.s idea is the session from the express session package we just set up and Postman actually stores these cookies just like a real browser would so you can see it's stored here as the key is stored in there and when we look into our mongodb database we will actually find another collection now for the sessions this is what the Bongo store did for us so this is the session for our user that's stored in our database with this x bios keyer and now we can force the user to log out by simply removing the session here but before we see how this works we'll have to add another endpoint where we can retrieve the user data of the currently locked in user so that we see that when we delete the session this will actually not work anymore so let's go back into our code and into our users controller once again and all the way at the top here before designer body I want to add another end point which I'm gonna call get authenticated user so here we get our user data from if we are logged in it's a request Handler it doesn't take any body or anything so we don't have to declare any types and as usual it's an async request next and here we want to get the currently locked end user out of the session which is very simple we can write const authenticated user and set it to rec.session dot user idea if there is a user currently logged in then this will have the ID of this user and if there is no user logged in it will be undefined and we know that there is no login session right now so in the try catch block here let's add the next call First we can check if there is no authenticated user then we could either just not return anything from the database but let's actually throw an error here so throw create HTTP error 401 for not authenticated viewers are not authenticated if there is an authenticated user we can return it here and we can call this endpoint for example later when we open our website so we open the website and of course we don't want to log in every time instead we want to see if there is a session that exists and the key that's stored in the session cookie and then we can just return the user right array So Below we want to retrieve the locked end user from the database so const user equals await usermodel dot find this time we can use find by ID because we have the idea stored in the session so between parentheses we pass authenticated user I actually want to rename this to authenticated user idea so rename this one up here as well we don't need to return the password here because the user doesn't need their own password on the front end but they probably need their own email address for example to show it in the user profile so we add a select plus email and add exec and then we want to return the user with a status code of 200 and we send the user and the Json body save this then set up a route for it router dot get slash we do it right at the user endpoint he was a controller dot get authenticated user save this as well and then let's try it out in Postman Postman get request two API users now we should be getting a user because we have the session cookies stored let's look in the audio there it is our user with our email address let's delete our cookie that we have stored here then the session should not work anymore use are not authenticated let's log in again of course that's a post change this back to get but before I execute this I wanna delete the session from the database so we have two now because one for the designer one for the login but the expire after a while so they don't keep stacking up in the database after they expire they will be deleted automatically but now we delete them manually and no decision should also be invalid even though the cookie is still stored yours are not authenticated so this is how sessions work there are two pieces there are the cookies which are basically the keys to your session and the session entry in the database and by deleting a session from the database you can force the user to log out but of course the user should also have a way to log out themselves without us having to delete them from the database so let's add another route for that let's add the route itself right array and then set it up afterwards so router.post slash logout entry will forward this to user controller dot logout which we haven't created yet but we will do this next now you could also make logout a get endpoint because we are not sending any body to the server but I think it's more correct to make this a post because we are changing something on our side on the back end side there are different opinions about it but I think post is appropriate so let's go into the user's controller let's put it at the bottom export const log out request Handler red rest next and then we have this rack dot session dot destroy function we can call to destroy a session now this doesn't return a promise so we can't use a weight and try catch in here instead we have to use a callback here but that's fine it's not a lot of code anyway so destroy attempts to destroy the session if there's anything that goes wrong it will pass us an error in this callback so we add error a right arrow and the function body here on curly braces we check if the error exists then we want to forward it to our error Handler as usual and if the error does not exist we just send a status code of 200 to indicate that the logout when successful and again since we don't send a Json body you have to use Zen status instead of just status okay and that's our last authentication route we need let's try it out in Postman once again let's log in first slash user slash login there's our session let's try retrieving the locked in user works as well let's log out we got our status of 200 and let's try to retrieve the user again oops and doesn't work because we are not authenticated anymore and there should be no session in the database yeah the session is gone as well okay so we just implemented authentication into our app using Express session if you found this helpful please leave a like on this video and the next step is to use these new endpoints on our front end so that we can actually sign in and log in and retrieve our user data in our react app rather than in Postman alright we will need a model for our user on our front end as well right so let's close all these tabs here for now and go into our front-end code here front end Source models and here we want to add a new file which we call user.ts that's just a simple interface that we want to export which we call user so that we have a type that we can work with it will contain the username and the email of the user we don't need a password here because there's no reason why we need this in any way in our front end we probably wanted this by the username somewhere and maybe the email address so the user can see it and change it but we don't want to do anything with the password on the front end now let's add all the endpoints that we need to our notes API file the endpoints for retrieving user data are logging in signing up and so on I'm going to put this all the way at the top here but below fetch data right here and you can also create different files for the API endpoints for the nodes and for users and other stuff but since they aren't too many right now I'm gonna put them into the same file Zone the first one is export async functional get locked in user I think the name is self-explaining it will return a promise with our user type here which we have to import properly in here we write const response equals await fetch data the end point is a slash API slash users and this will be a a get request now since both the front end and the back end are on the same URL this will actually send the cookies to the back end automatically so we don't have to do anything special in here we will either get the user if we are locked in or we will get a 401 response if we aren't so here we can simply return the Json body of the response which will contain the user data if we are logged in this works since the front end and the back end are on the same URL if they are on different domains or subdomains then you have to include the credentials explicitly which you do in the fetch configuration here so there's a credentials include property for that but you have to Google it because I don't remember the exact Syntax for that right now but you have to add this to the fetch call but our front end and back end are on the same URL so the cookies represent automatically but we also need endpoints for signing up logging in and logging out so for sign up we will need some input so let's create another interface for that which requires design up credentials similar to how we have created this node input interface earlier we will also use this in our sign up form later design up credentials consist of a username the email and the password and then we export another async function that we call Design up and this will take these credentials design up credentials as input and it will also return a promise of type user because after signing up rear return the sign up user right away okay const response equals await fetch data to a slash API slash users slash sign up comma and some configuration the method will be posed we send the Json body so we need our Json header here so let's copy this insert it here and the body itself for which we stringify our not create nodes but credentials which we pass to this function and then if everything went successful we want to return response.json which is the data of the newly designed app user we need another function for logging in again we need the credentials for which we create another interface lock in credentials because those only consist of the username and the password we don't need to send the email again so we create this interface and another function which we call login it takes the log in credentials and it also returns a promise of type user let's actually copy this from design up function because it's very similar just that we make the request to the login endpoint and the rest is the same we still send the credentials we still get the user back and lastly we need a function for logging out through our front end so another export async function log out doesn't take any arguments doesn't return anything we know that it went successful if fetch data didn't throw so we simply call a weight of fetch data two slash API slash users slash logout and the method is post and that's it save everything okay and now we want to create models for logging in and signing up which of course contain form input similar to what we already have in our add edit node dialog here but I said that we want to create reusable components for text input Fields otherwise we have to repeat the syntax here with form group and form label over and over again and it's quite verbose so what we do is we create another folder here in the components folder which we call form I just want to put form Fields into a separate folder for better organization and then here we created text input field.tsx file and we can split this and move this to the right so we can view both our files here at the same time we want to set this up in a way that we get rid of a lot of duplication here when adding these form input Fields so the first step is to create our component function here with the same name text input field and above it we want to Define an interface for the arguments that we pass to this component so text input field props so every text input field will need a name which is this part here that we use to register the field with the react formwork Library so we add a name of type string also all of our forms you have a label above it right so let's add this as another property you can make this optional if you want and only show the label for some but we show labels for all input fields then we need to pass this register call here to the text input field so we add a property that we call register and the type is used for register of type any like this we have to set this to any because we don't know yet what Fields this register will contain this way we keep it reusable we can use it in our zainab form in our added node model and so on and where do I know this return type from that we have to use use from register again I just Google this you just have to figure out stuff like this through Googling and this way we can pass this register function here to our text input field to register it with react talk form we will pass this configuration here separately so we add a register options and this one is optional because yeah we can pass register options like we do up here or we can omit them so we make this property optional and the type here is register options I just think it's more readable to separate the register function and the options rather than passing them as one thing and we also want to have this error message here and the type of these errors is field error or undefined so what we do is we add another property that we call error but this one is optional and it's of type field error so we can pass a field error or we can pass undefined in which case we want to ignore it just like we did here and then we add one more property here which we write like this scrap records X colon of type string like this and then call on any what does this mean this basically allows us to pass any other probes that we want to our text input field component even if they are not defined in here and we do this because these form input Fields have a lot of different properties available that we can add or omit and instead of defining each of them here separately we just add this syntax which allows us to pass any array of remaining properties then we have to list all these properties again down here so name comma label comma register comma register options comma error and for these optional props here at the bottom we write it like this dot dot dot props which is the syntax again where it takes something and it destructures it into its single pieces basically this just means that we get past each of these props that we add additionally one by one could be a bit confusing but if you just follow along you will see how this works and we must not forget to set the type here text input field props let's make this big for a short moment so we can see the whole thing this is how it looks and then we want to set up the same way as we did here on the left zor the outer tag is a form group with this mb3 class name and we add another property called control ID on this one and reset it with curly braces to name plus and then we append a string input and then we close this tag control ID is a property that does some accessibility stuff for example it connects the label that we put into this form group with the input field itself so that we can click the label and it activates the form input field and it also helps screen readers for example this is what this control ID is for we just have to set it here and we use the name of this input field which is different for each of them and we just append input to make it more recognizable then let's finish setting up this input field so we add the form label here which will contain the label that we pass to this component you can make this optional if you want by wrapping this with these two Amazon signs as we did earlier but I don't want to make this optional below we add form control which is the input field itself then first we want to pass these props here with this three dots which we simply do like this a pair of curly braces and then we write dot dot dots propsy as well and this simply takes these optional props and adds them to the form control and then we can just add them like we add any other props to our component just that we don't have to Define them up here on our interface then we have to do the same with the register like we did earlier another pair of curly braces dot dot dot register the first argument will be the name that we pass that's this property here comma and then we pass the register options which repair separately and then the same as over here is invalid property which we set to a to our exclamation marks to turn it into a Boolean and then the arrow we pass here which is the field Arrow or undefined this stuff is a bit complicated and a bit annoying but you only have to set up this input field once and then you can reuse them in your app that's the cool thing about it and it will be much less for both than what we have currently here and then we need this invalid input feedback let's copy this opacity inside the form group but change this to error.message because this is already the field error but it can be undefined so we add the save call Operator but it has to be error not arrows because this is the name of the property and now let's replace these input Fields over here in our add edit nodes dialog for these newly created text input fields so I'm going to do this with the browser open so we can see if the newer input field looks the same as the old one so let's not delete the other ones right away let's first add the new ones so opening angle bracket text input field and we can add the self-closing tag right array they all need a name the same one as we used here to register this so title they all need a label which will be title we set the type to text and this is the first example of our rest props here because we didn't Define the text as input props because we don't want to pass one down here for the text area this one is optional but instead of adding an optional property here we use these rest props this is how this is called so we can basically pass any property here and they will be put into our text input field so this is really just a matter of how explicit you want to be you can add them to the properties interface if you want to make this decision explicit or you can use these rest properties where you can basically add anything you want it makes sense for something like a form input field because there are so many different properties that we can pass or not and we don't want to specify each of them in our interface okay we want to set a placeholder as well which is another example of a rest property it's not in our interface 3.0 set this to title 2. we need register that's required here we can simply pass the register that we get returned from react formhog register options are optional and here we have to add two pair of curly braces because what we pass is a JavaScript object and that's why we need another pair of curly braces we want to set required and use the required string the same as we did before and now we can already save this and we see our second input field here the one at the top is the new one through our text input field component one more thing we also want to test the error here which we set two errors from react from Hook dot title so now when we don't add the title the error is recognized properly okay so we can delete the first input field here of the title and then we want to create another text input field for the node body area the name of this one is text the same as we are used down here to register it the label will say text we use S text area reset the rows and here you can really see all these different combinations of properties that we can pass that we all want to handle through this rest props here because it would be a lot of work to add each of them to the interface and it would be very verbose we add the placeholder which is a text and re-register this but this time we don't need register options add no errors because this is an optional field we don't have to pass it and there's our new text field and now let's delete this one down here now the new text input field code is not really that much shorter but the important part is that we don't have to repeat stuff like adding the correct margin all the time or all these different components is just a bit easier to use and everything that's required you can just add to the interface let's save this and see if adding a node still works another note blah blah and it's here at the bottom so it still seems to work now let's create a design up model through which we can create a new user account through our front end let's close the text input field code and the add edit node dialog code the API we can actually close everything and then let's create another component front end Source components new file we call it zineappmodel.tsx copy this name and create a functional component in here first we need to define the input props interface sign up model props we need an on dismiss callback so that we can close the model a function that doesn't return anything and we need another callback for when the sign up was successful so that we can set the use of our app to the newly signed up user so on design up successful this is a function that gets a user passed to it and doesn't return anything then we add these properties down here the usual way on this Miss on sign up successful of type sign up model props all right and now we have to write a little bit of code so first of all we need our register form hook and this stuff so we create a const curly braces the same as in the add edit note dialog we need to register let's actually add equals use form here at the end right array so that we have proper Auto completion for these different fields so we call use form add this import statement if it didn't automatically and the type for the input is our sign up credentials that we created in the notes API file earlier so we add this type argument and call this and now we have better Auto completion here we need handle submit we need form state which we destructure tour errors and is submitting this is the exact same stuff we have done in the add edit node model before then we need a function that handles submitting this data soar an async function on submit which will take design up credentials as input we need to try catch Block in case something goes wrong as usual we do alert with the error and we lock the arrow in the console we need a handle to our notes API file so let's duplicate this line and change this to a star as nodes API from the network nodes API file because we want to use this here we create a const for the newly signed abuser equals the weight notes API and we call our sign up function which expects design up credentials passed to it and if this weren't successful we want to call our on sign up successful callback and paste this newly created user to whoever is showing this sign up model now even though we don't have a sign up button yet we can still go into our ftsx file and show the signup model already so that we can see what we are building while we are adding the form Fields so let's go into app TSX and down here where we already have some models set up let's put it here below another pair of curly braces and since we don't have a state yet for now we just write true and to Amber's enzymes to show this model all the time and here we want to use our sign up model which expects the on dismissed callback on enter on sign up successful callback and for now we just pass empty functions here to ignore these callbacks but we have to finish our sign up model return statement here first before we can see it on the screen so let's finish setting this up this should return a model from the react bootstrap package research Hotel true as before and on height will trigger our on dismissed callback in here we put the model dot header with a close button and the title will say sign up below we put a model body which will contain our form so we import this react bootstrap form tag we forward on submit to a handle submit from the react talk form package and call on submit here which is our own submit function I don't explain this again because this is the same thing we have done in the add edit node dialog before now when we save this we should actually see something on the screen nice it's our emptier model right now and the formatting of the title is not correct yet because we also have to wrap this into a model title which takes care of using the correct font size and everything then let's finish setting up our form down here so we use our shiny newer text input fields the first one has the name username the label username as well just that we start with an uppercase because this will be visible to the outside we set the type to text we set the placeholder to username we Press Register from react formhook we Define register options with two pair of curly braces again because this will be required and you want to show an arrow here in case we didn't enter anything into this field which we get from errors Dot the username also from react formhog and when we save this we see our first input field then we want to add a second one below for the email address and then one for the password email and password are very similar so let's copy this it takes the same attributes but the name is email the label is email the type will be email as well and this changes how the browser handles this input field when we set the type to email we actually get some simple input validation here which means that Chrome or any other browser that handles this will not accept an email that's not shaped like an email with an ad and everything that's just a bit more useful than a normal text field but it does not replace backend validation remember because front-end validation can always be circumvented in one way or another on the back end we only checked that an email exists we don't actually check its shape there are packages that you can use for that but that's beyond the scope of this tutorial you can look that up in Google the placeholder will say email as well register is the same it's also a required field but for the error we want to use arrows.email and then let's copy it once again for the password and we can actually duplicate The Code by highlighting it and then we can press shift out and the down arrow like this but you can also just copy paste it the old way like a peasant okay so the name of this field is password the label is password the type is password 2 and this is pretty cool because it automatically hides the characters here so these types are handled by the browsers the placeholder will be password register and register options stay the same and we use errors password down here then of course we need a submit button so below here we add another button which is a sign up and it needs some properties we set the type to submit again so the browser recognizes this as a form submit button but this time we don't have to specify the form idea because now we have put the button inside the form tag itself remember earlier we put such a submit button outside of the form then we had to connect it manually but since this is inside the form the browser knows that this subnet button belongs to this form and when we press it it will automatically trigger this unsubmit callback here okay so we want to disable this button while the form is submitting so that we can't submit it twice at the same time this is our button but I also want to give it a width of 100 so it fills up the full horizontal space for this we can create another utility CSS class let's do that let's go over into a utils.module.css add another class down here which I'm gonna call width for 100 I think the name makes sense and here we set the width to 100 percent save this go back into our sign up model and import our utility styles so import Style utils from where is it located dot dot styles slash utils.module.css and now we can use it on here class name style utils dot with 100. and looks much better in my opinion looks like a real sign up form let's format this properly like this and then try it out so let's enter a new username Florent tool for around 2 at test.com and the password ASD ASD sign up now we don't have any feedback yet and the model doesn't close yet but if everything went successful we should see our new user in the database and also a session for it so here's Florian tour and there should be a cookie in our browser yet security is not secure is because we are on localhost it will be secure when we deploy this with https and there is our connect Sid cookie and now we should be able to retrieve the user data without having to send our login credentials again unless we log out let's also try this email validation that I was talking about so the browser yeah actually recognizes this and shows this error message here if the email is misshaped and also password managers recognize these input Fields because we set these different types here password and email and everything so a password manager like one password or LastPass will recognize that this is a password field and suggest you a credentials to put in there now let's also create the login model so we create another file here in our components folder we colored lock and model and of course you can organize this into another folder if you want but we don't have that many components in this tutorial so I keep it like this and create another functional component in here let's start with the props interface login model props as usual it's a dialog so it needs an on dismissed callback and then on login successful callback which again gets the user passed to it so that we can use it in our front end then we add this properties down here on this Miss unload in successful login model props and then the setup is very similar to design up model we need to set up our form so let's write const curly braces equals use form of type log in credentials that we put into our notes API file and then we need register we need handle submit and we need form state arrows and is submitting we need our async submit function so async function on the submit which takes the look in credentials log in credentials try catch alert error console Arrow error in try we want to try logging in a const user equals a weight we need a notes API let's copy it from design up model here because we are lazy this one here notes API the same location Dot Login we pass the user login credentials and if this weren't successful recall unlock and successful and pass back the user okay and then we need more forms so in here we create a model show on height I don't expand this again because we have already done this a few times by now oops what the hell is this model dot header with a close button model dot title that says login below the header we put a modal dot audio and inside here we put a form on submit handle submit on submit I heard that you like submits so we put an unsubmit into a handle submit into an unsubmit this was just a joke by the way don't get confused and we need tour text input fields first one has name username labor username type would be text placeholder will be a username we set up register we set up the register options required with the warning method required and for error repairs errors dot username that's a lot of work okay let's duplicate this for the password name password label password type password placeholder you guessed it password and error set password and then we need our submit button here as well let's copy this again first of all we need a style the style utils and the submit dot button down here copy this as well go over here paste it inside the form just change the text to a log in I never know if it's one word or two word it's very confusing and we have to import the react bootstrap button let's take a quick look at our login model over here we set this to false and we add another drawer to Amazon science log and model will be later set this up properly on dismiss and on login successfully for which repairs empty functions for now just to see this and as you can see the browser already suggests to save the password because it recognizes this as sign up and the login form okay here's our login form now it doesn't make sense to try this out right now the cookie is already saved first of all we have to set up enough bar and this navbar will then indicate if a user is logged in or not because we will see the username in the navbar let's set this to false for now so that we can set up our navbar and for the navbar as usual we will use a react bootstrap component this is how this nav bars here look you can add different stuff to them different colors different buttons and so on so let's add it to our app so we add another component to the components folder and I write the bar with an uppercase B like this because the component from react bootstrap is also called navbar but with a lowercase b and this way the names don't Clash soar we set up a functional component with the name navbar and as usual we have to sign up the props interface with the arguments the snuffbar component will take the Snapback will take the locked in user as an argument so that we can display the name of the logged in user but also the correct buttons either log in and sign up or log out for this we set the type of this to user from our models folder vertical barn now so this can be either the locked in user or null if there is no user locked in currently now why don't I make this an optional property like this because I want to force the color of the snuffbar component to pass something here if we used an optional parameter like this then we could just omit this property completely but our enough bar doesn't work without the user even if it's locked out we need this information so this is why we declare this type like this now we have to pass in a user even if it's null and then we need a few callbacks here for our different buttons log in and out and everything so the first one is called on sign up clicked when we click design up button we want to open our sign up model in the ftsx file now the question is why don't we put the authentication models directly into the navbar component then we wouldn't need a skull back to the app TSX file this is definitely an option but then you have to keep in mind that you can only open the models from within the navbar code but you might have other triggers in your app later that also open the sign up or login model for example if the user tries to do an action that requires a user account this is why we want to hoist this to the color of this navbar okay and two more let's duplicate this the second one is on login clicked and then we have on log out success file because we will handle the log out directly in here and then just notify the ftsx files so that it can remove the user data that's currently stored in the memory okay then we add all these properties here locked in user on sign up clicked unlock and clicked and unlock out successful and the type is our navbar props okay and then let's start building the navbar here and the return block we use this navbar tag from react bootstrap again this one has a lowercase b that's not our own component it's enough buff from react bootstrap we can do some configuration here we can set the background color to primary which is this default Bluer that react bootstrap components have you can customize this with CSS if you want but we won't do that here the variant defines the text color we said is too dark so that we have light text on the blue background expand defines Edward screen size the navbar turns into this mobile mode where we have this drop down menu that you will see in a moment so the Snapper is completely responsive and we set this to LG to what size you say this depends on how many buttons you have in there if there are a lot of buttons of course you have to collapse earlier otherwise there will not be enough room and we set a sticky attribute to Top This Way the nuff Bob will always be visible even if we scroll down but that's up to you and your preference okay inside the snuff bar we add the container which adds some padding so it looks better and then we have different components available which again I know from the documentation navbar brand adds a text or an image to the left side which many websites have when you click it you usually get back to the home page so let's enter a text in here Queen Notes app but you can also use an image if you want and let's already display the softball on our page where we are building it so we go into the ftsx file scroll up here to the notes page container and we want to wrap this into another div because we don't want to put the snuff bar inside this container we want to put it above it select this and then here we can use our navbar but this time with an uppercase B because that's our own one that's not the bootstrap one foreign user we just pass null right now and for the callbacks we pass empty carbex we will hit this properly later when we have this data so here we pass an empty function and there's our navbar of course it's not finished yet but we can already see our brand text let's actually make this a bit bigger here as I already mentioned we want to show different content in our navbar depending if we are logged in or logged out because if we are logged out we want to show a sign up and the login button and if we are logged in we want to show the username and the log out button so now we could cram all of this in here but it makes sense to extract this into separate files for better organization so we create another component in our components folder and recall this nuff bar locked in viewer.tsx I think the name is self-explaining and we create a functional component with the same name this takes some properties so interface Enough by locked in view props the first one will be the user from our user models and this time it doesn't have to be nullable because we only show this if there is a user only if we are logged in but we need a callback for logging out on lockout successful which is a callback that Returns the void we add these properties here user unlock out successful of type navbar locked in viewer props then we need a function for logging out which we can put directly in this component there's no real reason to hoist it to the outside in my opinion because the navbar is the only place where we have a logout button so we create an async function that we call logout doesn't take any arguments try catch as usual because even for logging out something can go wrong because it's a post request to our server which can always fail in which case we want to lock the error and alert it then we need our notes API so I'm going to copy this import statement here again they wait it doesn't need to return anything notes API dot logout and if this was successful we'll call our callback so that the ftsx file that contains the navbar can then remove the user from memory and in here we put the content of the navbar this will be two elements the text we've designed and username and the logout button and we want to display these two elements here in our enough bar later as I already explained we can't put two elements into a return statement they need one parent element we could put this into a diff but we basically just want to render them as they are inside this navbar here so we use a fragment as we did earlier and the fragment allows us to use two or more attacks in a place where we could usually just use one with a lowercase b and that's the bootstrap one dot text we add the class name m e minus 2 which adds some margin to the end of this text and this will say signed in as colon and then we use a variable we want to print user.username this will be shown in the nuff bar and then we add our log out button which was a log out and it needs an unclick attribute which will simply call our log out function up here which will then handle the rest now we also need a locked out navbar viewer so we create another component nav bar locked out viewer.tsx sfc this doesn't need a user because there is no user logged in but it needs callbacks for when we click the login or sign up button the interface navbar locked out viewer props and we need two callbacks on design up clicked and can you guess it unlock and clicked we add these here on sign up clicked on login clicked the type is navbar locked out view props and then in here we have set up this View again we create a fragment that will contain two buttons the first one triggers our on sign up clicked callback and it says sign up the second button triggers our on login clicked callback and the text says login that's it for the navbar locked out View now let's go back to the navbar TSX file and finish this So Below enough bar brand we add navbar dot talker this is this button that will later appear when the screen is small where we can expand and collapse the manual in Mobile viewer this needs a property called area controls which defines what menu this talker is responsible for it will be responsible for the main navbar so we type it in like this and then below we add enough bar dot collapse which we give the same ID here so this connects this toggle with this navbar collapse which is the collapsible manual so we said the idea to main navbar here as well you can set any name you want they just have to be identical close this and in here we put this enough Tech which just aligns the elements probably give it a class name of MS Auto which adds a margin start of order to it which means that these buttons and these elements will be moved all the way to the right so they will be at the end of our navbar so we close this as well and then what we show in here is either our navbar locked in or our locked audio depending if we are locked in or not so we add a pair of curly braces and check our locked in user which we passed with the snuff bar in the next line we add a question mark if there is a locked in user we want to show our navbar locked in viewer which expects some arguments it expects the user which is the locked in user which now can't be null anymore because we have this checkup here and our on logout successful callback which we forward to unlock out successful which is the property that repairs to the navbar component now as you can see when you have components and other components you often have to forward properties like this so we have unlock out successful in the nav bar but then we also have it in the navbar locked in viewer to a certain point this is okay this is called prop drilling because you trade these props into different layers if this gets too much there are ways around this for example your react context which you can Google there's also something called react query which gives some convenience functions and hooks for when you will fetch data from an API but this is beyond the scope of this tutorial here we use good old prop trailing because you need to get a feel for how this works when you are a beginner and below this line we write colon for when the user is null then we want to show the navbar locked out viewer which needs to unlock and clicked callback which we forward to unlock and clicked and the same for on sign up clicked okay and after saving this we can see that our token menu here appears let's make this bigger because at a certain point this will not collapse anymore again the size depends on what you want to put in here we can actually make this expand Point smaller because we only have these two buttons here so let's set this to SM which should be small so now it should collapse a little bit later so you can still it's still expanded and here then collapses I think that's more appropriate you can set this back to LG if you add more stuff to the navbar that just gets too long so now we actually want to check if the user is locked in and only show the nodes in this case again we have to handle this in the app TSX file but I actually want to organize the code that shows our nodes into a separate file because it doesn't really belong into app TSX it's not called organization and also it will make the code messy when we now have to add another conditioner that checks if the user is null or not so what we do is we create another component in the components folder which we call nodes page locked in viewer.tsx create a functional component with the same name and then we want to cut out some code from the ftsx file and move it over there the authentication models will stay in the ftsx file but all these added and add nodes dialogues belonging to our newer logged in viewer because there should only be available if a user is logged in so we cut out node to edit show add node dialog the loading Spinners and everything all the way up here to this button cut this out paste it over here but since those are multiple elements we have to put into a fragment like this now we have to fix some import statements and you can do this by just removing the last letter and then Auto completion will help you on importing this again at least for the components add edit note dialog the other stuff here is mostly still over here we need to copy over some states basically all of those move them in here import use state Auto completion doesn't work let's copy it from over here we need our node model here we have to import this manually as well because of the name so we copy this line put it in here we have to fix the folder where it's coming from I think we only have to add the dot here yeah that works and we need our style utils let's copy this as well paste it here fix the import as well should look like this I think import a spinner from react bootstrap and our notes grid is still over there of course we need that as well and we also need our delete node and load nodes functions actually the whole user effect so we cut our use effect with load nodes we cut our delete node and our whole node squared and even though it's a bit messy right now it will be much better organized after we have done this so let's paste this here let's do some imports missing notes API diodes is missing this one here notes page this is by the way why I call this notes page module zss and not app module CSS because I knew that we have to refactor this later okay and we need to import the row from react bootstrap and coil and our node component and this looks good I think we got everything so let's organize the import statements properly for which there is a shortcut shift alt or which organizes them properly and gets rid of the one we don't use format and save the file and let's do the same over here shift alt over shift IDF to align everything properly and let's save this then we want to create a little notes page locked out viewer but don't worry this will be a fast because you just print some text there so another component notes page locked out viewer dot TSX we create a functional component this one doesn't need to take any arguments and it will return a paragraph tag which says please log in to zero nodes of course you can always make this more sophisticated in your real app but for this tutorial this will do files okay and now we have to connect everything in our app TSX file set up the models and fetch the user and everything and then we will be able to log in and out from our front end so this was a lot of work but we are almost done with this part okay first of all we need a state for the locked in user when we open our page which Ibex executes this app component we will try to fetch the locked in user from the back end by making a request to the get authenticated user endpoint and remember we are automatically sending our credential cookies so we either get the user back if we are logged in or we get the 401 response if we are not logged in in which case we will just ignore this and then we can use our website as a not locked in user so we call this locked in user and The Zeta Zed locked in user which is a used State we have to import this again from react let's copy it from over here we will need to use effect as well use state of type user or Nile if there is no user logged in and we initialize this with no and we have to import our user type here we will also two states that indicate if the sign up or the login model are showing So Below const show sign up model and set a shower sign up model which is the use state that we initialize with faults entry duplicators for login so show login model and set show login model like this then we need a user effect because as I said as soon as we open this page we want to try loading the user which is a side effect so we add a user effect like this and before we forget it we add an empty array down here so that we only execute this one time when we open the page in here we put an async function that we call fetch locked in user doesn't need any arguments and below we call this function and I explained earlier where we have to do this because we can't make this function that we pass to use effect async we have to do it over this intermediate function and this gets a try catch block if there is an error including our 401 response we actually don't want to show a dialogue to the user we just want to lock the arrow to the console because otherwise every time the page is opened without cookies it would show an error message which we don't want now later we will Implement a way to distinguish between different errors so that we could still show an error message if it is not for one response but for now this is sufficient and here we will try to fetch the user and save the return value in a variable so Constitution equates a weight user notes API we have to import this dot get locked in user which we had set up earlier or the import statement is not correct like this doesn't need any input because again it will automatically send the cookie that we have stored and if this went without an error then we want to set our locked in user state to what we get back and we are almost done to our nav bar down here we want to pass the locked in user and enough bar will then use this information to decide what content to show but we will see this in a bit on login click it will set a show login model to true and on sign up click it will set show sign up model tutorial and in on logout successful we know that we successfully destroyed the session then we want to set locked in user back to null and the beauty of declarative UI is that all of this will stay in sync automatically when we set the locked in user to null our navbar will automatically be re-rendered with the Nile logged in user and the same after logging in but you will see there's an action in a short moment here for a sign up model we use our show sign up model state and here show login model and up here we want to show the content of this page depending if we are logged in or not so we have to add a fragment because otherwise we can't add this conditional here here we check for the locked in user if there is a locked in user we want to display the notes page locked in viewer and otherwise the notes page locked out View again this automatically re-runnels when this logged in user State changes and these two components don't take any props because they are completely self-contained they handle their own state let's actually take these models and move them out of this container it doesn't matter because the models are not affected by the container but for better overview I want to have them in this outer diff here and now that I save this file you can see that our navbar already displays the locked in view really cool but we still have to fill this callbacks down here so on dismiss in the sign up model we'll set our sign up model back to false on this Mist down here we'll set your login model to false and remember when we designed in or log in then we get the user back from the API so that we don't have to run our fetch locked in user again instead we can set our user State directly from the return value so both of them get a user test back because this is what we defined here in this callback in both of them we want to set the logged in user to the return value so I duplicate the cursor like this and I type Z locked in user and I pass the return value like this entry also want to close the models again so set show sign up model faults and that show login model faults and then we save everything okay and now let's try the different states so when we log out the user should be set to null if it went successful and our nodes should disappear and we should see the locked out view on there it is we will fix the padding later but for now this is cool let's try to log in Florian tour with a wrong password first invalid credentials we will put this error message into the log and dialog later instead of this alert dialog because this is a bit annoying but for now this is fine log in it works the browser suggests to save the password don't do this right now and now we can see our notes again and enough bar updates and again this is the beauty of declarative UI everything is synchronized through our state automatically basically as long as we declare it correctly of course right now nodes are not tied to a specific user yet so if I log out to a Florian tour and log in with Florian one or just Florian then we see the same notes oh I forgot my credentials okay one two three four five six right here then we see the same nodes as in the other account we will make it so that each user has their own nodes later in this tutorial but at least signing in and out Works already let's also try out if the cookie expiration works so I go into our backend code once again and I'm gonna set this to a I don't know 20 seconds but I will we wrote this in a moment just to see if this expires correctly so I saved this I log out here then I log in again to create a new session and then I wait 20 seconds and refresh the page and see if we are still logged in we shouldn't because I set the cookie max age to a 20 seconds but this will automatically refresh the session if we do something on the page where the session is still valid but if we don't do anything this will expire okay 20 seconds have passed and when I refresh this we are not locked in anymore because the session expired but I want to keep this at one hour or however long you want you can also increase this value and yeah the next step is to actually tie nodes to a specific user accounts so that's what we will do now in order to tie a node to a specific user we have to make a little change to the node schema in our backend code so let's search for the notes model in our backend here here we want to add one additional field to the schema I'm going to put it at the top you can also put it somewhere else doesn't matter we want to store the ID of the user that created this nodes so later when we retrieve nodes we can only retrieve the notes for a particular user the type of this field will be mongoose's object ID type that we already used earlier that's the one we store in our session so we already have schema here imported so we can just type schema dot types dot object idea and with that required to draw so that every node needs a user ID attached to it comma and then we save these changes and then in our notes routes we want to do the same as we did in our get authenticated user function inside the user's controller we want to check the idea that's stored in the session and if there is no ID stored in the session we want to return a 401 response because the user is not authenticated and they shouldn't be able to retrieve or update or delete nodes but this means that we have to repeat this piece of code with the same error message in many different endpoints instead of repeating this for every endpoint it makes sense to extract this logic into our own middleware and then we can use this middleware like we used any other middleware by attaching it to the routes that we want to protect so let's do that now in the source folder of our backend we create a new folder which we call middleware here you can store all kinds of middleware that you create yourself and let's call it off.ts in middleware is basically just a request Handler just like our endpoint controllers so we create an export const let's call it requires of of type request Handler wreck rest next we already know that and in here we simply check if the SS session in the request object that contains the user ID in other words if a user is logged in that's what we did in get authenticated user earlier up here then we want to call next and next without an error simply occult the next middleware so it forwards the request and the response object to the next middleware in the row which will then be the endpoints itself else if there is no authenticated user we want to throw an HTTP error now we could wrap this into a try catch block and throw an error here but we can also just call next and forward the error directly and since we don't have any other code in here that can throw this is more concise remember we trigger our error middleware at the very end simply by passing the arrow to the next function this is also what we did in all our endpoints just that those were the arrows that we caught in the try catch block but we can also forward an error to the next function directly and here we want to use our 401 around that says use are not authenticated with the correct spelling of course and now we can use this middleware on all endpoints that we want to protect and we don't have to repeat this chord and now let's use this for our endpoints and let's start with our get authenticated user endpoint here so what we do is we remove this check here this will be replaced by our new middleware and then we can also remove this intermediate variable we can keep it but we can also just press rec.session.usid here directly because we don't use it in another place we save this then we go to the user's routes and use this middleware here we want to use it for the get authenticated user endpoint let's see if Auto Import works it does requires off it adds this import here at the top and the Order of these middlewares of course matter we first want to check if the user is authenticated before we call our endpoint Handler otherwise this one here would be executed first and then we would check for off which doesn't make much sense so to see if this still works let's save our code and then open our website again so the session has timed out meanwhile let's refresh the page and it says user not authenticated so we are still getting our 401 response but we shouldn't get it anymore after logging in so let's refresh it once again and we get our authenticated user with a 200 response so it seems like our endpoint still works properly just that we extracted the authentication logic into this middleware and now we can reuse it on other endpoints as well and we basically want to use it on all nodes and points right because you can't really interact with notes if you are not authenticated so let's do that now and now we can decide if we want to add our requires of metalware only to specific node endpoints in which case we could add them here but we actually want to add it to all of them so we can make it easier and edit one level higher we can add the middleware right here before we forward to any of our notes routes so here before notes routes we also color requires of and now just like that all our nodes and points are protected by our authentication middleware let's try it out in Postman first of all let's remove this once again for a short moment just to see that we can still retrieve all notes if we don't have this middleware so we want to make a get request to a slash API slash nodes here which returns us all notes right now now let's put the middleware back in and there are no cookies set right now so we shouldn't be authenticated and now it says user not authenticated with a 401 response which is triggered by our middleware and this should also work for creating new nodes updating or deleting notes and everything else we add to the notes routes so let's try deleting a node from our database I already refresh this just take a random note here this idea slash notes slash this idea a delete request we are not authenticated user not authenticated but right now this only means that a user has to be logged in to interact with the nodes but once they are locked in every user can still interact with all nodes because we haven't added any logic that allows the user to only retrieve their own nodes or modify their own nodes so let's do that now in our notes controller so the authentication check is already in place we only Reach This endpoint if we are authenticated so now what we want to do is we want to get the authenticated user idea so const authenticated user idea from the session so rec.session dot user idea but now we still have a little bit of a type problem because authenticated user ID could be possibly undefined there is no guarantee that we set user ID on the session now we kind of know that there is a user ID because we have this middleware in between that checks for the user idea and throws the 401 error if there is none but for one typescript doesn't notice it's not smart enough to recognize the middleware and say okay the user ID will definitely be defined but secondly even we can't really know it because we can accidentally remove this middleware and then this user ID could be undefined and as I explained earlier using undefined values in our code is a bit dangerous because it could make our app misbehave the one way to handle this is just to be confident that we added our middleware everywhere and whenever we can't use an undefined value we can use the normal assertion operator on the exclamation mark but it's actually better to have another check in place that makes sure that the user ID actually has a value so for this I want to create another function that does this check we put this into the YouTube folder of our backend code new file let's call it assert is defined.ts and let's copy the name because the function that we put in there will have the same name from here we want to export one function with this name and this function will take a generic type argument which we do like this with a pair of angle brackets and a big T in between and then in between the parentheses we write via colon tier while it's just a variable name you can give this any name you want and if you haven't worked with generic types before which is a feature that many languages have this T basically allows us to pass any type to this function so why don't we use any instead of tier because we actually want to get a non-nullable type back there's a feature for that in typescript which we do like this we add the colon for the return type but instead of defining a simple type we write asserts which is a special typescript keyword and then again of this type tier and then we add curly braces for the function body now if this is confusing to you don't worry you don't need to understand this in detail and this function will be very small it's just a nice feature to use but as a simple explanation this function allows us to pass any type to it and then it will check that this type is not null and then on the outside where we use this function we get the non-nullable type bag that's basically it and this also works for undefined so if we use this for our possibly undefined user ID here we can use this function and then know that it is indeed an object idea otherwise dysfunction will throw an error which we do in the function body so here we check if exclamation marker value so if value is undefined or null then we want to throw an error because again it's better to throw an error if there's something wrong in our code rather than using the wrong value and having the server misbehave and in here we pass an error message something that allows us to later identify the error so let's write expected and then in single quotes buyer to be defined but received and then we can add value itself which will then say another undefined depending on what the value is and that's all for this function if you want to learn more about the syntax you can read the documentation but for our example here this is all we need and in here we want to use this new function let's put it into the try block so that if this function throws our whole Server doesn't crash only this endpoint here will return a 500 response which is appropriate because we messed something up in our code when this happens so we call assert is defined and pass the authenticated user idea and this is actually all we have to do when we use this authenticated user ID afterwards it will have the appropriate type because typescript is smart enough to know infer this type because of this special syntax here this function asserts that authenticated user idea is defined so it has a value again you don't have to do this but it's a nice security measure and I think it's a cool typescript feature to learn about and now in our find call down here we only want to return the nodes for that specific user so we add a pair of calibrators to add the filter here we want to check the user idea of our node model that we just added a moment ago and we want to compare it with the authenticated user idea which Noah definitely has a value because we are past this assert as defined check before we add this to the remaining endpoints let's quickly try it out let's remove the requires of middleware from the notes routes once again and let's try to make a get request without being authenticated an unknown error occurred it's a 500 response with this generic error message because it's not a HTTP error we threw here and in our FTS file we only handle HTTP errors and otherwise we file back to this an unknown error occurred message but I think this is fine because when an error like this happens the user doesn't really need to know what happened in our code instead we just lock this error which will print the whole message to the console so it should be visible in our backend terminal yeah expected value to be defined but received undefined and as long as we know it everything is fine the user doesn't have to see this error message now let's add this to our remaining endpoints here get node is the next one here we also want to get the authenticated user ID so let's copy paste this line then at the start of the try block we want to check assert as defined to make sure this has a value so we have to reuse this everywhere and then we have to add some code that only allows the user to access this node if the user ID is fit right so after the note was found we can check if this node belongs to this user so we do if exclamation mark note dot user idea which is of type object idea and to compare objects IDs we have this equals function here that belongs to this type we want to compare it with the authenticated user idea so exclamation marks so if they don't match then we want to throw another error throw create HTTP error for one response for not authorized you cannot access this node maybe without the exclamation mark and now this node endpoint is protected properly the next one is create note again we need to extract the authenticated use ID from this session let's do it here we need to check that it's defined so we copy this as well the start of our try block and now when we create this node we also have to pass the user idea it's a required field now so this wouldn't work without the user ID and since we have our off middleware we shouldn't be able to get to this create nodes function unless we are authenticated so we want to store the authenticated user idea in the node as well then we copy this authenticated user ID once again for update node we copy assert as defined put it here and then we want to do the same thing as we did for get node we want to copy this block here you cannot access this node and do this check after we checked if this node actually exists now of course you can always extract some of this validation logic into a separate function that you can put for example directly into this controller file for Simplicity I will just copy paste the code that we need on different endpoints because maybe you also want to use different error messages for the different endpoints in which case you have to write the stuff over and over again and one more time for delete note so again we copy this line paste it here we copy assert as defined paste it here and we need our check for the user idea as well after we check that the node exists and save everything this will now after saving everything when we refresh our front end these nodes here should disappear because they are not tied to a user they don't have a user ID attached to them but now we only get notes with our authenticated user ID back which is stored in the session cookie this one so let's refresh this page you don't have any notes yet let's create a node for this user authenticated note this is my private note okay there's still something off with the formatting I know why we will fix this in a moment for now let's log out with this user with Florian log in with florian2 who doesn't see this note because it's not tied to a specific user account Florian 2 snort this note is a secret so again this is attached to this user account log out into the other one and we won't see this note only our own one nice now let's fix this formatting here real quick earlier in our notes page modules yes S5 we created this node squid class with width 100 but we never used it anywhere so we go into our notes page logged in View and when we scroll down we have a typo here we call it node grid but the class is called notes grid now it should be fixed yeah it looks better now let's add the second note authenticated note number two and the layout looks good now and when we look into our database we will see that our new nodes now have a user idea attached to them our old nodes don't because we created them before we require the user idea but here our new nodes have this user idea so these other notes are basically off and now no one will be able to receive them you can delete them from the database you can keep them as a memory I don't care and our backend code is finished for now we now created the fully blown server with user authentication and different endpoints of course there are more features and little things you can add but you can always figure this out yourself or keep an eye open for my future courses that I'm building where I also want to cover more advanced topics but this is already pretty cool the course is not quite over yet because we still have to make some improvements to our front end first of all the styling isn't great yet there are still some problems here we like the missing padding but even more important there are some improvements we want to make to the way we handle errors so that we don't only always show the alert dialog which is really annoying and I also want to show you how you can navigate between different pages in react because we haven't done this yet we only have this one page right now we will add additional pages and then navigate between them so that they are even represented in relative ul's on our front end like localhost 3000 slash privacy for example and remember but after that there is another video waiting for you only notes Channel where we deploy this whole thing to a real server and if you want to put this project into your portfolio for example to get hired later it's a good idea to actually deploy something to production rather than only putting the project on your GitHub profile because this way you can prove that the thing you build actually works and it's easier for recruiters and employers to access your project and try it out without access to your GitHub account so you don't want to miss out on the part where we deployed this whole thing to navigate between different pages in our react app we can use this very popular package called react router because remember in a react app everything is one single page basically and the only thing we can really do is replacing components that are rendered on the screen but react router basically gives this process more structure by mapping different components that we use as pages to different relative URLs so that we can have something like a slash privacy page where we render the page component for the privacy policy slash nodes and so on as usual the documentation for this package is humongous but we don't need to know all of this you can just follow along but we need to install it so let's open the terminal for the front end so I'm going to ZD into the front end and we run npmi react router Dom that's the name of the whole package that we need and start a sucker and right now here in our ftsx file our notes page is hard coded yeah into the page what we want to do is we want to extract this into a separate file so that we can replace this part here when we navigate to different pages so let's create a new folder in our front end Source folder here which we call pages and inside this Pages folder we create a file code notes page.tsx where we want to extract this piece of code here into so let's split the editor create a functional component with the same name and then we cut out this container here put it over here fix the import statements container from react bootstrap notes page locked in viewer from our own components and the locked out viewer we also need a styles which we can cut out here paste here but this page needs the currently logged end user to know which of the views here to render so we have to pass this as a property so we create an interface notes page props which receives the locked in user which can be logged in or not so it's either user or no if the user isn't logged in and then we add a prop down here locked in user and the type of these props is notes page Pros and now the same as before we check this user to decide if we render the locked in view or the locked audio and the rest works the same as before we can also remove this unused import statements over here shift alt or and they are gone before we set this up let's create another page that we can navigate to gonna close this and create another file in the pages folder which I call a privacy page dot TSX recreate the functional component with the same name and I actually hired a lawyer just to make this course that came up with a elaborate privacy policy he told me to write this we care about your privacy promise this way you are safe and no one can ever sue you of course that's a joke I can't take any liability for your privacy policy or any other legal topics this is not legal advice let's save this and let's actually create a third page I want to have a fallback page for when we try to access a URL that doesn't exist so we want a page not found page so we create another file in the pages folder which require not a found page dot TSX again this contains a div with a paragraph that says page not found of course you can make this always more elaborate okay back into our app TSX file in order to implement react router Dom we have to wrap this whole diff here into this browser router tag this basically activates this routing functionality and this is the place where we want to navigate between our different pages the navbar is unaffected by this because the navbar stays in place no matter what page we are on right and our models can also show on any page because they are triggered by the buttons in our navbar so in between these two parts where our nodes page code was before we add a container from react bootstrap again container centers the content and gives it some padding and also I want to add some styling to it later and in here we add this routes tag this one here routes from react router as the name implies this allows us to set up routes in here between which we can navigate and now registering these different routes is actually quite easy for each route we create a route tag this time it's not routes it's route close this tag and then we give it two attributes the first one is the path so the relative URL to this page for the first one we just use a slash because we want to show our notes page on the base URL you can also put this on slash nodes and add a different home page but that's something you can do yourself then we have to define the element which is the component that we want to render for this page so between curly braces we pass our notes page component that we created earlier which takes the locked end user as a prop ER and then let's add the other Pages as well so we create another route the second one will go to a slash privacy and for the element we want to render the Privacy page and for any URL that we didn't specify we want to file back to our not found page which you can do like this we add another route but for the path repairs slash and the star this fits any URL but before it checks this one it checks the ones above it so if none of these match it will fall back to this one here and for the element we pass our not found page and as simple as that our routes are set up let's save everything open our cool Notes app and there seems to be something wrong with an import here in the notes page TSX file and the import to the CSS module is wrong so notes page dot TSX I guess that's two dots now let's try it out and now it works again so let's try it out manually let's type in slash privacy in the URL and here's our nice privacy policy of course the styling is not good you can improve this yourself if you want and then let's type in a URL that doesn't exist and we fall back to our page not phone page and now before we go to the next step let's fix the padding here so what we can do is we can take the container of this page and just add some padding to the top and it will be applied to all our Pages here so back into ftsx we need a new CSS module for our app TSX file because all the other CSS move to these different pages and components we created so we create another file in styles which we call app.module.css and again this module will be scoped to the ftsx file and not clash with any other class names and here I want to create a page container class on which we set a padding gonna use 32 pixels for the first value which are the vertical values so top and bottom and for the left and right side I'm going to use 0 because everything is centered anyway and then we import this in ftsx Imports diodes from dot slash Styles slash app Dot module.css and then we scroll down to our container here and add this class Styles Dot Page container and now when we save this and open our quill Notes app again we have this padding here applied which will work on any page now looks much better now let's add a menu point to our navbar with which we can navigate to our privacy page and let's make this brand text here behave like a link tool so we can click it to get back to our notes page so back into our code we want to go into our navbar component so Above This enough with MSR tour we create another nav tag we put it outside of this part here because these buttons will be on the right side and I want to have the links on the left side this is why it goes outside of this margin start Auto attack here and also from bootstrap we have this nuff link components which just at a properly stated link to the navbar that looks good this one with a privacy and it needs an href attribute which is the link where we want to link this tool we want to go to slash privacy so let's save this and try it out we now have this link up here and when we click it we go to the Privacy page but if you pay close attention the way this works is not quite optimal yet since this is a normal link it will actually refresh the whole page which means that the user that we stored in memory disappears for a moment and we also see the navbar flashing up because the whole page is replaced let's take a look at it again it looks weird you can see that we are locked out for a moment so to speak why because it's fetching the user again we don't want it to behave like this instead we want this to behave like a real app we had enough ball stays in place and only these parts down here are replaced right this is where we can't use a normal href link for internal app navigation because it will always refresh the page to handle this internal app navigation we want to use a special link component from the react router package we have to import this manually I checked it a moment ago the auto completion didn't work so we import it like this link between curly braces from react router Dom down here and then we go inside the nuff link and we wrap this privacy text into this reactor rather Dom link and then we cut out the slash privacy here remove the href attribute because we want to let the react router domlink navigate which we do we add this tool prop now the syntax is where we were both with the snuff link and this link inside it we will actually improve this in a moment but for Simplicity I want to show it like this first so we go to the cool Notes app again and now the styling is completely off as you can see the color doesn't work properly anymore which is the case because we invested these different components but we will fix this in a moment the important thing is when we now click this we will navigate to the Privacy page but the navbar will not refresh and the user will stay logged in click it and as you can see it's a much smoother transition and even when we press the back button the behavior is the same it doesn't refresh the whole page but now let's fix the styling here what we can do is we can keep using the nuff link but we can render it as a link from the react router Dom package and again I figure this out through Google this is a special syntax that we can use on this bootstrap components and this feature is called render props it's a certain design pattern and reacts that you can also build yourself if you need it and some packages like react bootstrap use that for certain components so what we can do is on the nav link we can pass this as prop with one else not two and here we can tell react bootstrap to use the styling and everything from the nuff link but actually render a different component when this is displayed on the screen and in here we can pass the link from react router Dom and the cool thing is now that we render this as a react router Dom link it also behaves like a react router dumpling this is why we now see this error that tells us that we need this two attribute that's the two attribute down here now that we render this link up here we have to pass this to attribute here as well and now we can remove this intermediate link here in between and now basically we are using a react router Dom link but we are using the styling of a normal bootstrap nuff link so when we save this and go back to our app now The Styling is correct again and it behaves like a react router link okay now let's also make the cool Notes app brand text here clickable so we go into navbar brand and here we use this as attribute as well we want to render a react router link and we want to navigate tour slash as a string so this is just the home page and it already is you can zip this trade out and now this one here is clickable as well you can go to privacy and back to the home page cool stuff okay our page itself is almost complete but there's one more important topic I want to teach you and that's how we can distinguish between different errors on our front end because right now for every arrow we do the exact same thing we lock the error message and show an alert dialog but you might want to handle different errors differently so that's what we will learn next distinguishing between different arrows on the front end allows us to handle them differently for example when we try to log in with invalid credentials and we get a 401 error back then we probably want to display this differently than internal Zara arrows for example so if the credentials are incorrect we want to display a little error text here above the input Fields so what we do is we go into our front end code and create a new file here we put it into a front-end Source here we create a new folder first which we call errors and in here we create a file called http arrows.ts and in here we Define some classes that allow us to distinguish between different errors that we receive now I guess we could also use the HTTP errors package that we used on the back end but I think this is a bit Overkill because it has all these functions to create errors but on the front end we don't want to create errors we only receive them and want to distinguish between them so I think we don't need to add this package instead we will just create some small classes that allow us to distinguish between these different errors so what we do is we create a class called HTTP error extends error we use a class instead of an interface this time because error is also a class and we want to extend the normal error to add our own fields to it and here we add a Constructor if you have any programming experience then you know what the Constructor is the same as the normal error class our class will take an optional message that we can store in this error and show later the question mark colon trippy of type string and then we want to pass this message to the superclass to Stuart in the normal error message field so we call Super and pass the message here the reason why we overwrite The Constructor is because we also want to set the name attribute of the error and set it to this dot Constructor dot name and this means that when we create a subclass of HTTP error it will use the name of the class itself and put it into this name field and now below we want to do exactly that we want to create a fewer subclasses of HTTP error that then allow us to distinguish between different error codes and we export these because we want to use them on the outside we don't want to use the generic HTTP error on the outside only the subclasses are meant to be used throughout our code so we write export class and the first one is for 401 responses when we are not authorized so we colored unauthorized error and it extends our HTTP error class and again our HTTP hour class does is basically putting the name of unauthorized error into the name field of the error class and every class needs a body but we can keep this body empty because we don't want to do anything special in here we just need this name to distinguish between the different error codes and we will also add a documentation comment here with a slash and tour style symbols and here we can write a message that we will then see when we hover over this class I'm just gonna set this to a 401 so now when we hover over on authorized around we can see for one actually let's write status code 401 this just makes it a bit easier later to remember what the status code each error was and then we create the second one below export class we call this one conflict error which we use for four or nine responses for example when we try to sign up with an email that already exists it also extends HTTP error with an empty body and create a documentation command as well status code 409 and I'm also going to add another comment here at the bottom which was a it's more error classes if you need distinction this is just a reminder for you that you can always add more error classes here then we go into our notes API file here in our Network folder and all the way up into fetch data where we now want to distinguish between these different arrows because right now we always throw this generic error class so we go above this line and we simply check for the status codes so that we know whichever we have to throw so if response dot status is equal to 401 then we want to throw an unauthorized error which will also contain the error message and we actually have to add the new keyword here in front of it for normal errors you don't have to do this you can if you want but since this is our own custom class we have to add a new keyword in order to instantiate it then we do an else if because now we want to check if response dot status is equal to 409 in which case we want to throw a conflict error which will also take the error message and only if both of those are not the case we want to go to the else block and throw our normal error and we can also make the error message a bit more elaborate so we see which status code we got from the error message itself so I'm going to pass a string that says request failed with status colon then I append response dot status and add something more to the string message colon and error message you don't have to do this but I think it's a good idea now let's save this and update a few places in our app first of all let's go into our login model and instead of RS showing this alert message when we get a 401 response back because the password or the username was wrong we want to show an error message that is embedded in the dialog directly instead the first of all we need a state for this that decides if this error message is shown or not so const let's call it error text and set error text equals use State Auto Import often doesn't work for you state I don't know why let's take it from somewhere else here you state we actually don't need use effect we call you state we set the type to a string or another because if there is no error we want to set this to Nile then here in the catch block we want to check if error instance of which is a keyword that we can use to compare the type of this error if this is an instance of an authorized error which has the status code 401 we can remember this by hovering over it then we want to set the error text to error Dot message and if this is any other type of error we want to do the same as before we want to show the alert dialog or just lock it or whatever you want and we will lock the error in both cases so we put it outside of the if block and now we also need an element in the model body here that actually displays this error let's put it here inside the model body but above the form we check if error text is defined so error text and to Embers enzymes then we want to show an alert which is another bootstrap component and this alert will show the error text from the state and we set the variant to Danger which gives this some nice styling it makes it red let's save it and try it out let's go to our quill Notes app and try to log in with invalid credentials and now we see this message here instead but any error that's not a 401 error will just show the usual alert dialog as we had before let's do the same for our sign up model so we open the design about the TSX file again we need a state const error text and set error text use State again we have to import this manually use state of type string or null and we initialize it with null and then down here we want to check if error instance off and this time we use conflict error which is the status code that we return When the username or the email is already in use right 409 then we want to set the error text to error.message else we want to use the same alert as we had before and we want to lock the error in both cases again we need our Alert warning here in the model body so error text to Ampersand science alert variant Danger and for the text we display the error text okay let's try this out as well so we open the sign up model and I use a username that already exists test at test.com we try to sign up and with the username already taken please choose a different one or log in instead and this is the error message that's coming from our server from our user controller username already taken and the other one which you can try out as well so we use a different username but in email that already exists I forgot which email I used earlier florian2a test.com a user with this email address already exists and we get the error message directly from the server because we read it from the response body and then pass it to our error here and then we display this in the UI through this error.message field and of course you can use the same approach to distinguish between different errors in different places in your app and this way decide what you want to do with them all right we have successfully created our first mon app this is a special moment that you will always remember and of course you will like this video and share it with someone that could need it because this helps me and you are a very thankful person that wants to give back although I heard remember that there is another video where we deploy this whole thing only notes Channel you can find the link in the video description below you definitely have to watch this as well because building this app and then not deploying it would be a waste also of course there are a lot more features we could add to our Merin app and keep an eye open on this channel because I want to make more web development tutorials so subscribe if you haven't yet and if you build a cool project on top of our moon app rebuild here if you have some cool features that you added or a project that you deployed or added to your portfolio that I would be very happy if you tag me on Twitter and just show it to me tag me ads either at coding in floor or flow and score Volta which is my personal account doesn't matter which one and then I wish you best of luck and happy coding take care
Info
Channel: Coding in Flow
Views: 51,855
Rating: undefined out of 5
Keywords: mern, mern project, mern stack, mern stack tutorial, mern stack projects for resume, mern stack authentication, mern stack full form, mern stack beginner, mern stack beginner projects github, express-session, mern typescript, mern cookie authentication, mongoose, mongodb atlas, react beginner, react beginner tutorial, react beginner project, express error handling, MERN TypeScript, MERN bootstrap, css modules, react-hook-form, react forms, react router, mern Coding in Flow
Id: FcxjCPeicvU
Channel Id: undefined
Length: 470min 17sec (28217 seconds)
Published: Wed Jan 11 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.