Build a Next.js Project and deploy with Vercel, Neon, Drizzle, TailwindCSS, FlowBite and more!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
over the past few months I've become a little bit obsessed with nexjs and for good reason [Music] now I really like using react.js as a front-end component it's a really cool and easy way to just do little user interface elements throughout a project but one of the things I've always had a challenge with was communicating to the back end in a secure Manner and then on top of that managing State and doing all these things write and react so what next.js does is simplify all of that Nexus can actually do our back end and you write it almost identical to react.js so you actually have a fully integrated project that works back end and front end so you can build your own backend API if you need so third-party services can actually use your project but then you could also use your back end to communicate to a database which we're going to be doing using neon a serverless database service that actually sponsored this series but the idea here is to make it really robust simple and fast for your project to have reactive components on the front end that go really quickly but then also very very fast components on the back end that integrate super seamlessly to a front-end react.js project now this is hard to fully appreciate if you've never done it before which is why I want to take you step by step in making this stuff happen now I will say in a moment I'm going to go through a fairly detailed walkthrough of what we're going to be building and then we'll talk about the requirements of all of that of of the entire project specifically so you can actually get started now to me if you've never used react before this will give you a little bit of an introduction to react but the thing is we don't want to make things too complicated we want to have something practical and real that we can put in production and real users can use it we can have them log in we can have them sign up all of those things right so we're going to be doing all of that and I'm going to be taking you step by step to make it happen and hopefully make it as simple as it possibly can be to learn nexjs with all of these Cutting Edge features now my name is Justin Mitchell I'm really excited to have you here so thanks so much for checking it out and let me know if you have any questions otherwise let's take a look at that walkthrough right now foreign we're going to do a detailed walkthrough of what it is that we're going to be building but before we do the detail let's do the shortened version first and foremost we develop an end-to-end web application with users to shorten URLs right that's what happens here you put a URL in and it shortens it and make sure it's a valid URL with no Extra Spaces and all that you shorten it and what you get is a shortened link that you could do whenever you want with in this case we just re-render the page itself and then I also show you the ability to redirect it I also track every time you go to one of these links as well so that you have a general idea of what's going on when these links are being used and all that which is really really important I think so if you wanted to redirect it it's really simple to do that I just didn't do it to avoid spam because yes this is actually deployed on a custom domain something else I show you how to do now all of the code itself is available on GitHub so if you go to github.com coding for entrepreneurs you'll be able to copy this project however you see fit you can Fork it you can clone it you can import it however you want to do it but all of the code is here so be sure to check out this code as you go forward and you can also review all of the history of it to see all of the changes that have that happen and when they happen so any given lesson you'll be able to see the changes there as well so that's where the code is next thing of course is we actually use a serverless database service called neon this serverless database is incredibly fast we also use their JavaScript package for interacting with next JS and versel and Edge functions and all the cool stuff that comes there and so this is actually a really easy way to store all of our data and to do so in a serverless function which is fantastic for something like this project right so if you shorten all these links you don't need that application running all of the time you just need to running some of the time and that also means that our database only needs to be running some of the time so that's where neon comes in and does really well it's incredible how fast it is and I really appreciate them working with me on this one to make this project happen for you guys next of course we actually deploy it to versl and we do this over and over and over again through GitHub right so all of it comes through GitHub which is also pretty cool so as far as the details are concerned we actually use next.js for this right so next.js does a back end and our front end which is cool we use app router which is The Cutting Edge version of nexjs although you could use page router 2 if you wanted to we just don't cover it we also deploy in versa like I said it also builds our application so we just need to push it to GitHub and then Versa does the rest with that we use Tailwind CSS to make this look good don't worry if you don't know Tailwind we just copy and paste a bunch of classes here to make it look better I don't really go into that much detail there because there's also flow byte that we use that just makes all of that that much easier as well with a bunch of examples to actually run that and then you will need a database of some kind using neon works really really well with for sale they even have it on their home page so it works on versel's edge functions so one of the cool things about this too is when we look at our project here what we can see in any given deployment as we've got these functions here so all of these functions right here work a little bit differently so if we go to API links we see that there's this Edge runtime which means that it's going to run as close as possible to your users the people that are actually going here and it caches things really really effectively because of next.js which is great but it also presents a problem using all kinds of databases which is why neon has optimized to work really well with these Edge functions and their client which is why we end up using them and stuff like that so in the code itself in the actual project itself we see that this is how you just declare an edge function you just change the runtime and boom now all of these will run on the edge which is great this makes things a lot easier what else is cool about versl is that we can declare different routes based off of the page and we can actually render database related data now if you're familiar with react.js in the front end you'll realize that you actually can't do this you can't call a database function directly you have to call an API which then calls a database function that part is actually not different the the actual client side the front end react still calls an API it just so happens that the API is in the same project because of next.js so it actually makes all of this really really seamless overall and so what we see in our code here is we see a mixture of front in and back-end code server components and client components and you can actually look at the like the UI for example this nav bar here at the very top it just says use client and then we get all of the react related things that you might be interested in which is like use State use effect all of those sorts of things can be done inside of this component and then we can actually bring that component into our layout and we can just render it out look at this is not a client component this is a server component it renders the client component really really effectively which is so so cool now of course we talk about all of this stuff we go into it in a lot more detail we show you how to actually use forms both with react and without react we show you how to actually do authentication this is really heavily based off of well sure we Implement a form to do the authentication on the user side but the back end needs to be as database driven as possible with sessions with schema data actually having our own design table for the user themselves password utilities that actually hash the passwords and do all that and then also that work on the edge functions as well we also validate our URLs which is you know to make sure that we actually have real URLs going through in there and then of course we store all this data using API routes which is something we talk about as well so all the different API routes and the HTTP methods that we can handle so there's there's a lot to this project even though the web application itself might feel simplistic it actually sets the foundation for you to build pretty much anything because being able to submit data on any given you know web location and then submit it and have it stored directly to a user is basically what all web applications do so this really gives you that fundamental understanding of how to actually build web applications with users with logging in with registration all of those things that you really need to be able to store and Associate data as necessary and it does this incredibly fast and this is a globally it's CDN all of that stuff it works really really really really really fast which is like shocking how fast it is and it might convince me to use nexjs for every project there is out there and then also of course using for cell and neon as a host yeah host in the database of course those things are also something we really want to do now the other thing about this is it cost me zero everything that I've done here I haven't spent a dime on and I can actually do this for some time before I actually need to start accruing charges because of how effectively and efficiently everything works it's so so cool but that's it for the walkthrough now we're going to look at the technical requirements to get this thing going which does take a little bit of installations and maybe some repetitiveness as far as what we're going to be using but the idea here is this project is meant to give you a solid foundation in next.js so you can start building your item applications there with users and all of that thanks so much for watching the walkthrough I realize a little bit longer let's go ahead and take a look at the requirements now foreign this project hinges on a few core Technologies and one of those things is nexjs now nexjs makes it so easy to build robust powerful fast and efficient web locations using react.js as well as using server-side Code that kind of replaces a back-end service altogether right so like you don't need express.js you don't need Django you don't need fast API you can do everything right with next.js which is really cool so if you've built web locations with react before this will be a really nice change for you it simplifies so much stuff and removes a lot of bloat as we'll see now the other thing about this if you've never built a web application before this will be a great introduction for you on those things although you might want to have some experience with JavaScript and using jsx of course if you don't I'm going to go step by step so you'll understand things as much as possible now the other Technologies we'll be using is Tailwind CSS now if you've ever used Tailwind before don't worry we're also going to be using something called flow byte which will basically do the work for us when it comes to Tailwind but Tailwind is actually integrated into next.js really really well so it makes it nice and easy but this will make our site look great or at least look better than just a Bare Bones HTML with no CSS and of course we're going to be hosting it on versel versel.com is a way to host your applications and of course they actually manage the xjs they have open sources they run this application which is great that they make it as efficient as possible to deploy your next.js applications now one of the other things that all applications hinge on are databases and of course neon is going to be the database we're using which is a postgres database now full disclosure they of course sponsor this series but this is a fantastic way to store your data in a serverless environment now we'll talk more about serverless but the idea is it's more efficient that's one of the key things here is efficiency and simplicity so much of this to me is efficient and simplistic or at least simple as it can be now to get all of this stuff working correctly the first thing that we need to install on our local machine is node.js right so you need to have the LTS 18.16 of node.js now if you're new to all of this if this is like brand new stuff you might want to pause right now and install 18.16 from nodejs.org now this should also work for Windows and Linux directly from the node.js.org website there'll be installations for that however there is a more advanced way to do it and that's using NVM so NVM if you do a quick search for this this of course will be linked as well in the description but the idea here is NVM is just a command that you can run to install different versions of node.js much like the LTS itself which is just simply NVM install LTS that will always install the latest LTS which is what I do that's what I use and that's what I recommend now in order for next.js to be deployed to versl we also want to use pnpm this is a requirement to make this whole process more efficient and more effective efficiency is the name of the game here so what we've got is we need to also install pnpm this is actually fairly easy to do and there's a number of ways to install it you can use a script if you want and and of course you can use Homebrew you can use coco if you're on Windows you can use the windows subsystem for Linux or you could use Powershell there's a lot of different ways to get pnpm installed on your machine much like there's a lot of ways to get node.js installed now a few other things that we definitely are going to be end up using is vs code Visual Studio code is how I'm going to be writing all the code I recommend you do the same it's a fantastic text editor of course if you already have a preference you're not going to listen to me anyway but if you're new to this definitely use vs code there are a lot of other ones out there but vs code I think is the best of the best and it also integrates with Git Version Control really well so Version Control is something you're new to this is something else that vs code makes really really easy for us so you're going to want to make sure that git is installed on your machine as well which I'll talk about it when we actually need to use it again and then of course finally we will be using flow byte as well to make our Tailwind much much better and just a quick overview of that if you just snap a screenshot of this these are the things that we'll need for this project but that's it those are the requirements so install node.js now and the way you can check that nodes working is you do no dash dash version and there's my node version I also have NVM in here and that also means that I have npm whenever you install node you get npm and I also have MPX installed which is a way to execute packages we'll talk about this in just a second when we create our project and then also I have pmpm and that is installed as well or at least it's not installed so I I think I actually left that for us to actually install it together but the idea being that we need to have all of these things installed when we actually need to use it right now we're going to be using npx so let's take a look at how to create our next JS application foreign if you're eager to get started go ahead and run MPX create next app at latest in a location that makes sense to store your code if you are ready to go through this with me let's do that now first and foremost you're going to have to open up terminal or Powershell if you're on Windows and not WSL you're going to be using Powershell if you're using WSL Linux or Mac you're going to be using terminal this is your command line in a little bit we're going to be using vs code instead of terminal or Powershell so it's okay that we just do this for now just so we can get our first app up and going so I'm going to go ahead and make a new directory in my user's root folder which is what tilde slash is doing here in there I'm going to make a folder called Dev this is where I store all of my projects and then I'm going to go ahead and navigate into that folder and now I'm going to go ahead and run MPX create next Dash app at latest and hit enter okay so I'm actually going to cancel this out real quick because what you also want to do on a regular basis is run npm install Dash G and that's npm at latest we want to run that to make sure that npm is up to date and also pmpn just to get in this habit of installing these packages I do this all the time already so I didn't really do much here yes it says it changed things but I've run this like four times already and it didn't actually do much of a difference so after you do that then you can go ahead and do the create next application in my case I'm going to be naming my application jref and I am not going to be using typescript if you're familiar with it obviously go ahead and use it using typescript compiles into JavaScript but it's a little bit more complicated if you're a beginner or you've never used nexjs before next up is eslint yes we'll go ahead and do that Tailwind CSS absolutely we want to use the SRC directory yes I think that's convention overall for all kinds of programming languages so let's go ahead and say Yes app router absolutely the same is so so cool I'll show you soon next up we're going to not customize the default import Alias and then we're going to hit enter and this of course is going to install everything for us it's also are going to create a bunch of configuration files for us and some of our early code for us so now that we've got this let's go ahead and navigate into that new folder here which of course you could always just copy this right here and CD in that way it was the same thing but if this path is looking weird to you then perhaps you ran your you know create next application in the wrong spot that's pretty much it which I definitely have done before too so no worries if you had and notice it also initializes a git repository which is great it does a lot of stuff for us so now that I'm in this folder I can list things out and I see everything that's going on here even if you're not familiar with post CSS or Tailwind or nexgs or or package.json this is just describing the project with the various tools that it's using the various dependencies like Tailwind CSS and post CSS right package.json on the other hand is one that is used in pretty much all node.js projects package.js son is something that we'll need and we also need to run pnpm install right here so this is just so we have the lock 4 pm PM pmpm can be what we managed to install packages going forward I'm not going to install very many of them but when I do we will use pmpm and so if I list things out now I see that I have a pmpm lock so these are just lock files these are files that are updated automatically when we do installations or major changes but without all of that out of the way let's go ahead and run P npm run and Dev and hit enter now what this is doing of course is it's looking inside of package.json for a script called Dev we'll see this in just a second but the idea being that we have a server running on Port 3000 on our Local Host so I can copy this and bring it on over into you know my browser here and there you go hello world next.js is working fantastic so that's it that's how you started xjs application now what we're going to do is actually modify it slightly so you can see what routing is all about Nexus and what what convince convinced me that this is an amazing way to handle URL routing foreign things about nexjs is how it handles URL routes or URL Paths of course what I mean by that is like slash blog on your URL in this case it renders a 404 by default that is somewhat to be expected right so the page is not found now the way nexjs does it Harkens back to how websites really used to do it which was just a bunch of HTML and you'd have something like blog slash index.html and that would sort of render out that page now of course new sites web applications are a lot more Dynamic than that and then we can do a lot with these paths but this is I think where the Genesis of this came now a lot of web application development doesn't do it this way a lot of them do it in a little bit more of a complicated way where maybe there's a single file that has all of the different paths you want to support however when xjs does is so cool and I want to show you that now the first thing is we need to close out our server that we have running in our terminal we're going to clear this out and we're going to open it up in vs code if you have the vs code command line tool installed you would just do code period inside of that working directory or you would open up a new window in vs code with control in or command in and then you would go into the explore here go into Dev into your folder and open that up okay so naturally we're going to be working in this pretty much going forward I probably won't open up the native terminal like this or Powershell pretty much ever again throughout this project I also want to save this folder uh save this workspace to this folder go ahead and add this up and we should get a vs code workspace file in here so we'll go ahead and save workspace as and we want it to be in the root of our project and of course it's going to be jref cool okay so we now have our project all set up let's go ahead and take a look at how it does routing now the first thing you'll notice inside of app so all of our next.js source code is inside an app there are configuration things we'll look at again but right now just inside of app here so if you think of SRC slash app as the root of the application itself you're on the right track okay so what we want here is we want to have the routing take place so I had the example of a Blog I love how Nick JS does it look at check this out you just type out blog and then you create page.js and then you're going to export a default function and I'll call this blog page and then you're just going to return HTML look at that that's it I mean it's so cool so now if we go back in here uh oh yeah I don't have it running again so I need to run it again right so if I kept it running in the terminal obviously I'd be able to see that page rendered but I'm going to go ahead and open it up in vs code now I actually use the terminal application in vs code pretty much all the time now one way to do it is to open up the terminal a new one with this command here or what you can do is toggle it itself so instead of view I see the you know command and then basically tilde and that's how we can toggle this so if you get used to toggling the terminal because it's it's incredibly handy in any case we now have that toggled I can run npm run Dev and of course if you haven't used vs code before you might be like wait I didn't navigate anywhere well vs code by default the terminal itself every time you open a new one it opens in the root of the workspace right so that's it right here so this workspace is exactly where we need to be to run those pnpm or just npm commands from package.json which of course are all of these right here all right great so with that in mind we've got the server running I can now go back into my blog page and I can see Hello World now this repeating thing is a bit strange and it's actually related to the CSS as you might already know but the idea here is how simple it was for me to create a brand new page now it's also very simple to solve this issue if I go to layout.js I see the standard HTML stuff what do you know so in here I got this inner class name I can actually change this with some string substitution uh just slightly so I'll keep that inner class name that's there and I'll also add NH screen this is a Tailwind class for making sure that this element has the minimum height of the screen so I save it and a refresh in here and what do you know there's hello world and if I come back in here I've got my next JS stuff pretty neat right I've I now see how to do routing I also see how to change the layout a little bit right in other words every time I do routing I don't actually have to write all of the HTML all over again which we could verify in many different ways so let's like one of the ways was this CSS another way we could do and let's just put the head in here and say title and say Hello World save that refresh notice it says hello world up here on the blog now and if I go back it's nothing but it does say hello world so that layout is out allows me to do all sorts of really really cool things now I actually already have the title up here and it's not something I need to put manually like this I would actually put it inside of this metadata right here and say hello world or more specifically the name of my project jref.io we can refresh in there and there you go so now you've got this head thing now there's a lot more stuff we can do in that front foreign how to handle a URL route to render an HTML page in the term of blog's hello world granted it's not a very good HTML page but it is an HTML page nonetheless let's take a look at how to do a basic API request so to do this we're going to jump back into our app we're going to create a new route for API and inside of there we're going to go ahead and create a file called route.js now with the the point of route.js is to actually handle different HTTP methods so like git or post for example you could have other ones in here as well but these methods are really important when it comes to doing any sort of API call so to do this we're going to go ahead and import our next response and this is from next slash server and what we want to do is actually create functions for the methods we want to handle so for example if I do export async function get all capital this is where I can return a next response let's say for instance some Json and we'll go ahead and pass in an object here of hello and World okay so this is an object it's a dictionary another way to look at it but the idea being that this will now handle git if we wanted to handle post we would change this to post you know post is like for form data or an API Json post data both things are correct okay so what we want to do is we'll say hello post right so we're going to have both of these endpoints and they're really really easy I just created them granted we need to do more things with them but this is how easy it is to make API responses inside of next year's now everything looks like it compiled successfully so let's go ahead and take a look at those endpoints so I just did Slash API so in my localhost if I go to slash API I have a plugin for Json rendering on Chrome but that is my Hello World there so if I see the raw you'll probably see something like this if you don't have that plug-in but that's the idea now we can also copy this and jump into our command line so just open up a new terminal window here and run curl and we'll go ahead and do Dash capital x post do Dash capital L I'll explain this in a second we'll paste this in and hit enter it now does that hello post if I change it to ABC and run that again same thing so this is a proper API request right this is from my local terminal to my server right so if we actually had this deployed I could in Theory actually call that same thing now with this slash or this Dash capital L does if I put a trailing slash here it will follow the redirect that ends up happening if I don't have that trailing slash if I do curl with the trailing flash it tells me where it's going to redirect to that's it okay cool so um very easy to create these API endpoints now we actually use these API endpoints in conjunction with our statically rendered react pages to actually work with like your database for example so what we'll end up doing is like our blog page if our blog page needed to get a bunch of uh URLs or a bunch of blogs from the database it would actually call one of these apis to then get that data which we will see of course but at this point we need to see one more way of doing URL routing and that is being a little bit more Dynamic inside of the URL itself so like for blogs there's different blog URLs we want to see how we can actually render that out as well foreign now that we can actually handle URLs we need to handle Dynamic URLs and what I mean by that is normally when you have a Blog you get a URL with blog slash hello world or blog ABC or whatever and that page will change based off of the URL so that URL is a bit more Dynamic now we could manually do each one but that doesn't make any sense where it would make a lot more sense is there's a dynamic one that then does a database lookup which is exactly what we want to do so the way this is done is also pretty clever so what we do is we create another folder wherever we need it nested as far as the segment is concerned we put brackets around a variable name in this case I named it slug but it can be whatever you'd like slug is what's often referred to as this segment or the URL path that is for a blog post and then in there we would do page.js and just like what we've seen before we would export a default function and this will be our you know blog let's say blah blog post detail or dynamic something like that and I'll put in params here for a moment and then we'll return Main and we'll just go ahead and say H1 hello world okay so what we'll get through this page is parameters being passed those parameters are based off of this slug here so if I do console log and params I should actually see some of those so to take a look let's go ahead and jump into our page here on blog ABC it says hello world let's change this to hello detail View and there we go now I just console logged it if you're used to using react in the client side what you would naturally do is go into inspects into console and of course you won't actually see anything logged in here instead it's actually blogged in our server on the server side it will actually log out the parameter itself so the params are slug ABC now we can Nest this again right so I can actually come in here and say another let's put brackets and say another and once again I'll copy this page.js and hello detail sub view something like that and this is blog post sub detail and then if I go into changing that to ABC whatever it will show me that detailed View and we come back in here we see those two different parameters here now in xjs these are called segments so each one is a segment and they come in in some sort of logical manner now you actually don't have to do it this way what we could do is we could also put in three dots in front of here so if you do three dots with those brackets this another will never be accessed so if I refresh in here it should now just say hello detail view it might even create an error because I've got two things that are basically conflicting with each other so let's actually get rid of this one right here we will move that to trash and then now refresh in here and I got hello detailed view just like that and now I see those two segments so you can kind of go either way now I think this catch-all or almost catch-all is fine in general for a number of things but what I would tend to do is really just do the single Slug and then have the nested uh you know dynamic segments as I see fit now this also works in an API route it's not a whole lot different so I'm going to go ahead and paste this in here slug we're going to change it from page to route I'm going to go ahead and grab the git route we'll just do that single one and we'll paste in here this does have parameters that come in it has a request that comes in as well as context we can log out both of these things so log the request and the context itself so we can see what's going on with any given get request and I'll actually Nest this one further I'll go ahead and API and posts and then I'll bring this into that just like that okay great and we'll come back in here and we'll do API posts and ABC we'll hit enter it does render it it says hello world and we see all of the request stuff first there's a lot of things related to the request and then we've got the context that's being passed in here very similar to what we just saw so we've got parameters and slugs so you'd actually be able to handle those things from there right so basically you would say const and this is going to be params and it's going to be into the context itself and then const and Slug and that's equal to params itself as well so now we could just say the slug is equal to the slug or whatever is coming through and now we see what that is and if we change it at any time what do you know of course you could also make it an ID you can make it individual numbers you can make a uuid there's all sorts of things that you could put in here to make this Dynamic but having these Dynamic URLs will allow us to actually look things up in our database a much much more effectively and much more efficiently now of course you might be wondering like why are these slightly different right so why does this parameter different than this one right and that has everything to do with how it's being rendered and how it's running so this is a lot more like a back-end server because we're handling a method a specific method whereas this could easily be changed to something different and it can be changed to a standard react client-side by just saying use client as a string at the beginning and then if we go into the blog and go into slash hello world we now see these parameters being console logged right there right so just one slight little change and it turns from being like a statically rendered one on the server side to being a client-side rendered one that just gives us a little bit more um more access to things that we could do from a user interface perspective which is also pretty cool but as far as the API route we can't just change this to a client-side thing that just doesn't work this will always run on the server foreign go ahead and do an API endpoint request so back into this blog here we're going to go ahead and look at the posts so inside of the root of the posts I'm actually going to move this route here just like that so I've got posts route and then post slug so to verify this we can go ahead and use Curl again so curl and we'll just leave it at get so HTTP colon slash localhost 3000 API posts hit enter it should just say hello world so I can actually say items and actually pass in some items here and I'll just go ahead and do something like ID one and title being hello world something like that so if I run this again I should now see a little bit more data coming through the post itself I'm going to go ahead and comment this out we probably won't use posts to create data or this endpoint to create data in fact we'll move it towards what we actually want to build but for now we're just using this as a good example of seeing how to do a request inside of a actual page so going back into our blog page here we've got the blog page itself we do have a slug itself going on as well so both of these will work similarly and what we want to start out with is not using the client we want to keep it in the back end we want to keep it as a server-side rendered item as you'll see in just a moment so the first things first I'm going to go ahead and go into the blog page the Hello World blog page this is where my list is going to be so we're going to create a brand new function this is going to be an asynchronous function and it's going to be get data and I'll go ahead and pass in what it is that I want so number one I'm going to go ahead and grab my endpoint so my API endpoint what is that and that's going to be a constant we'll just say const endpoint equals two and in this case we'll go ahead and do HTTP colon slash localhost colon 3000 slash and we want API posts cool next up we're going to do our response so we'll do res as in response equals to a weight fetch of this endpoint now this is why we're using async is because of fetching it's going to be an asynchronous request it will request this endpoint and once the request is done it will return back and then the you know the rest of the function will work correctly basically we also want to check if the response is not okay which is what's happening with this condition then we're going to go ahead and throw an error and we'll go and say failed to fetch data we'll talk about handling these errors in a little bit but we definitely want to do it this way otherwise we'll just return the response of Json now this actually assumes that the API endpoint does respond Json data because it might not so there are ways to check that as well but it's just outside the context of what we're doing here we'll just assume that it's going to return Json data because well that's how we've actually set up our API itself is it's going to return Json data cool so back into the main blog page here we've got this data so what we want to do is now change this also into an asynchronous function by just putting async here and I can now say cons data equals to a weight git data okay so this is how nexjs recommends that you organize your requests is to make a function to handle the request and then inside of the actual render page you would do something like this and so to see this data I would just go ahead and use these curly brackets and then say n and data we'll do json.stringify and of that data now what stringify does is just allows you to display this data versus try to iterate through all of it which is something we'll do eventually but just not yet okay so now at this point we should be able to get data this is the correct API endpoint and if we come back into our blog our main Blog Page and refresh we now see that data coming through here which is great so another thing we could do is say cost items equals to data and and data items and then data we could dot data dot items or we could have AMT list and then again same thing we could just do Json stringify of those items and now it's actually showing me all of that data and of course I can iterate over that as well so we could do items.map and this will allow me to do all sorts of things with the mapping function itself so the first one is going to be the actual item and then the index value so we return this to do something like this now this is all very much react.js on how react.js renders things so we'll go ahead and say key equals to post Dash dollar sign 80x and then we'll just go ahead and render out the item dot title I believe we had so we say that and let's make sure we're closing everything off in here with these curly brackets there we go and so now I've got the posts coming through so let's go ahead and do posts and those are coming through granted they're off to the side in a way that's kind of awkward so let's go ahead and just change the layout a little bit and I'll do PX 10. that means padding on both sides of 10 and now I can see a little bit better don't worry we'll fix that in a little bit but that's how we do a API request right there are more things that we could add to our fetch request itself and we will talk about how to handle forms so by default this will be a HTTP get method which not surprisingly is exactly what a route is that's actually why I commented it out so there's no confusion as to how it actually did the request it did a get request by default as fetch does and this is just how you'll handle it now this is not how you would handle it with use client right so let's let's actually change this to just use client hit save and we'll refresh in here and wait a minute it still did it it still worked let's do console log items let's go ahead and restart the server it should have restarted on its own but let's go ahead and do it restart refresh whoa it's working so there are certain things that actually overlap depending on how you end up doing it in this case we don't need to use client especially when you're doing API endpoint requests you definitely don't want to do that you want to do that on the server side um so I'm going to leave it off use client there are cases where you can use it where it's not on the server side but in this case we're going to leave it like this and you can see all the requests coming through from it and of course when I do keep it on server side the console log changes it's fantastic really really like next yes so let's keep going doing API requests is pretty simple to do but the thing is with API requests at any time the likelihood of causing issues or having errors goes up a lot right because you're kind of depending on something else working correctly so for example our endpoint here if I change this to ABC that's already an error that is not going to work and if I go back into my page I get this runtime error unhandled runtime error more specifically now this is more likely to happen throughout right especially if you're using a third-party service which you might right so a third party API request right so what happens there there's going to be errors servers go down you do the wrong request you put the wrong URL in all of those things so we need to learn how to handle these errors so that's what we're going to do now so I'm going to change this to localhosts and it's still an error and we just want to actually handle this now to do this we're going to go in the roots of the app and I'm going to go ahead and say error.js okay so this is going to be a react client-side component so that means we need to say uses client or use client at the very top of this file and we're going to go ahead and do export default and this is going to be a function of error and we can take it it actually passes in parameters of error and reset which we could review but this is all in the documentation it's very clear and straightforward and in here I'm just going to go ahead and return a div that just says you know H2 something went wrong okay great that's all we'll do so far and also console log out what the error is okay so we saved that we refresh in here now it says blog something went wrong let's go ahead and look at the console remember we're using use clients so we should be able to see potentially something in here uh but we're getting fetch failed that's that looks like that's what the error is so let me just say error is and save that refresh and sure enough error is type error fetch failed okay great so clearly something's wrong now we can actually make this a bit more robust by using things related to react itself for example this is directly from the documentation you can import use effect which is a react hook that will allow you to respond to if an error is happening so in here we'd say use effect and we pass in an arrow function with the error itself and this is actually where you will want to console log the error right here okay so this use effect method is possible because of use client and these error handlers have to be in here just like that okay so now we've got our use effect put the error console log last this is where you could then send this to some sort of reporting service or maybe back to your API that then triggers off an email to you or your team or a slack message or something like that that's where you could then do this right the next thing too would be to maybe reset or retry this right so to retry this what we could do is we could create a button here and I'll go and say retry request something like that right and I can actually create a click Handler and we'll go ahead and say const retry request Handler right and this is going to be a function here that will just call reset okay so we grab this right here and we put this on click and we'll retry the request refresh in here if I click it of course the error keeps happening so that's pretty nice now this right here is related to the development process of nexjs but the fact that I can do this is pretty cool so what I'm going to do is actually keep this I'm going to make a new blog copy and I'll just call this error so at some point we could test this out and I'll remove uh the slug I'll just have slash error so if I go in here slash error there's that error the actual blog post itself that page we'll go ahead and put it back to what it was which was localhost so then when we go to blog it actually works uh for this example okay great now there is something else that's really cool about errors is I can actually bring in error.js and right into the path itself and I can change it in here so something went wrong on purpose exclamation mark now if we go into error something went wrong on purpose let's go back into Vlog and we'll create that error again just to show the differences here um we refresh into blog now something went wrong so so just another way to handle the request so you can handle errors at every single endpoint which is really cool or you could just use the general one which is what we started with anyway both are fine and in some cases especially like apis with the errors and stuff like that you might need to actually look at it from the actual endpoint itself right so in this case of this error here if you actually were using a third-party API service and an error happened you might say that like you know uh let's let's come back in here to this error with it you could say that something like open AI is not working try again right as many of us would be potentially creating stuff with openai something like that right it's pretty cool error handling is very very simple okay we want to get in the habit of pushing this to GitHub we haven't done it at all because we never set it up now if you're familiar with this process by all means create a new repo add it to your local project and push it I'm not going to be doing it that often but those of you who are a little bit new to this process this is for you so the idea is you go to github.com create an account and then we're going to go ahead and click this plus item and new Repository in my case I'm going to call it jref.io because that's what the URL will be you should call it something else you could call it you know next JS jref or something like that right well mine's gonna be jref.io so a tutorial on creating a URL shortening service with next JS Purcell and neon something like that okay cool so we'll leave it in as public because I want it to be open source but by all means make yours private if you don't want anyone to see it you don't need to initialize it with anything because next.js already did that for us perhaps you want to add a license later which I probably will do if I haven't yet please let me know but anyways we're going to go ahead and create this repository here and create it and then we want to grab this right here okay so the important part here is we jump back into vs code open up the terminal I'm going to go ahead and open up a new terminal window and clear everything out and I'll do git status what we see in this git status here is all of the files that have not been committed yet all of the files are pretty much it's pretty much everything but if I do git remote or give remote Dash V or lowercase V I see that there's no remote there if I do get log I see that there is one single commit now this was done I think automatically when I created this application right so it actually did commit all of the files that I needed it also has something called a git ignore which is ignoring all the files that I don't want which is a lot in my case I also do not want something called DS store I'm not actually sure if it's in here oh it looks like it is good thank you next chance um so DS doors for Mac users but the idea being that you want to make sure that you ignore as many files as possible one of the big ones would be node modules this is something that is done by default with this project but if you happen to do this manually you want to make sure you do not commit your node modules because it's a launch it's all this third-party code that you just don't want to submit nevertheless we have one actual commit I'll explain what that is in a second and then we do not have a remote a remote is really just your repository your remote repository on GitHub you're creating remote repositories that's what they are remote from you your local repository is the one we're looking at here your remote one is wherever you host this code GitHub gitlab bitbucket there's a lot of places to actually host your code so this URL right here is the location where it's hosted no surprise there so we're going to go ahead and do git remote add origin and then we'll go ahead and put this one in here now of course this is also right here right there right and we're going to go ahead and hit enter now I will say on your git push this next aspect if I hit git push I can send mine in yours might make you authenticate with GitHub there might be extra steps that you'll have to do here in order for you to push this to GitHub which is fine if you're having issues there let me know but the idea being that we can actually push this code into GitHub if I refresh in here it's everything up to the first commit or the most recent commit right so if I look at my code there's not a whole lot going on it doesn't actually match here now this is where vs code comes in it makes using gits really really easy this part right here if I click on this I can actually add all of these things in and say up to lesson nine or something like that error handling right so that I can commit that and it's saying there's no stage changes on here would you like to commit all of these so we're going to Stage them and commit them I'll explain that to you we'll go ahead and say yes and then I'll go ahead and sync the changes down there and say okay okay um cool so there's the other thing is we can periodically fit run git fetch which would pull the code from our repo which we don't necessarily need to do but down in the bottom right underneath me there is the way to refresh uh or synchronize your changes with Git and now if we go on to GitHub we can see all of that code is in there now right it's all open source so you can always look at this as well by looking through the commits and all that I most likely will not use branches for this particular project but if you go through the history you can see all of the different commits so a commit is two things okay so let's say for instance I want to change my main home page I'm just going to get rid of a bunch of stuff here so I'm going to get rid of this this and this so that first div we'll get rid of that I think my server is still running let's just verify it is so let's take a look at what I changed refresh in here looks like nothing changed so far next.js is still there I think I did get rid of one thing but let's get rid of that there we go and I'll go ahead and say H1 and jref.io is coming soon cool so I made a change refresh in here there's the change okay so I changed the title of it so the process for git is this simple first of all you go in here you could also do it in the command line but I'll do it uh right here on the vs code you go in here and you're like Okay so this changed let's take a look at what changed cool I see that I deleted a bunch of stuff that's what that red indicates and then if I scroll down a bit I should see some green or somewhere in here is green there we go there's the green that's what I added so I deleted all this and then I added that so I can go ahead and Stage this which means hey get this ready I want to commit these things I want to make them permanent changes on the remote branch and then I'll just go and say changed home page title on lesson 10. or rather I'll go and do lesson 10 change to a home page title we commit that then we sync those changes I'm going to go ahead and save this action will pull and push so if there were any changes on the remote already from somebody else it will pull those down make sure that we're all good with those changes and then I'll say okay and now what I'll do going back into my application here I can refresh in the commit history and I can see what happened in the in those changes themselves right which is really nice so we can see the command we can also see what changed what was removed what was added just like I did on vs code so using git is something that you'll definitely want to get used to if you're not already but the idea here is we want to regularly be updating how our project is working and you want to do it as small as you possibly can I will do it after each lesson although I'm not going to show you me doing it right I'm I'm showing you only just one time other than Maybe when we push to versel and actually get this into production which is something we will do next but the idea being that now we have our application running and everything is working in the sense that it works locally it is stored on git and it's now ready to put a production version in production so let's see what that looks like next foreign of continuously deploying our application all of the changes we're making we want to deploy them regularly before we actually can deploy our first version we want to get rid of all of our fetch calls which we'll talk about more later but for now let's go ahead and jump into our vs code workspace I'm going to do a quick search for fetch which would be command shift F or Ctrl shift F and then we're going to go ahead and just comment out these get data items now one of the things you could do is just comment this part out and just return a dictionary like that right and you could also say items and an empty dictionary that way if we need to bring it back it will still work but everything else in here generally speaking is working okay and then we'll go ahead and do the same thing here and then comment these out with command slash quick way to comment it out okay so now we'll go ahead and do git status and we see that these are the things that are have changed we'll go into our source control on vs code we'll add these two and we'll go ahead and say removed fetch we'll commit it we'll sync those changes we'll go and say okay pushing them onto GitHub which we can then go into GitHub and verify so we're going into your repo there you can see that it says remove Fetch and it was now okay with all that done it's time to integrate our GitHub repo with versl so regardless of how you logged in this is the process we go into new project import git repository you're going to scroll down here and you're going to add a GitHub account you can obviously switch provider and I think if you logged in with a different provider it would show you that in our case we're going to use GitHub and then we're going to go and add our GitHub account right so by coding for entrepreneur's profile the repositories I don't need all of my repositories in here I just need the jref io repository which is exactly what I'm going to use and just that one I'll show you in a moment how to uh revoke that as well so once we have that we can then of course we can add other GitHub accounts into our local account but there's our project right there I'll go ahead and import it and I'll use a lot of the defaults now versel created or manages next.js so the defaults are probably just fine you probably don't need to change much here but there are other framework prefixes that you can use or presets that you could use so I'm going to go ahead and hit deploy it's really almost that simple but of course now it's going to build it it's going to do all sorts of things related to nextjs that could fail so if you have that fetch still there there's a good chance that that could fail now while that's running I'm actually going to go back into GitHub and show you where you could delete this so inside of your project here or your profile go down into settings and you're going to want to scroll down into applications and in here installed GitHub X apps right here right so on my coding first account I always remove these after I am no longer using them uh and that's true with a few others as well you can get in that habit also but it's really up to you but that's the point is you can actually come in here and reconfigure this to allow other repositories in here as well so for some reason it's not working with versel you could just come in directly on GitHub and do it there but more likely it will be working on Brazil okay so back in here our project takes about a minute I would say at a Max two minutes to build and deploy so it's doing all sorts of things look at it's checking out all the routes everything that we've gotten there it's building all that creating everything that neces that needs to happen and then it's going to go ahead and deploy it so if I go back into my root project here I see or the roots of her cell on the dashboard I see that my project just close probably uh and it now finally has a production deployment and I can open it up by going to visit here and there it is right uh and let's go ahead and try it out just like that what do you know pretty cool so uh it will start to speed up as far as the build unless you change a bunch of things but let's go ahead and change one simple thing going into page.js here I'm going to go ahead and get rid of this div I don't need that anymore and we'll do git status get add oh yeah I remember I said that I would be using Source control on vs code so back into vs code we'll go ahead and add this one we're staging it we're getting ready to be committed and we'll go and say update home page commit and we'll sync the changes which is pushing and also pulling and now we'll go back into versel here and into our project under deployments we now see that a new deployment is going granted I had to redo one but the idea being is it's going to take I don't know 45 seconds to a minute or so before the new one comes out and we can take a look at the Domain here and then surely this will be an exclamation mark which is the minor thing that I changed but the idea being that now we have the ability to continuously integrate and get it right into production which is really cool and how quickly it happens is also very cool so the point here now is we need to figure out a way to send data to a database so it actually is there whenever we need it so that we can also retrieve that data and then maybe add user accounts and stuff like that but all of those things are just stacking on the features that we want our application to end up having but at this point we have the ability to at least get it into production right and so about a minute it's into production and there's that exclamation mark and it's working it'll probably be working on your end as well so all of those other things are really exciting and let's go ahead and start looking at how to do it foreign it's very cool that we have our app in production but the problem of course is that we aren't able to get data or seemingly able to get it yet so what we want to do is address the first problem with how we were getting data in this one and the next one we'll talk about caching with fetch so let's go ahead and take a look first off the get data function the biggest glaring weakness as some of you might have already noticed is this endpoint right here this is absolutely not what we want you can't access localhost from production or at least there's no easy way to do it and it's probably not a good idea to even attempt to do it so we need to we need to solve this one so when I say production I also mean the build process the build process will attempt to build this how it's currently designed with how fetch is currently working it will attempt to automatically get this data it will it will pre-render out this data for us which is good in some cases in this case it's not necessarily going to be good as we'll see but the idea here is we need to change change this localhost really we need to change the protocol and the domain we need both of those things to be fixed now next.js comes out with a really clever way to do this so inside of our project here we can use a DOT EnV file but more specifically.ub.local and you already notice that it's grayed out this is because EnV is in the get ignore because next.js just supports these so the question of course is what e and V should we use well one thing that you could do is you could say public domain or like my domain or something like that is localhost you know 3000 and the cool thing about this is by default I could probably log this out let's take a look so we'll do console log and it's process.env always process.env dot whatever environment variable we have which in this case is public domain so if we save that and maybe refresh our local page it might render out so I might have to refresh the entire thing here so what it's doing is not rendering out that local no yeah so look it rented out localhost so if I change it to ABC for example it shows me ABC great so that's working correctly so we've got our public domain and we can now reference this on another file so this will never be checked in to get we'll never put this into Version Control so presumably using something like that we could then take this same environment variable the key value pair so the key is public domain the value is localhost 3000 without the quotes um and we could probably even used it without the quotes inside of EnV local that should be probably fine but the idea being now is I could then come into versel into our settings here scrolling down into environment variables and I can add it so public domain and then well what's the public domain now this is where versel offers some built-in environment variables so instead of using public domain we could use something else now at some point I will have jref.io but really I will probably have https jref.io and all that so I wanted to be able to change based off of whatever domain I actually have and I don't want to have to hard code it I don't have to remember it so like I said versel gives us environment variables it gives us system environment variables this is true with a lot of production environments that will give you environment variables for your runtime and some of these environment variables will work during build time as well the one we're about to use will work during build time as well so what we see here is we've got these system environment variables so there's resell whether or not it's during the build processor continuous integration the environment it's in the Versa URL these things are all great but these are more for sale specific we want framework specific ones and more specifically for next.js of course but there's no a lot of other ones and I'm sure there will be more to come so the the things that we need are the environment that's currently running which in our case will eventually be production and then also the URL that we want to use this does not have the protocol right as it says right here to not include the protocol so these are the environment these are the actual environment variables we want to use locally as well so instead of public domain we'll use next public for cell URL and then we can render that out and here and we see that right there now the other thing that we can also think about is the next for sale e and D which I'll put up front as well and this one is going to be development really personally I think it's anything but production is the important part here as we'll see when we actually design the final you know endpoints that we need this right here okay so now that we've got those environment variables let's go ahead and put them into action in some form so inside of app we want to make a folder called lib and inside of here I'm going to go ahead and call it get domain.js so what we want to do is we want to export a default function called git domain and all I'm going to do here is I want to return basically this part of the domain not the path just that right so localhost but of course I don't want localhost I want this to be based off of those environment variables so the first thing is grabbing the protocol and this one I think is fairly simple it's process.env Dot and it's going to be this right here the next public for sale underscore e and B all caps just like that and I really want to see if it's equal to production and if it is we'll go ahead and use https if it's not we'll go ahead and use http and this allows me to change this protocol in here to whatever that value might be simple enough the next one of course is going to be our domain so const domain and it's basically the same thing except we don't need to set it equal to anything we are just going to go ahead and grab the URL itself and then we'll just repeat this process right here and instead of HTTP we can just bring in localhost and then we change this to the domain correct so fairly straightforward function that's going to check whether or not it's in production if it is it'll use https it's also going to check whether or not this environment variable even exists if it does just use that one otherwise we'll just default to localhost you know maybe in production you'll eventually just default to the production URL because if you accidentally make a mistake somewhere perhaps the default should be the production one because when you go into production that'll be something you'll want to do in other words change this to something like jref.io at some point but for now I'll leave it in as localhost 3000. okay great so the the to use it of course we just come in here and say import git domain and then it's going to be this is the auto fill one I like using the at app lib and git domain I much prefer that uh method for it so then I'll just do const domain equals to get domain and then we'll just do some string substitution here for this value right there and there we go okay so this still doesn't solve the problem it helps solve the problem a little bit but it's not fully solved yet so let's go ahead and Commit This and we'll see what the error is after it's committed so we'll do oh yeah so I want to go back into this right here and I'll just go ahead and say updated prod domain fetching and we'll go ahead and Commit This no stage commits I'll go and say Yes stage all of those changes and then I'll go ahead and sync them as well which looks like it has some syncing issues so I'll do git push Force or get push dash dash Force now the only reason I'm doing this is because I've been doing a bunch of different testings you should not have to force it right now I know exactly what I'm doing I had to test a bunch of things and that's why I'm forcing it okay so now with that pushed what we're going to see here is in our deployments we should still see an error right so what this error will show us is well it's going to give us hopefully something related to the Json data that's that's my hope I mean it's certainly possible that it actually doesn't give us an error because it is the correct domain but it's also possible that it will give us an error and yes so it gives us an error error pre-rendering this page unexpected token in Json and position eight zero so this error is related to fetch as well and it's something we'll address in the next part foreign that last part we saw that our fetching failed it was something related to Json data being Incorrect and I also mentioned this when we started building it but basically you might want to have a check after the response is okay we want to check if the response.headers dot get of content type we want to basically check if it's not equal to application Json and if it's not we're going to go ahead and return just in the items being empty what we had before right so we want that content type to be application Json to call this res.json that's pretty much it right the response.json so once we have that let's go ahead and add it into our deployments so updated uh you know git or fetch response and then we'll go ahead and Commit This and sync it okay so in theory this will maybe solve the issue for us maybe not but maybe we'll now it might solve the issue in terms of building and you know putting into production what what it might not solve what it probably won't solve is getting the actual data now this is where I think next year has something really really cool and how it actually caches these requests so while it's building this it's actually rendering things and it will go through and perform a proper fetch for us so if we wanted data to just store their cached until the next time we build it we can do that we can do that right here in how it currently is set up and that's because of the fetch caching options so we've got fetch caching options not catching but caching now what that of course means is it's going to go ahead and looks look up something and just store that in memory if you will to the next time it needs to be looked up in other words the next time it goes to that page that's trying to render out whatever that fetch data is so the default is force Force cash now this is a great default if you just are looking up something once when it's being built and that's it now another one now you can use this in other contexts as well but the way this functionality works is it will happen when it's being rendered now the the other one the one that will change it to you eventually is no store what no store will do is it'll actually trigger it every time this component is rendered so I'll actually look it up every single time which is great that's what we want now what we'll first attempt to use though is another one that's really cool is called revalidate and you could do it after however many number of seconds now in the case of blog posts revalidate might be something that's worth doing on a blog post right so you want to update it every 30 seconds or so for your blog post or 60 or whatever it might be that might actually be something you end up doing where we're going to be using no store to make sure that we're getting it every single time but we'll start off with revalidate okay and we'll see what that ends up looking like so before I even do that let's go back into our deployments and see if we have that recent one deployed and it looks like it was right so successfully deployed which gives us the false hope that it's actually working correctly and of course if I go back into that page still not working correctly right because again it did that Force cache it did the one-time fetch Windows being built and that's it it was not application Json so just return back an empty list so it didn't actually render anything so let's try the revalid H1 inside a fetch we'll come in here and we'll pass in a new object with a key of next and inside of that next key we'll put the value of a new object for revalidate and however many seconds so in my case 10 seconds right I'm going to revalidate every 10 seconds this request so now I'll go ahead and say updated fetch to revalidate every 10 seconds okay we will commit it and we'll sync it and we'll let that go now this should be successful so I'll also go ahead and put my other one as a comment here and we'll put this in as get rid of that and the key is simply you know cash right and then the string will be no store okay great so the no store again will happen every time the page is requested or the blog page is requested in this case so go ahead and say added no store cash to blog page lookup great we'll commit that I'm not going to sync it just yet because I don't want to trigger off another build just yet so go into jref.io happen really quickly 32 seconds that's great so if I go back into my project now if I refresh the first time it's going to be still empty right and that's because when it was built it did the first one it cached it so after 10 seconds which should have already happened I can refresh and now I see that data great so of course the final one is actually going to be the no store so that it works every single time and then we also have the actual git data handling you know the build process essentially with this application Json so go ahead and do get status then or actually it should be pretty much ready to go and we'll go ahead and say updated to no store caching commit and sync okay great so now that should actually solve the lookup problem that we've been running with now of course this isn't necessarily how we solve it um all the time for every type of fetch right but I want to show you all three options so you can you can actually try out the different options based off of what that specific thing needs right so in the case of like getting like if you had a button in here for example that was actually going to go ahead and call some of these things it's probably going to work a little bit differently than this because as soon as you have a button in here that's going to be a client-side component you actually probably can't use fetch this way in fact you probably shouldn't so we'll look at that in a little bit as well but the idea being now we have the ability to fetch this data in a way that I think works out pretty well and pretty nicely so I'll let this finish building it did change a little bit so it might take a little bit longer okay took a minute but now if we go in here and refresh every single time it should be doing that request right and it's there it does take a little bit longer to actually do the request but it's there it's working and it's using the correct um you know actual endpoint and all that great foreign and render out a react client component inside of a server component in other words turn this list element into a react client component and without changing that much stuff it's actually really really cool on how it works now the idea being of course is working towards something like this card with image right so at some point you'll have a Blog that will look a little bit more like this so flowboy gives a really good example of this with all the code that you might end up using but we're not there yet we we just want to actually render out the react component so let's go ahead and do that now now if we look back into our blog up in this to this point pretty much everything that we put into our app folder right all of these different files are basically rendering out a page of some kind it's a route that gets rendered and that's because of page.js inside of the folder itself anything that's not related to page.js or route.js will not be rendered it will not be accessible from a URL so instead of blog here I can easily put card.js and this is where I can render it out so first off we need to declare use clients because this is a client component and we're going to go ahead and Export the default um and we'll call this a function of and I'll give it the name of card and it's going to take in some props here which I'll pass in title and then we're going to go ahead and return a div and in here we'll go ahead and put our title okay so basically we'll also say if not title then we'll just go ahead and say div empty something like that right we'll return back that empty diff okay so with this in mind let's go ahead and use it into our page come back in here I'll get rid of some of these comments here we don't need this use client stuff in here anymore and I'll go ahead and import card from dot slash card great now you might want to call this our you know our blog card something like that uh just to give it a more cons like specific name or more robust name for this particular element and when you import defaults you can easily do that okay so now what we do is inside of our blog page here we'll get rid of these console logs instead of items I can just get rid of all this basically I'll leave that key there because I need that but I can put blog card and I can cut this out and close it off like that and just say title equals to item.title but I'll misspell it for a moment so we can say we can see what empty looks like but we we save that now let's bring this back over here we say that everything should still be running and if we jump back in we see that says empty great put it back in title cool now that blog post is working so why is it that we would end up doing something like this well it's so we can do something like this and that's use state from react this is a hook that's really nice so we'll go ahead and say count and set count and there's going to be you state of let's start with just one and then we'll go ahead and say you know count right here and I want to add a click Handler to the title so we'll do const handle click and this is an event do event dot prevent default it's probably not necessary but we'll go ahead and do set count count plus one okay so you can't do Cash Plus plus if you were attempting to do that that is a constant you need to use said count and do set and count plus one that won't modify the count itself or mutate it great uh so now that we've got this let's go ahead and add this into our H1 with on click the actual click event this is how you attach it this very very simple react stuff here we save that we refresh in here if I click hello world many many times that counts as incrementing up and up right and we can also do this with some more data so our posts let's go back into the post route here I'll go ahead and add in a few more items of data so we can see it in action we don't really need to change all of that necessarily but if I refresh in here now I can see that these actions are working as they should okay great so the next thing of course would be just to commit these things so we'll go ahead and say react client component added and I'll commit all of this say yes sync those changes and then we'll look at the result in just a moment okay looks like it was successful so let's go ahead and take a look back into our blog here we refresh we should see three now and of course we do and if I click on then what do you know they're working so we now have that react component in there and I mean look how tightly coupled it is like it's it's really really cool on how quickly all of this can happen when it comes to other methods of trying to combine a server with react it's not as easy let's just put it that way this is really really easy to do now the card itself the actual client-side components can do requests they can do lookups right they don't always have to be on the on the server side or a server component right the lookups being this fetch here it just has to be done in a different way than what we did already which we can see in just a little bit but the idea being now we have a react component rendered out it's pretty cool foreign Implement a react hook for client-side fetching that is very similar to this git data function that we have on our blog page but instead of using fetch we're going to be using the SWR package so let's go ahead and add it in with pnpm ADD SWR this is basically the same thing as saying npm install but this will actually work on versel as well so once we have that I'm going to go ahead and create a new route here for GitHub and inside of this we're going to go ahead and do page.js now this is coming directly from their example but the idea here is that we are modifying it a little bit for our own use case and the first thing is by saying use client right so we definitely need that and then we're going to go ahead and import use SWR from SWR lowercased okay so first and foremost this hook will only work in the client side it might work on the back end in the future but it will pretty much only work in the client side the next thing is we're going to declare const fetcher equals to URL and then we're going to go ahead and do fetch URL dot then and it's going to take in a response of rads.json okay so we'll see how we use this in a moment but this is basically a function to do the fetching for us that's what this is that's what's happening here and we'll just pass in a URL again it's not a whole lot different than a standard fetch call but you declare it there and then we're going to go ahead and do export default function and I'm going to call this my GitHub profile and there's a few things that we use for this hook here and it's going to be const and it's the data itself that comes back the error if there is one and whether or not it is loading so for this we'll go ahead and say use SWR we're going to go ahead and put in our URL here in a moment and then we're going to pass in the fetcher function the Callback function that'll be used to actually do the lookup okay so the first thing that I need to do is get the actual URL that I want now in my case I'm going to go ahead and grab this URL here let's go and copy that whole thing and we'll bring it back in and I'll do cost my GitHub profile or repo profile rather and we'll put that in as a string now it's a little bit different than this you'll do API Dot and then repos slash and that's it that's the only change that you need to do and then we'll pass this in to use SWR then what we're going to do is we're going to return some data here which is a div and the first one I'll just do is going to be H1 and this is going to be data dot name okay so of course if there's an error we want to check that and we'll say if error then we're going to go ahead and return and error happened and then if is loading then we'll go ahead and return floating cool so there we go that's how we're going to end up doing it let's take a look at this go back into our project here and we'll do slash GitHub because remember we called it page.js it does loading and then it gives me jref.io now there's a few other things that I can grab that I'll just go ahead and copy and paste here as far as the data is concerned and it's going to be subscriber counts Stargazer account and forks count we say that should we refresh and there we go right not a whole lot going on here as far as this repo just yet maybe by the time you're watching it'll look a little different but there's all that data and it's fetching it when it needs to and it's working correctly right and notice it's happening when I reload the page as well but it will also cache things pretty well as well so the next thing of course is just to verify this works on versel so go and add this and we'll go ahead and say added SWR for client fetching okay and we'll go ahead and say yes and sync those changes okay and then we'll come back to just make sure the deployment went okay okay finished I'll refresh in here and go over to my GitHub page and what do you know there it goes so this is hopefully the process you start getting into is you make a little change you deploy it you make a little change you deploy it right that's something that I really want to emphasize here but the other part is of course this is a effective way and efficient way to do your get requests it's not to post and update data right in the back end it's really just to request data you can request data from the backend as well that's okay with this but this is mainly for getting data now we're going to start the process of sending data to the back end this is going to be a client component inside of a server component that will actually handle the form to eventually shorten our URLs and store it into a database so the idea being that I'm actually going to copy page.js we'll copy and paste this and I'll put it into links slash page.js which creates a folder for us vs code is really nice but now we've got this basically the same thing so I'm going to call this My Links Page no big deal and I'll get rid of that so we save that and if we look at our project here and go into links I should see basically nothing in here great so now what I want to do is create our form so I'll just call this my create form.js you can call whatever you like but create form is exactly what I intend for this thing to be now what it's going to be is a client component so we want to use client and this is so I can actually tie in user interface type things like handle submit so when you submit a form I want to prevent whatever default action happens and I want to handle it myself that's exactly what I'm doing here so we're going to go ahead and do export defaults and function called our links create form and it's going to return our form here I'm going to put it into a empty fragment here which is similar to react.fragment but of course we don't have to type it out inside of next.js and so what I want to do now is I want to create my form so it's going to be a form in here and it's really going to have two things that's going to be our input and uh this is going to be a type of text and the name is going to be simply URL and that's it okay we could also do a placeholder here and say your url to shorten or something like that and then we'll go ahead and put a button here and give it a type of submit and we'll go ahead and say shorten great okay so this is very simple so far we're going to go ahead and render it out into our page so I'm going to get rid of this import for the image and we'll import the links create form from dot createform just like that and we'll bring this in here just like that great so we're refreshing here there's our URL to shorten I'm going to go ahead and grab this one right here copy it and paste it in here and hit shorten obviously nothing happens and the default action is a get request to a different URL as you see up there so what I'm also going to do is I want to add in the value just being that value just so I don't have to copy and paste it over and over again and I can just run this at any time that's really the only reason to do this right now okay so I want to handle this data now the first thing that I'm going to do is I'm going to declare a Handler so handle form and this is going to be an asynchronous function so I can use asynchronous fetch on the client which we'll see so async event and this is going to be event dot prevent default okay so now I'm going to go ahead and come in here and do add on submit so this is tying into the submit that is this event right here it's tying into that it's being assigned to this handle form and we're preventing the default here okay so we save that and let's go ahead and refresh in here if I hit shorten now it doesn't actually try to change the url like it was great so the next thing of course is to grab all of this data now there's a lot of different ways on how we can grab this data the first way would be to get it specifically like the actual name here and you can get that with events.target.name and then dot value this value or this is coming directly to this right here this name here but the problem with this in my opinion is it's not as flexible as it could be so to make it flexible we do const form data equals to new form data and that's just the event.target this turns it into something called form data which you can use in a lot of different ways but what I actually want is still an object right so we're going to go ahead and change this into data and there's going to be object Dot from entries and then form data so this we can actually console log and see what it does of course it's an object now which means that I can also turn it into Json data and it's going to be json.stringify of that data which we could also console log as well so let's take a look at that save everything go back into the project hit shorten of course it's console logging on the client side so we need to look at the client console and let's get rid of this log here we're getting an error here you provided a value of course so we provided a default value which should have been default value not the actual value so let's change this to default dot U now some out of this okay we're gonna get rid of that anyway but let's just make sure that it's correct okay so we're going to shorten this and we see two different values one is an actual JavaScript object right so that's an actual object the other one is a string or JavaScript object notation that we can then submit to our back end cool but it has the same data and that's just really really flexible in terms of like if I wanted to have multiple URLs I don't know why you do this necessarily but if I refresh in here and hit shorten now it has all of those and that's exactly why I wanted the form to work from form data entries so if I add new inputs in here I can at you know really really easily okay so now we have all of the data we need so we just need to formulate the request itself so this means that we need to update our options here so the first thing is we want to add in the method of post the next thing is going to be our headers and there's going to be content type and application Json right you always want the content type of application Json when you're working with your API and then finally our body is going to be our Json data okay so this is slightly different than what we saw before but nevertheless it is correct and then the next thing is going to be our endpoint now in this case since it's the client side we can actually use a path like API slash links slash create or something along those lines I'll just leave it in as API links which means that I need to create that route so back into our API here we're going to go and create a new folder called links and then I'll go ahead and do route.js now we already saw route.js within posts and we already saw the post method in there as well so I'm going to copy that and we will paste this in to our route here and I'll just have post as a the function that actually works and of course it returns back Json data we'll look at this request in a moment but for now I'm going to leave it as is great so I've got my form data here and then the next thing is going to be my response and that's going to be a weight fetch the endpoint itself which again it's a relative endpoint and then we're going to go ahead and use our options here and then we should be able to get our results which would be result equals to a weight response dot Json and then I'm going to go ahead and causal log what that is great okay so let's take a look I hit shorten and hello ABC great so it now shows me exactly that I was able to create form data and send it to my backend I and if I really wanted to I could also say results and set results equals to use state of null of course if I want to use U State I need to import it so import use state from react okay and now when I want to set results I will go ahead and do set results of the result and then we will come in here not the string of null but rather simply null and then down in the actual rendering I'll go ahead and say results in in Json Dot stringify results correct refresh in here hit submit and there they are now we've got it all sort of Pump It On full cylinders if you will gretchy we don't actually have the data on the API side that's something we'll still look at I'm not going to do it just yet but the idea here is you can now reuse this form element in many different ways and of course it doesn't have to be posted it can absolutely be a git method as well but using Post in this case we are allowed to have other kinds of data and the idea of using form data too this right here is then you can have also have inputs like files and stuff like that you could actually reshape this to use file inputs as well and even use a different kind of request if you need to but this is actually I think fairly straightforward and also pretty easy to do the final test that we want to do of course is to push this onto our server so I'm going to go ahead and say um added links create form and we'll go ahead and commit that yes and sync changes okay and then we'll go back into versel just want to make sure my deployment is working and it'll come back once it's done okay looks like it built okay let's go into the production version and go into links hit shorten and there we go hello ABC it's quite a different spacing there I think maybe because of the console let's bring that console back up there there it is okay great so uh we now have the ability to do those API requests with post data which is fantastic now of course we need to do something with that data in terms of putting it into a database it will work towards that after we understand how to actually even look at that data from the API now we're actually going to get the data from the post route for our API links now in this post route what we could do is we can accept the request that's coming through in the function that comes in by default and we can grab the data with const data equals to a weight response or rather request.json and then we can Echo back that data here and typically speaking when it comes to creating data you'll pass in or respond with a status code of 201 the default I believe is going to be 200 but you want to have the correct status code when you are creating that data and in the case of this form we are creating data in this API endpoint okay so if I hit shorten now what's going to happen is it's going to respond back with that data and it's going to be the correct status code as well now of course what's happening here though is I'm not actually checking whether or not this is the correct content type so I'm also going to go ahead and come in here and say const content and type with a lowercase C here equals to a weight and a request.headers DOT get content type and basically if the content type is not equal to application Json then we're going to return something just slightly different the status will be 400 and then the message will pass through will just be simply error and invalid request something like that if the content type is anything other than Json that's what we should do cool although it is returning Json so perhaps we would want to render something different but for now we'll just leave it just like that so we save it and we come back into our form of course nothing changed here so let's go ahead and actually make something change in terms of the form itself so what I want to do now is I'm going to go ahead and copy and paste this form and I'll just call this form and create HTML form as in just a Pure Old HTML form not a react component so I'm going to go ahead and get rid of this and I'm also going to get rid of all of these things here and then we'll come back and instead of form on submit I'll go ahead and say action equals to slash API links and Method being post let's get rid of that trailing slash there okay so with this we'll go ahead and get rid of that this is a another type of create form so this is the HTML version so I'm going to go ahead and go back into the page and grab that HTML version so links create form from create HTML form it's just slightly different on how it's actually going to be submitting this data I hit shorten and then I get this invalid request as we already declared pretty cool um so that's just a quick way to just jump through each one but how do we actually make this a valid request we absolutely can and it's something that would be done inside of the post Json itself so what you would be doing is instead of it being Json the actual data you'd want you would come in here and do form data and this is going to be just slightly different and we're going to go ahead and wait and this is going to be a request and we want the actual form data itself and then we'll go ahead and do console log of that form data granted I'll still be getting a invalid request but I just wanted to show you that just having a standard HTML form is still okay right so in this case it says invalid but if we look on the server itself we see that form data right here it's the same data we can handle it we could do all sorts of stuff but it's just outside the context of something that I really want to do in this case so I'll get rid of that and I'll come back into my page and turn it back into what it was originally and I'll leave this HTML form here just as an example of something that you could do and I will actually comment this out too using standard html4 because every once in a while you might not want to use a you know a react component a react client component to handle all of the the form data itself I've tend to like using this so I can be responsive and actually I can manipulate things related to the data that's being sent and shared which is kind of the point cool now before we start the process of storing domains in a database we need to validate our data so if I click on shorten here there's nothing validating this against an actual URL it's just echoing back this data I want to actually validate it now the way I'm going to do this is by copying code that I created specifically for this for a regular expression validation so if you go to just.github.com coding for entrepreneurs and locate is valid URL you'll find this it's also going to be on the GitHub the actual code itself but I'll update it more often here if anything okay so the idea being that we want to copy this and we're going to go back into our project into lib here and we'll go ahead and create a new file called isvalid url.js and paste this in it is an asynchronous function but the idea is you can pass in any sort of URL and then an array of domains that you want to not allow and you have to put in an array of domains to not allow um and then it's going to go ahead and tell you whether or not it is valid so back into our route here we're going to go ahead and use that so we're going to import is valid URL from the live folder as we see here and then I'll go ahead and say const URL equals to data and if that data exists we'll go ahead and look for the URL key itself and if that exists we'll go ahead and do data URL otherwise we'll go ahead and say null and then we'll go ahead and say it is valid or rather let's say valid URL and then we'll go ahead and do a weight and is valid URL of the URL and then pass in something like let's do jref.io for right now and then it's basically the same as this right here except it's not content type instead it's now if it's not a valid URL then we're going to go ahead and pass in a message and say something along the lines of like URL is not valid and the status code for the application type the actual invalid uh you know data type that's being requested we'll change that to 415 to have a better status code where 400 makes a lot more sense for a validation error okay so now when we go back to our our page here we shortened the GitHub one that one's still working that's fine if I do jref.io get rid of it.com shorten that that's not valid if I do some gibberish also not valid right so great we now have a way to validate that data right inside of like right before we would actually want to save it in all that which is great now the other actual shortening I want to potentially use would be the domain from versel so that's whatever domain this is and this one we don't necessarily have to hard code right so if you recall we could use the environment variable of that URL right so that's another one that we could absolutely put in here uh just to make sure that that's working but of course locally using the jref versus L is probably probably going to work if I don't have it already in the environment variables so I can do process.env and then that next for cell URL okay cool uh so now we've got all of those things and localhost is already not allowed it's a local host 3000 it's really just what domains do we just not want to allow in here oh that's the live version that's funny okay so we come back in and do local post 3000 hit shorten not valid great so we're definitely on the right track as far as having validation done and we're pretty much ready to start storing this into a database but of course we have to do a few Integrations to get that going as well at this time I would recommend that you just deploy this to versel as I will I'll go ahead and say added URL validation to Links form and I'm actually not going to show the verification at this point but it should work just fine we shouldn't have any issues if you do just let us know in the comments but more likely if there are issues we'll look at them later when we actually start using the database that all web applications have in common number one they're accessible likely through the internet and number two they actually store data somewhere our application doesn't store data yet so let's change that now we're going to be using neon which is a serverless postgres service that allows us to really scale down or scale up to meet the demands of our database which also means that we only pay for what we use which is typically how big our database is another cool thing about neon is that we can Branch the database so if you have a bunch of production data that's being created and you don't want to touch the production database you can actually Branch it and then use that Branch as a new database like locally or something like that it's pretty cool now the other part about this is It's optimized for versel the serverless functions or the edge functions we're going to be using the edge functions which are really fast and really cool and it's really easy as well so let's start off by signing up for neon we'll go ahead and sign in here continue with GitHub in my case I already did that and then we're going to go ahead and create a brand new project which is in this button down here and I'm going to call mine jref now the key thing here is this region we want to select a region that's close to where our Edge functions or our functions on versel will end up being now if you're not familiar with what I mean by functions we'll take a look at those soon too but the idea being is we go back into our project we go into settings here and we go down into functions and we see function region we want to pick a region and either that are near each other so in this case it's already in Washington DC and so what I can do then is on my neon database I can change it to North Virginia that's likely a lot closer Ohio North Virginia you know there's not that much of a difference likely to Washington DC but the point is we want it to be close you might already know why it has to do with speed otherwise known as latency between these two things connecting it's not really about connecting to your users your users is going to be more about the actual function region or where your application is deployed but Brazil is incredibly efficient as far as getting data to you that's one of the things that nexjs does really really well as far as actually loading the application itself so now that we've got this let's go ahead and create this project here and the first thing it gives us is a database connection string now if you're already familiar with postgres you're like oh cool I could just use this really really quickly and that's true now what we're going to be doing though is using the neon client for serverless databases this client is optimized for for cell Edge okay so what we're going to do here is we're going to copy this and we're going to bring it into our local EnV file so.env.local we'll call it database URL we're going to set that equal right there with this open I'm also going to jump back into my project here on versel and go into my environment variables under the settings and also add it in here as well now there's a huge caveat that you should be aware of that you probably won't want to do when it comes to your production applications and that is using the same user and the same credentials for local and production so back into the console here what I can do is close this out and I can actually go into roles and I can create a brand new role right here I'm just using the one single roll in two places but when you actually start using it in production definitely consider creating another role that can still have permission to the same database but the idea being that you're not having the same passwords exposed in multiple places now this actual database and the database connection string will be deleted pretty soon for me right it might not be for you but it is something to be aware of Okay so we've got a couple things covered we've got the database string that we need to actually connect to our database so now it's time to actually install the client to do that connection so we're going to do a Hello World here so if you go on GitHub for neon database serverless you will find the clients that we're going to end up using this client is evolving so if anything major changes please let us know but more than likely this is what's going to work in in a lot of things that have been up before are Backward Compatible so we're going to go and install this now I will point out that you don't have to use this on for sale you can use it for a lot of different things including the drop-in replacement for the node postgres which is great so that means that it actually has support for a lot of orns that we'll actually look at a little bit later but we want to do a Hello World type thing here right now so I'm going to go ahead and install this into my app with pmpm ADD and it's going to be at neon database serverless just like that and of course we need pnpm so it works on for cell we hit enter and it's going to do some installation for us so what I want to do is inside a lib I'm going to go ahead and create a db.js and we're going to go ahead and import a few things first off we're going to import neon from the at database serverless and then we're going to go ahead and declare our SQL client which you will do is SQL and then you're going to pass in two Neon process.emv.database URL just like that okay and so to actually run SQL commands we will call just like this so we do something like select now and that will get the time that we'd have so let's just console log this this probably won't do anything uh just yet because we haven't imported this file at all or used it anywhere but if we run PM pm and run Dev I don't think it will actually console log this result just yet which is fine we can totally do it in just a moment so what I want to do then is instead of just console logging this I'm going to go ahead and Export an asynchronous function called hello world now I'm not exporting a default function on purpose but I am exporting just this asynchronous function here and all I want to do here is give this response back what I had originally so to do this it needs to be awaited so that's another reason why this doesn't necessarily work is that I need to get my DB response in Brackets just like that and we're going to set it equal to a weight and SQL select now there we go so inside of these back ticks is a SQL statement you can do all kinds of SQL statements here and that's exactly what it is and so we're going to return back this DB response so I need this to actually be on some sort of page so I'll go into my blog here and I'm going to import that hello world go to import and hello world from our database live I'm going to go ahead and use at app like that's just like our git domain here and then I want to call this hello world down into the page itself so I'll go ahead and do DB hello equals to I'll wait hello world and I'll go ahead and console log what that is so console log by DB hello to whatever that is great okay so back into my project here I'm going to go ahead and let it run for a moment it might take a moment for it to fully work but there we go that is my database response right there and it gives me the time which is exactly what's happening with this select now that's what's going on in terms of the database itself so what I could do then is in my hello world I can change this to being DB now equals to the DB response and we would basically say and DB response dot now then we'll go DB response now otherwise we'll just say it's an empty string and that's what I'll return okay so now we see that that's a string there just like that one of the questions you might have is it a date string so can I actually remove a date from it right so let's go ahead and try that with select or subtracting a new date object here save that and what do we get we get a value right it's probably about 83 seconds or milliseconds actually um so that's kind of cool but the other thing is I can actually come back into this hello world here and I can say dbnow is DB now and then I can test the latency here so what I can do is say const start equals to new date and then const end equals to new date right and so the latency then would be we'll use math dot ABS or absolute value and minus start and this should be in milliseconds so we refresh and here we see that the console log is happening just like that and then back into our page what I want to do is I'm going to go ahead and add what this DB hello says by putting it into a paragraph tag I'll do DB you know response and it's just going to be the json.stringify of the DB hello and that's pretty much where we'll leave it for now uh and the next one will actually change this into an edge function but we can refresh and we can see how fast it actually ends up being which is really really fast and I am in Idaho so this is actually going across the country into uh what did I say North or Virginia I think North Virginia is where it's going so it's really really fast even for where I am which is pretty cool so now what we need to do is actually deploy this into Versa that's something we'll do in the next one by modifying our Blog Page a little bit foreign this to for sale yet is because we want to declare a couple things inside of our page.js here now whatever we are going to be using a database function of some kind we want to deploy and change the runtime so we're going to export a const or constant called runtime and we're going to set this to Edge if we don't set it to Edge it's going to default to node.js which is probably fine but Edge should be a little bit faster more efficient and I believe closer to your end users the other thing we want to do is we want to export a constant and this is going to be our preferred region and what this region will be we could say Auto we can leave it in as Auto or what we could do is we can actually come into our project here go into settings and grab the functions and grab whatever that value is so in this case it's i a C1 but you would grab one of those regions and have that as your preferred region and I'll do IAD one now of course the reason for that is because our neon database is well Associated to that region or we selected it based off of that region so now that we've got that let's go ahead and say added database port and Edge function so go ahead and Commit This say yes I'll go ahead and sync these changes I'll go ahead and say okay I'll just wait a minute or so to let the deployment finish and now back into versel I see that it is finished and there's the database support and Edge functions so if we go back into our project and we click on the project itself rather deployments itself and go into that recent deployment and go into our functions here we can see all of the various functions that we've got all of these will work as functions whereas our blog function will actually be an edge function in Washington DC as we see so the execution duration is going to be 30 seconds or if we go to like links we see that it's node.js the execution duration is a lot shorter it's only 10 seconds right so we definitely want to use a little bit longer of one if for some reason our query is taking a little bit longer but we've got we've got blog being an edge function and if we go in here and take a look at that blog there it is the latency is a lot less than it was with me in Idaho and that's because of course it's not making as long as the journey and also how efficient for sale is at getting this data out there through a Content delivery Network as far as connecting to the website itself so significant only faster than my local lookups you know five times or two at least two times three times four times faster than what I've got locally so that's pretty cool and this is also one of those features of using those Edge functions as well so we can use the add function Edge functions anywhere so anywhere we want to put this runtime as our default we could totally do that and I think that's perfectly acceptable especially when it comes to getting database related things so whenever we're using neon we're going to want to use that edge runtime and this preferred region I would imagine the auto preferred region probably will work but just declaring the region that we prefer is ideal now we can also add in stuff like revalidate in here just like what we saw with the fetch itself we can add in like 10 seconds if we needed to or something along those lines I'm not going to do that but I will say I will at least point you to where you could learn more about it and that's in the root segment config on how you could go about doing all of these root changes and how fast it works and it will work on the page as well as we just saw with that runtime so whenever you need to change it this is the way to do it now the other part about this that's important to note is that not everywhere you find documentation related to next.js will have the app router right in many cases it will maybe not right so on neon's current readme for this client this is using the other version of next.js the page router which is still valid but it's just slightly different if you were to use this it would give you a warning so let me just show you that save that you refresh in here and you go back into your project and let's go ahead and reload that page what you should see at some point for this one is a warning related to that and here it is right there right and this is only because of app router versus page router but it is something to note and something to be aware of personally I really like how this one works it's just pretty straightforward and there's already a fallback and a default so yeah that's pretty cool we now have our database working on an edge function and it's really really fast so let's keep going foreign actually creating the database tables we're going to insert data into where we're going to store our data and then I'll also retrieve our data of course so to do this we actually need to lay a foundation for what we'll use very soon which is called an orn but in the meantime I want to actually create this table using pure SQL so if you don't know SQL this is going to be a little bit of an introduction to it to you if you know SQL well you know that we've already done a SQL command right in here right and so you can continue to do that but what I've found is when working with nexjs specifically writing invalid SQL commands takes a little bit longer like even up upwards of a few minutes to give me that error right in xjs versus right inside of the neon console or of course if you have the postgres client installed you can always log in there but in the neon console in this SQL editor this is a really easy way to just jump in and run some command ends so we can you know get it working correctly before we copy and paste it and bring it into our local project so what we want to do here is we want to create a brand new table and the command for this is as simple as create table and then you can give it some name so like let's give it some gibberish name for now and then I'll use some parentheses in here just like this to add the rows okay so I can go ahead and say ABC and some other gibberish and I go ahead and try to explain it I should get a syntax error I'm going to analyze it also syntax error right so this same exact error running inside of next.js might take a really long time and never work of course if I go to run it it will also save it over here in my history of course this is not a valid command whatsoever we've got a bunch of issues here so what we want to do is we want to create a table if it doesn't exist because if we need to execute this again it's only going to happen if it does not exist so to do that we say create table if not exists but if you accidentally put it didn't put an S there or you spelled it incorrectly again you get a syntax error if that happens so we change it to the correct one and then we give it a table name in my case I'm going to call it links and now what we want to do is design each column that we want to store now the column being like bid for example right so every time you insert a new object or a new data point a new row you want it to automatically get a unique ID that increments by one each time so to do that we do ID and then it's serial primary key and not null that's it now we have a way to have IDs in there now we're going to go ahead and add in another field which this field is going to be simply URL and it's going to be text so it could be kind of a varying length it could be fairly long and it could be fairly short as well and I'll go and say not null right so as far as my knowledge the default does not have a data type for URLs you would put the data type in as text or the ID we want it to be serial so it automatically increments like one by one next up we're going to go ahead and do created at and we use that underscore there instead of a dash and I'm going to go ahead and do timestamp default now okay so created that as in when this gets entered into the database it's going to automatically set it to now and that is the same as this select now it's going to be the same exact value inside from the database so this is actually how we can create that table I hit run and now it should actually create that table for me so this is now valid SQL I should be able to use it just fine and I can also verify that the table exists but before I verify that I'm going to bring it on over into my project here and I'm going to paste it into with back ticks around it so we'll we'll solve that in just a second I'll go back into my tables in the neon console and I see this links table in here just like that okay great so the next thing is of course is we actually want to be able to call this command so I'll go ahead and copy this hello world here and paste right underneath it this time I'm not actually going to export it but I will say configure database as the function name and then we're going to go ahead and automatically run it and we'll go ahead and catch the error if there is one and console log uh DB config error with that error okay great so the SQL statement is now going to be this so we can just paste that in here just like that and this is going to be our response so I don't need to unpack it at all I can just do DB response and I can get rid of this and then I can also get rid of the return statement we don't need one and I'll just go ahead and console log DB response for new table and just pass that on in here just like that okay so at this point let's go ahead and make sure our project is running it looks like it still is and so one of the things you might be wondering is like when is this actually going to be ran well it should only be ran one time that is when it's being built or when the server refreshes so when it restarts it's going to run it that one time as we see here we've got DV response for new table and so on right so that's going to happen literally every time I save it on my local development but when I'm in production it's only going to run with that build and the reason it even runs in the first place is because this db.js module is being used and it's being used on the blog page so here's that blog page that actually is calling that module and therefore everything in there or at least this Command right here would end up running in that module as well so what we have here though can be called elsewhere it doesn't have to be called here right we could actually put it in something like the hello world thing um but it's not really that necessary we could just leave it as is and so the reason it is even being called in my console is because I'm actually on that page I'm on the blog page right here and right now it's saying something went wrong it's failing to compile all of this because of when it was saved so this goes back to that caching issue and things that are related to potentially issues that you have while trying to use this nexjs caching right and so now if I fix it hopefully now it's working but it's certainly possible that it could take some time before it works and I want to emphasize this latency that ends up happening is not because of neon it's not because of the database it's because it how caching ends up working and if you have an incorrect SQL statement so the question of course becomes how do we make correct SQL statements how are we going to go about doing that well that's what we want to do with the orm so let's take a look at drizzle foreign s to work with a SQL database using JavaScript is by using an orm this is true for many programming languages but the orm stands for object relation mapping or relation mapper and what that allows us to do is instead of writing SQL like this we can actually go in and use something a bit more like this now they're very very similar they basically overlap in quite a bit of in many ways right so we've got our idea of primary key in here we've got a full name which is basically like that URL and then we have this phone number in here so it's not exactly the same but it's very very close right so drizzle orm is going to be doing stuff like this but the thing is even with that in mind I found the best way to create or update tables is by using this configuration Command right here so we're still going to be using what we just did just we're going to be using drizzle to help us with that process and so what we want to do here is we're going to to create what's called a schema file which is really just a design of our tables all of our tables we're going to put them in one schema file as drizzle recommends and we'll basically be like oh if we need to store more data we're going to update that schema file as we see fit so this is what we're working towards right now so first thing that we need to do is we need to install drizzle and drizzle kit drizzle kit will help us make some of the SQL files that we need are also known as migration files but the idea being that we want to actually go off of almost off of this we don't need postgres in here but just we do need drizzle orm and drizzle kit so let's go ahead and install that now I'm going to open up a new terminal here and we'll do p npm and we'll go ahead and add drizzle orm and then we're going to go ahead and in our development environment pmpm add Dash capital D the drizzle dash kit and we'll go ahead and hit enter and there we go okay so our schema file is going to be inside of our lib here we're going to go and create schema.js okay so again we want to think of this in terms of how we're going to just declare all of our database files however we will continue to use this going forward so the first things first we're going to go ahead and import timestamp and we're going to import text PG table and serial and there's going to be from the drizzle orm slash PG core okay now what we're going to do is we're going to export const we're going to give this a table name so in a lot of examples you'll see it as like links like this I tend to append with the schema table to it so I often do something more like links table like that just so that I know this is specifically a postgres table it's a SQL table that I'm using with Drizzle and we want to declare that table with PG table and then the name of the table now if you recall we already have this table right it's already exists on our database which we could change in a little bit and we will next we're going to go ahead and declare all of the columns that we want to support as a JavaScript object there's that object relation mamper first off is the ID and again we're going to be using serial of the ID and then dot primary key and then dot not null next up we're going to go ahead and do our URL again this is a text item and again we're going to name it URL so the key value pairs are slightly different I'll explain those in a second and again it'll be not null then we're going to go ahead and do created at and this is going to be time stamp and then created at the default now okay so what do we have here first off serial right there we've got our ID this is the field name in the database the one that's in the string the actual key is the one that we can use inside of JavaScript that's where this created at and create at makes sort of a difference now I think generally speaking you'd probably want to keep these things the same but every once in a while you might want to change them and that's how we actually go about doing that just so you're aware of it that's why I put it there and we've got that default now still not in all means that we can't have an empty value in there in the database and there will be some checks along with that okay so now we've got our table that's our first table so the question of course is well what do we do with this table well the first thing I want to do is actually create a migration so almost like assuming that we actually didn't run this command yet but we want to create what that command could look like with using uh our drizzle kit foreign statement from JavaScript using drizzle kit so this PG table object will be converted into JavaScript for us with this method it's fairly straightforward but it's really nice because it gives us valid JavaScript or valid SQL from this JavaScript that hopefully is valid and then it also will give us a history of these changes that you might be making so inside of the root of my project here I'm going to go ahead and do drizzle dot config.js just like that or rather Json JS does work as well but we'll use Json and then I'll go ahead and add in a schema and then we'll also add in out so out is where we want to store these things I'll just do it in SRC slash migrations and then the schema itself is this particular file which we could copy the relative path to and paste it in just like that okay so that's the config file very very simple the input which has an export for this PG table and hopefully all of that stuff is valid and then we have where we want to store these things so we'll go ahead and save it and to run this it's as simple as MPX drizzle kit generate PG we hit enter by default it will use that config file that we just created if you didn't have one you can specify one and all that and what we see here is it's actually going through all of these columns now if I had an error let's say not nulled like that I think it will tell me that right so it validates this stuff for me and it shows me a pretty good uh you know example of what what happened as far as the failure is concerned but if I run it multiple times and go into SRC migrations I only see one item in there and if we look at that single item some good news comes out and of course it's a SQL file I can go ahead and copy this and bring it over into my database here I'll put in some back ticks and paste this in here what we see is quite literally the exact same statement pretty cool and it's valid should work just well just like this other one so what we can also do let's get rid of that statement there we don't need that anymore is we can obviously make changes to a table so if we were to want to make changes let's say for instance we wanted to put in a varying character of our Char we could actually come in here and say short is varchar and we'll call this short and then we can pass in a value of length like maybe 50 so we have it 50 long notice that I don't have not null on there and I also don't have a default if I wanted to make these required I would say not null and then put it defaults the default being all of the items that are already stored in the database but we save it now and then I go ahead and generate it with the MPX you know drizzle kit generate PG and then if I scroll down to my migrations I see this new command here okay so alter table lengths add column short varchar 50. pretty cool so let's go ahead and look at our table so back into the console here we'll go into our tables and we'll go into links and we'll just open it up a bit and there is short let's go ahead and get rid of that short there and run it again and we'll refresh in here again we'll look at our links still there okay so yours is likely the reverse of that I did some testing to see what's going on but the idea being that this Alters the table this also Alters the table right so it's basically just a history of what could happen in your case yours likely didn't alter the table yet so let's go ahead and look at that we'll come in here and I'll just do a weight SQL paste that in there save it and what's going to happen assuming that you know my server's still running and all that and a refresh in here on the blog page what it might end up happening is or what should happen is this table actually being created for me I might have to restart the server I've been doing a bunch of different testing on here so it's certainly possible that this might fail a little bit on my end but there it goes it refreshes and I come back into my table here and of course it's already there right so yours would now be there as well but of course every time I save this now I'm going to get this column error here right so this is this already exists so we could put it into a try catch statement in terms of altering the table right like we want it to be altered so we could always put it in like this and just take a look at what that error would be of course the error itself you know perhaps we don't want it anymore because it's already been changed so before we go any deeper down that rabbit hole I will say that uh drizzle kit itself can help handle these things for us but one of the things that I found is it just doesn't work super well with Nexus and the caching that goes on with that at least at this time so if you want to use this there's a lot of different ways on how you might be able to just automatically go based off of these migrations instead of needing to call it directly inside of JavaScript but that's outside the scope of what we're trying to do here instead what I'm trying to do is really just have this one single table and that's all I'm going to leave so really I'm going to go ahead and get rid of this and not really worry about changing the tables in the future I'll go ahead and delete the migrations this time and I'll go back into my schema this time I'll bring back that short we're going to save that and we're going to do something that we've already done many times and that is we're going to go ahead and drop this table again I'm going to run it we now should no longer have that table in here looks like we don't so I'm going to save that and then open up package.json I'm going to go ahead and add in migrations and this is going to be MPX drizzle kit generate PG so whatever I need to generate those those actual migrations I can then run you know the P npm run migrations this is definitely how I would end up doing it all the time then back into my SRC I'm gonna go grab that migration grab the entire thing copy it bring it into my database here and we're gonna paste it in place save it close it off like that now it's certainly possible that I accidentally already created it but let's go ahead and refresh this page refresh neon and there we go there's our links and there's our short right so making those changes is certainly possible we just saw how it's done it's just outside the context of all the things I want to do here realistically I recommend testing out creating and destroying tables as much as possible until you have a really solid foundation as to the columns you need you really shouldn't need to add a bunch of columns in the future if you start finding yourself that you're adding a bunch of columns it might be best to put it into another table or to maybe re-architecture how you use all your tables in the first place but just think through these things as much as you possibly can as far as the columns that you need and when you do figure out all of the data types and stuff like that that you're going to want go into the documentation go into column time for postgres and look at all the various values that you could have in there and really just play around with it like that so that is getting our table in there now it's time to actually start adding data in there so we can we can really have something that we can look at foreign storing links into our database using neon and drizzle so to do this we're going to open up db.js we are going to do an import next to Neon for neon config this is an experimental feature which is the unconfig dot fetch connection cache I'm going to go ahead and say true I'm this might change over time if it does check out the documentation but I think this is a good one to use when it comes to doing our connections so go ahead and do import drizzle and we're going to do from drizzle orm slash neon Dash http okay so from here we'll now declare a DB element for drizzle of that SQL connection just like that so we're going to continue to use this inside of various functions so the very first function we'll do is export async function and this will go ahead and we'll just call this add link we'll pass in a URL here and we'll go ahead and do you know create a constant called New link and it's going to be equal to url url okay so right now it's going to go ahead and add a link into this new object and then we're going to return an a weight DB insert and we want to insert into our table so let's go ahead and grab that table as well we're going to import the links table from the schema right there come back down into our insert command we will insert it into this table and we're going to pass in values values can be a single object like what we have here a single dictionary or it could be a list of them and we do new link and then if we do dot returning we will actually get that value back so now that we've got this let's go into our API for creating those links which is this post header right here all of the stuff we did to make sure that that's working correctly will now be in use so go ahead and import that add link from at app lib DB now we'll go ahead and say const response or let's go ahead and say DB response equals to await add link of the URL and that's the response I'll now give back to when we submit data okay so let's go into our links here let's just make sure that I don't have any errors I did see one a second ago but looks like we're okay so I'm going to just go ahead and submit this hit shorten and there we go so null for short this is basically showing me yes it was created I could create it again and what do you know it does it again so if we go back in here into our tables now and click on links we now see those entries coming through fantastic now of course we're not done because we don't have the short Parts just yet which we will get to but I want to get all the data first and I have that all working and there's another thing that we need to fix and that is we don't want to insert the same data over and over in other words I want an error to happen if I already have this data in here that error will then inform how I handle it in the future like I don't want to have the same URL many many times potentially it's kind of a design decision on you're in on how you might end up using that your own service in this way so the other thing is let's go ahead and grab a URL that shouldn't work we hit that and we get that message great that's still working as intended and so at some point we'll get rid of this you know default value of a link but for now we have a way to actually create data congratulations it's super exciting now let's go ahead and list out data it's actually a lot like ad link but this time we'll go ahead and say git links so what we want to do here is instead of saying insert we're going to go ahead and do from and also dot select so DB select from this links table and the values we don't need that or returning returning just means that it will actually return the value that was sent to it in the case that we saw it actually sent a list of values because you can insert a list of values so it's going to return back a list of values but getting links on the other hand we can just do it like this now I can't make it a little bit more robust than this and I can actually put in here like a limit like the amount the maximum amount that I might want to have in here which would be 10 let's say for instance and we could also do an offset like the number of pages so if you need to do pagination this is essentially what you would end up doing you would not need this URL and you would not need that new link but what you could add in here are maybe the limit and Offset you might want to have so what we would then say const lookup limit equals to the limits itself or zero or rather 10 the defaults whatever and then we'll do const lookup and offset and again same sort of thing as to when we want to start it and there we go and then go so that's how you can do pagination just right off the bat you might as well have pagination in there just to make sure that it is available to you when you start doing it of course there's more advanced things that you could probably do with this but let's go and do this get links now this time I'm going to do is on the page for links I'm going to go ahead and create a new component and I'll just call it table for now table.js we're going to go and import that get links from at app lib DB and then we're going to export a default value and call this just simply we'll call this our links HTML table let's do not get it confused and then we'll go ahead and return for now I'll just return a div and we need to call this a we'll call it an async function here okay and so we'll return div so what I want here is my links response and we'll do a weight get links and I'll just do a json.stringify of that link response and I'll do an and and just to check it okay great so now back into that page here I'll go ahead and import that links HTML table and then we'll go ahead and put it underneath the create form itself so let's go ahead and save that and we'll Refresh on our links here and there we go there's my data right and so of course I can turn this into a table now pretty simply so we'll go ahead and put a table element here and then a tea body for the body element and then we'll go ahead and map through all of the link responses okay so link response and Dot map and it's going to be the link itself and then the index value of that link and then we'll go ahead and do a row a table column the first thing is going to be link.id and then maybe the next one being link.url and I'll just leave it like that but you want to return this value and then we're going to give it a key in this case I'll give the key being you know link item I'll pass in link dot ID and idx the actual index value here and that is mostly for paginasian so if we end up doing pagination here which is something I'm not going to cover at this point but you could then have it uh show up so with that mind we refresh in here and there are our two links fantastic really really simple nice and easy to do that's how we get links and that's also how we display them and so you could use this in many many places right and so right now this table is working uh just on the server side it's a server-side component it's a server component it is not a standard react client-side component but you could totally have it be one you would just have to do your lookup slightly different in terms of actually creating a route for it right so an asynchronous route similar to what we did here that's why I wanted to show you both ways this right here would be the API endpoint to create it but it's not much different to to get it to list it out and so I would leave you with that challenge but I'm just going to show you because it's really really easy to do you come back in here either we're going to bring the get links and now I can do export async function and it's going to be get now of the request right and so we want to get that data very similar to what we saw here and we'll go ahead and do const links equals to await get links and then return nextresponse dot Json and what do you know links and we can add in a status of 200. and so if we want to check that out we can come in to API links hit enter and there's our links as well right and so one of the things you also might be wondering is like oh well what about limiting the data that comes back right this is something else that comes up from time to time when you want specific data not all of the rows but specific parts of the rows now to do that we would come in here and I'll go ahead and just copy this function and create another one and we'll go ahead and do get minimum links and so in this select element then you would pass in the values you want so ID being from the links table dot ID and then like our URL again links table dot URL and maybe you want to change it to timestamp instead of created as and that's going to be linked table and this is going to be created at right so we can also modify how it looks which is really important in terms of an API itself because you might want to have it just look just slightly different in here and so when we use that one now let's go ahead and change it in our API here should come up to get links instead of that we're going to get minimum links or get API links something like that we refresh in here and it's just slightly modified or majorly modified depending on how you want to see it now you could do a lot of other things to modify how this response comes back and when it comes to an API that's when you're going to want to do it even more so than when you're doing it with just you know sort of standard rendered Pages if you will but the API then would want to be well documented and there's a lot of other stuff that we're just not going to really talk about but that's pretty cool I think it's also really easy to just get that up and going and now we have these requests that end up working really really fast so what I want to do is actually send this to the database now and bring it in or rather send this into production now we'll go ahead and set added git and create you know links and I'll go ahead and commit that say yes and we'll go ahead and sync it I'll let that finish as far as deploying is concerned and we'll take a look at the production version in a minute now over into the production version if I go to Links here I see that I've got a few already there if I go to shorten it um I think it should work just fine and I see that it says ID of 11. so this must mean that I have 11 stored but only seven are showing up and if I keep going um yeah same same now if I go into the API I can see that I have at least 10 in here but it's not being rendered here now this is because of that caching there's a lot of different reasons as to why this ends up looking this way but of course when everything was being built that's when it actually did that Fetch and was able to grab all this data but it wasn't a fetch it was just a database lookup so we actually want to convert it into being a fetch like we've seen before and that's something we'll do right now foreign this table right here for a links we want to display it slightly differently first off I wanted to be able to display shortly after I submit a new link I wanted to actually show up on this table that's pretty common to see now what I'm not going to do is blend these too much right I totally could but I'm not going to do that just yet or maybe at all instead what I'm going to do is use some of the advantages that SWR has in a client component which means that we're going to change this from being a server component to being a client component so it can be a little bit more reactive to things that are happening in the user interface but then also being updating some validation stuff so we'll see what that looks like now first and foremost inside of the GitHub page this is the model we want to work off of so we can go ahead and copy this and bring it on over into our links table here and we'll just go ahead and paste it in now of course it's no longer the GitHub profile instead it's going to be the lynx HTML table and my GitHub profile should actually now just be in points and we can update that accordingly next up is the actual string or the endpoint we're looking for which is just simply API links no longer directly from the database itself and then of course we can actually bring this table in here and this could be what we return back with now one thing that I still need to change is this data right here and there we go and now I can go ahead and get rid of the server component elements in there and that's pretty much it right I now have a client component doing roughly the same thing granted I definitely needed to have this part already done which I did but their actual response is the same they're identical it's just now it's doing a actual endpoint request and thus it has the use SWR hook which is great because then I can pass in another argument in here for when this data needs to refresh so we can do this refresh interval and it's going to be um in so we would say a thousand for one second so every second this will update on its own and it will refresh all of this data so now if I refresh in here it says 9 if I shorten it again that's my 10th element here it just takes a second literally to actually update that data which I think that is plenty of data in there there are other automatic reevalidation things that you can look at with the SWR and there's something else called mutate but I found this to be pretty effective in terms of just you know checking this new data the other thing would be to Resource this data based off of when it was created so let's go ahead and take a look at how we would do that just really quickly so first off in the route itself I want to update the limit to a 100 and then I'll keep the offset at zero just to make sure that I can see more data coming through in here we'll worry about The Styling in a little bit later so now I just want to flip the ordering of it and of course it's going to come from this function right here so jumping back into db.js right here is where we're going to want to change the ordering so we can do order Buy in here and what we want to do is we need to pass in something called descending this is a function directly from the drizzle orm which we can just type out and it will actually import it for SVS code is great and then we're going to go ahead and do links table dot created at and that will actually Resort these things based off of when they are created I can shorten it again and in just a moment boom there it is 11 is showing up and I do it again and then 12 is going to show up so really I probably don't even need to render these successful page that came out and if I try to do something that just doesn't make sense in here it will give me this Val invalid error where all of these other ones are seemingly valid even though it's not a real domain it is still a valid formatted URL so that's pretty cool now the other thing is of this descending I can always do another field as well so I could change it to the ID field or of course I could use ascending which is just another way that just reverses it now by default it is sends by you know one or the ID value it already does that that's the defaults but there are other options that you can have and personally I like doing descending by Windows created this becomes a SQL query itself right so you could also write this in SQL if you were on that advanced site so that's pretty cool I think this solves a lot of issues that you might have with this kind of data with adding this kind of data now do we need to refresh constantly not always not necessarily but when it's something like this you might actually want it to refresh every second or so just to make sure that that's working pretty cool foreign if you opened up your console log and you noticed the refresh interval just going completely off the chain that's because it sort of is we don't want it to refresh every second we can have it do that but we don't want them to do that instead what we could do is we could use something called mutate which means that we can actually trigger something inside of this table that will automatically refresh it so I'm going to go ahead and get rid of this refresh interval here and I want to have mutate be able to be called so mutate and so the question of course is how do I call This And when would I call this well the first thing is we would call it on the create form the form itself that's going to need to cause that mutation to happen and now that they're both client applications or client components we can actually bring them together so instead of them being rendered on the page together they're they're going to be rendered in the table itself or the table component itself so I'll go okay and bring this in here and then we'll go ahead and do our links HTML at the table but rather the create form do that links create form and that should bring it in for me right there great okay so now it brings it in and we should just refresh to make sure that we can render it out sure enough it's being rendered okay so how would we trigger this mutate well one approach would be to just just say const did submit and this being an event or maybe the actual new item in here and we could go ahead and this method we could just call mutate you can make it empty as well this method itself would then be passed as a prop to our link links create form and then back into the form itself we can grab that property and basically inside of this handle form submit we can just say if that exists then we'll go ahead and pass in the results and I'll go ahead and do I'll just pass in the results itself and you can actually see the resulting Json itself that comes through this result actually doesn't matter that much we can also pass in the response from the back end as well or the Json data either what the reason this one doesn't really matter that much has to do with the fact that mutate is going to trigger the end point again it's just going to look up that endpoint again um so we don't even need this at all really let's go ahead and come in here and hit shorten and right away it triggers it right away it triggers it this is a much better approach to what I just showed you however refreshing data on a regular basis is still important for all kinds of applications that you might be building this right here is a little bit more like hey if you know how to use react props a little bit you can move things around now it's not the only way to manage this kind of idea it's also not the only way to manage this kind of state element where we're sort of managing the state of where the form is but it is a really simple and easy way to do it on a page and form like this so yeah hopefully you like this one a little bit better personally I do I'd rather mutate it based off of when an actual relevant happens versus when time is being passed especially with serverless components right so we don't want this to continuously run if it doesn't have to that's the point of using a serverless database as the point of using serverless Edge functions as well we wanted to run when it's efficient to do so this is quite a bit more efficient foreign we're going to create short strings just random ones that will really represent the destination URL in many ways it's actually just an ID for the entry inside of our database it's not the actual ID but it's a type of identification for the entry which we'll use to look up later so it's really not that big of a deal in terms of how it actually works so first and foremost let's go into our library here and we'll go ahead and call this a random short strings.js and we're going to go ahead and Export the default function of Random short strings and what we're going to do here is we're going to turn math dot random this will give us a red just a bunch of random values and then we'll go ahead and do two string of some arbitrary length I'll go ahead and say 36th and then we'll go ahead and do substring like a short number of it between two and seven or however long you want it to be cool so that's it that's the function that we want and from here we'll go ahead and import this and the question of course would be where would we import it what would be the best place well I think in the database functions here when we go to add the link this is a really good spot for it um so we'll go ahead and import it now so import random short strings from random short strings and we'll come down into our ad link here and I'll do const short equals to random short strings and then we'll go ahead and do shorts it is short now the important thing about entering this data in is ensuring that it is in the schema in the links table schema so go back into that schema and there it is right here right and we want to make sure the length is appropriate now when you start running out of these strings which could happen if you have millions of entries you would then need to adjust the size of the substring a little bit to ensure that it's a little bit more random but that's a that's a problem for scale something we really don't need to worry about at this scale right we would need to get a lot more strings going through but that's just the general idea so how everything's set up right now I really like it because I can jump into the console here go into SQL editor and just drop this table here and run it table's gone I refresh locally it says an error happens of course it happened the table's gone now I can actually shorten this link and this time I'm finally get this short URL here which is great now in some cases you might want to have the ability to do it many different times right so having it done many different times will allow for the possibility of seeing different analytics for that single short link but of course what we need to do now is we need to actually set up a way where I can go to that short link and it basically represents the actual URL itself which would eventually maybe redirect you there or it would just show you information about whatever you're putting there so let's go ahead and start that process now that we have these short strings here I want to actually create the URL routing for it so my domain name slash whatever that short string is we'll go ahead and enter and we want this to actually go where it needs to it actually needs to look up the record but also show and render a page so the first thing I want to do is inside of my app here I can make a new folder use those brackets and we'll just call it short so that's it right now your intuition might be like oh it's going to not go to any of the other routes it actually still does xjs does this very intelligently which is great so now go ahead and do my page here so page.js and we'll go ahead and Export a default async function and we're going to call this short page and it's going to take in some params and we'll just go ahead and return H1 short page something like that okay so now if I go back into my my URL here for that short URL we've got this short page great and if I went to console log those params oops not that param but the param is being passed we see short coming through okay great so that means that I can then go cost short is equal to these params just unpacking that value okay so now that we've got this we need to actually create a database function to look up this short value so into db.js right underneath git links we're going to go ahead and copy this paste in here and what I want to do is call this get short link record and in here we'll pass in short link we do not need the limit or offset so I can get rid of both of those things as well as from the actual lookup itself but instead what we're going to do is a where call so where is a way to query this data or like make it like look down even further right so narrow down what the query would end up being so what we want to do here is we're trying to check short link being passed equaling to the database version of links table dot short right so if we look back at that schema it's this value right here whatever this value is not what the database value is but the beta the value directly on the schema itself is how we're going to be doing this comparison so when it comes to doing it in drizzle this kind of comparison we have to import a new orm feature which would be EQ so this is basically going to say we're going to do EQ and then we're going to grab our like our SQL data itself or the actual schema data so there's going to be links table dot short and then we're going to go ahead and pass in the short value that's being passed into the argument here or the short link rather great and of course it's just the slug here so we'll go ahead and do the short slug value that's what I'll call it just so it's very clear that it's not the entire link but rather just the short slug value okay so this will actually return back a list it will turn back an array for me that I will then have to use in just a moment okay so I grab this and now what I can do is import it into our page so import get short link record from and it's going to be at slash app lib DB and so now we'll go ahead and do our record I'll just call it our record for now with those brackets like that we'll go ahead and await it and pass in short okay so with this I'll go ahead and use a fragment close off that fragment and we'll just do a Json stringify here so Json Dot stringify above that record it will also say if not record we'll just go ahead and return H1 not found Okay cool so now that we've got that let's go ahead and refresh in here what do you know there's our record it's the actual data it's looking good but remember if I wanted to change this create at with a timestamp I want to change the result that's coming through which might be better for the API itself but we can come in here and select and do something just like we did here right so perhaps you don't want the ID perhaps you just want the URL and timestamp in which case you just change it like that and then the data that's going to come back is just the URL and timestamp it's kind of up to you on how you go about approaching modifying what the data looks like when it comes back I'm going to get all of the data because again this is not an API that I need to change how it's consumed because the page itself will change so that's it and if we go to a pay an actual URL that doesn't exist we get a DOT found here because of this H1 that we just did but this is not the best way to do or not found we need to actually use the element inside of an x.js for not found it's really easy to do and we can customize it quite a bit let's take a look at that on our short page right here whenever I actually look up a value that's not in the database I'm returning just a valid HTML string of not found which actually gives me a 200 status code of course if you're aware this should be a 404 status code now for the user it doesn't really matter that much right so c not found is fine I guess but for the browser and to make this actually work the way it should we need to actually have a 404 error now nexjs already has this built in so we can actually import the not found function from the next navigation and then we could just call this function right here so I'll just call it there we go I'll also do if not short I will also call that function before I attempt to look it up in the database now there's a good chance that not short will basically not happen but if it does now we have any not found here so now if I refresh in here I get something went wrong something didn't actually go wrong but it sure seems like it did so inside of my app what I can do now is I can modify the standard 404 page with not found.js and I can actually export a default and we'll go ahead and do a function name of not found and I can return some fragments here we'll go ahead and do a fragment and I'll just go ahead and say this was not found and something like you know status 404. we save it and we got this was not found status of 404. cool well the other thing though is I can actually copy this and paste it into short and modify this a little bit more and we can say this is not a valid jref.io link so now if it's going to the short length that's what it ends up doing so if I go into let's say blog slash something random blog will now say hello detail view because of how we did the blog itself but that again would be just another opportunity to do that let's try how about GitHub some gibberish and there we go so this was not fast status 404 great so by default the main 404 will be you know whatever that's not a valid jref link but the point is that we can actually modify our not found page in the 404 page and this is just how we do it and of course we could expand on it quite a bit but it's actually really really easy to do but the other part is we absolutely want to not have it say there was an error but rather just say it's not a valid link that's it foreign we now have all of the conditions available to us to actually have a URL shortening service work so let's go ahead and shorten this and we give our short here and I'll go to it of course it should render out that same data and yes it does so now what we needed to use is the redirect function so I want to emphasize here that app router works slightly different than page router app router is the modern version so we're going to stick with that and if we scroll down here to functions we see there's a bunch of different functions in here and we've used a bunch of these already one of them being the redirect function here is what we're going to be using now and so we want it to be push as in we want to redirect this page but you can actually have it replaced the same page itself so what we'll do now is we'll bring in from next navigation which is I believe where it's from yep we'll bring in our redirect so redirect just like not found and I'll go ahead and do const URL is equal to the record and we'll say if not URL then we'll go ahead and do another not found okay and they will go ahead and now say actually I could probably make this a little bit better yeah we'll leave it there uh otherwise we'll go ahead and just do our redirect and bring in our URL and I can leave it in as push that's the default and now we don't need to return anything at all okay so we saved that and we go into our short page it already redirected for me so let's go ahead and try it again I'll go ahead and do it from scratch here now and just drop it in to that URL and what do you know it redirects exactly where it should fantastic so this is definitely now working of course there's a number of things that we still want to test out but with this in mind let's go ahead and push this and we'll go ahead and say added page redirect I'll go ahead and commit it and sync those changes and it's a lot of different changes on my end perhaps you have the same now in here we'll finish this develop the deployment itself on versel and then we'll come back okay so it's deployed let's go ahead and take a look at that production version in my case here it is I can now go ahead and shorten a link grab that shortened link go to it hit enter and fingers crossed it actually works what do you know we now have a production version of everything that we've been working towards granted it took us some time but we had to learn about all of these little intricate details to get here we could have just sped through and just went straight to this but I wanted to make sure that we had some foundation and of course we are going to be building off of this this is not where we finish I do want to have a number of other things polished one of the things for my actual production app that you will see it's not actually going to do the redirect because that's there's a good chance that it'll have abuse happen if that's the case what we'll see instead is just like a hey this would be redirected here if we had it turned on type of thing but at this point we now just need to continue to clean up how everything works how it looks foreign and create unique values in our database now one of the easiest ways to do it is to go into your schema and just type out dot unique now this generally speaking works fine but in the case of the URL we need to do slight other modifications so what we're going to do is we're actually going to be creating a unique index now the unique index will make sure that it's Unique before anything else so we're going to go ahead and say links and we're going to set it in in here we're going to go ahead and return a dictionary and it's going to be our URL index and we need to import the unique index value here and this is going to be our URL underscore idx for index and then we're going to go ahead and say on and right now we'll do linkside URL so this right here isn't a whole lot different than just saying unique we'll see why it's going to be different in a moment but for now we'll just leave it as is now what I need to do here is I need to close down my server just to make sure it doesn't accidentally do anything and then I'm going to go ahead and run my migrations which will give me the SQL command I need to run so I'll go ahead and copy this we're going to go ahead and bring it into our database file in the configure database and we'll do await SQL and we'll bring this in now this will almost always be right after the create table it's not going to be unique on the URL itself okay so this index is pretty good so far now if we save this what we need to do then is go back into our console and drop this table right so of course we need to drop that table because what this is doing is checking whether or not it exists and we also want to get rid of everything that's not already unique so let's go and run our application again and we'll come back into our links and at this time we should have nothing in there I should be able to hit shorten and try to do it again I should get errors right the errors don't show up on my app but rather inside the console itself which is good we'll handle those errors in just a second but the thing is I want to make sure that it's Unique always in other words if I used git hub with capital UB in his shortened this actually creates a brand new entry because technically speaking these are unique values because the characters have been changed so one of the reasons to use the index is that we can adjust this Command right here now for whatever reason I can't actually figure out how to do it inside of the schema itself so I'm just going to have to do it on the SQL which is not really that much different than what we've got here except of using this I'm going to use two parentheses then lower all caps and then another parentheses and then URL this will make sure that it lower cases that URL and make sure that it's all unique there now this is an extra step that maybe you don't necessarily need to do because one of the things you could also do is inside of adding the link itself you could just lower case the URL here but this adds a constraint on the database to make sure that the index is lower too so we get those errors if we accidentally don't have it in our code somewhere so with that in mind let's go ahead and close out our application running and then we'll go ahead and drop this table once again because I need to change that and I don't need to run migrations again I'll go ahead and run the dev here and we'll refresh and now if I run shorten it should shorten if I do UB it should attempt to shorten but it won't shorten again it will give me an error because it's now lowered so that's one of the reasons to have a index versus a unique Clause is that I can I can run different SQL commands right on it just like this to make sure that it fits with that but of course in the future it's not going to attempt to make this again so this old SQL is still generally find but it's not going to attempt to try to remake this so of course now we need to actually solve the problem of the error happening with this unique index and display that to our user foreign that's happening inside of this call right here right so now that we have that unique index constraint going on in our database where this is obviously going to create an error or maybe not obviously but that's exactly what's happening so what we're going to do now is we're gonna turn this into a try catch block so go ahead and do try and catch and we want this to be the response and then the next response one that's not valid we'd say something like message like uh let's do URL is not valid please try again it's a pretty simple one as a catch-all for the error and then of course we would just say let response and then we would assign this value in each of the try block itself and then we can just return whatever that is and there we go so this this sort of handles what we want right so it's just not valid okay well the other thing is what we could probably do is we could say well we can break down this error message a little bit but by saying name and message and we can actually console log what's going on here in terms of name and message and it's going to be the same thing that we've already seen which is all of this stuff so let's go ahead and try that again shortened it and we've got the name here and then all of this other stuff is the message okay so there's a couple things that we could do with this right when we go to add the link because we are returning the response here right we have it returned what we could do is just return back that link and not necessarily add a new one that is certainly an option here we could do a different kind of lookup as in the similar to this get shortened link you could totally do that I'm actually going to handle it slightly different than that instead what I'll do is say if I'm going to pass that message in as a string here and then we'll go ahead and say includes well what do we want to check that this string would include in this case I want to say duplicate key violates unique constraint right maybe the whole thing here this entire thing but maybe just duplicate key it's kind of up to you on that but basically the idea being hey it's going to violate this constraint because it's a duplicate key and in this case I can go ahead and say that the response is equal to something like has already been added right so let's go ahead and say URL has already been added great and then otherwise we'll go ahead and use this response which maybe is the default response right so maybe we should say the response is just simply that and if anything else happens we can go ahead and re you know change it as as uh need be okay so we go back into shorten it's already been added if I do GitHub with two bees I hit shorten now it actually works and it works correctly and then we don't have any errors existing any longer just a quick and easy way to sort of manage that issue that would come up and we would want to tell our users that there's a problem there now of course this should also adjust our status code as far as the response is concerned right so when we go into creating this our posts or whether our not our post but rather a link route when we go to create this the response status should change as well so it's certainly possible that we change our data a little bit to also include what the status code is the thing that's coming back from our ad link here this response right here so let's go ahead and do that I'm going to go ahead and say response status and this is going to be equal to the database response okay and perhaps I also want to just have data and response status right both of those things coming back or we'll call this response data so now we've got this and then our response status so coming back into our DB lookup here we can now say our data or response data is that response and then our response status is going to be well most likely 201 but of course we're going to set the default there of response status being 400 like it's not a valid request and then if it is valid if there's no errors here then we'll go ahead and say 201 and there we go so let's go ahead and try that out now with those new changes as well just again improving how our actual site works and how the messaging comes through we've got this already added and if we look inside of our application here we've got a 400 error coming through which again we could validate with uh let's change it to 405 just for an example here and hit shorten and there now it's showing 405. great but of course we want to keep it in as 400. that's just one method of handling how that could happen and of course you might be wondering well can I just do that same cat try catch inside of here and you absolutely could that would probably simplify your db.js but I just think if I use ad link anywhere else I would almost rather have both of these things coming through like this but realistically I also want the response data to be data and status not response data response status so then back in my route what I would end up doing LinkedIn is saying costs response data equals to DB response Dutch data yeah we'll do both things so DB response dot data and then put that in otherwise we'll put empty and then cause response status the same sort of thing and if this status is incorrect then we'll say 500 like it's a server error now because that status should definitely be in there and so there we go that's even better I think so we we do this now and there we go everything's looking good we check back in here and there it is so this of course is happening because of how that list link stuff was working before in terms of how we triggered it right that event trigger great so much better way of handling these errors overall it has multiple checks going on and again we could put this into a try block but I think it's much better to put it directly into the link itself or when we actually make the modification on the database itself [Music] tracking when someone visits one of the shortened links that's like one of the main reasons to have a URL shortening Services you can track when people are actually going to it and what we're about to do will work regardless of if you have a unique URL or not to that unique index we just did so what we want to do is create a brand new table so let's go ahead and jump over into our schema here and we're going to basically copy this links table and paste it right below and we're going to call this our visits table and it's going to be stored as just simply visits and then of course we need to think about the things we want to keep I don't need URL or short although I could keep those things I will keep ID and created at now what's cool about this is I could absolutely store data this way and start storing things in our business table when a link is requested or looked at as we've already seen like you could probably do that now but we could actually make it a little bit better by actually relating these two tables together and that's actually what we want to do so the first thing I'm going to do here is I'm going to import the integer column field and we want to bring in and come in and say links ID or rather link ID and this is going to be that integer and it's going to be linked underscore ID and then I'm going to set it to not null and then I'll go ahead and do dot relate references and inside of references here we're gonna reference it to something at the links table dot or what do we want to reference here well generally speaking you would reference the primary key of the other table so you would reference the ID itself right so that's why I call it link ID and just generally speaking too when I create a table I usually use the plural and then each individual row would then be a singular that's why we've got a link ID now what we want to think about here too is links a single link has many visits or can have many visits whereas a visit a single visits a single visit only has one link right so it doesn't matter what visit it is it only has one link so it has one relationship that way where the links have many so we actually need to Define this as part of our structure here so what we're going to do then is we're going to import relations I can actually just type out relations here and the drizzle orm should come up and it does so what we want is we're going to go ahead and do export const and there's going to be our links table relations now the important thing about these relations Is you can have many of them it just depends on how you want to Define and design everything so the first thing is we're going to associate it to our links table just like that with relations and then we'll go ahead and come in here and we're going to define a callback method that has a couple things we can put in many and what okay so this callback method will then return back a object of some kind okay so what we want to do here is we are connecting this links table from the links table down to the visits table which is this right here it's that kind of Direction we'll put this one down here so that means then I would come in here and say something like visits and then we'll go ahead and do many and pass in the visit stable right so many is one of the arguments that we could use and then I can copy this same thing and do the reverse of it and this one would be then our visits table relations this time instead of the links table we would use the visits table and then instead of visits it would be a single link and they would say one and then we want to grab that links table so one single link okay but of course when we come to declare one we need to be a little bit more specific as to which fields are being connected here so that's done with fields and it's going to be our visits table dot links ID so that's the table or that's the field that we want to connect to the other one which will be then declared with references and that's going to be our links table dot ID which we've already actually declared up here so this is now how they are all linked together right so with this we need to go ahead and run pmpm run migrations and this will give me a bunch of new things that I need to run so that's these right here let me go ahead and copy them and bring them into our database configuration and we need to do a weight SQL paste it in now these are actually two statements notice it says statement break point we're going to go ahead and do another one then a weight and SQL and there okay so now we've got these constraints in here these are foreign key related now and we are going to be able to take a look let's just verify here and I'll go ahead and shorten it already been added great okay so what I want to do is in my console I'm going to go into my SQL editor here and I'm going to try and drop the links table we'll go ahead and run it and now we can't do it right so Ford Keys also sort of help us along those lines which means that we need to drop the other table if we were to want to drop the tables which is the visits table now and we'll go ahead and run that and now it drops both tables and so we refresh in here shorten again now I got that that short URL in here that we can then go ahead and use okay we'll we'll do that one in just a little bit but one of the things I want you now not have going is the automatic redirect I'm gonna go ahead and comment that out and we'll just return the URL that's coming through just like that and we'll save that and now I can go into that link and this will become even more important as we once you start storing this data in the next part you want to track and store visits that is of course when somebody goes to this page here that shortens it we want to track those visits and so how is it that we're going to do this first off in our db.js what we want to do is we want to import our visits table so if visits table from our schema and then we're going to go ahead and scroll down right underneath the get short link record I'm going to put it right underneath here because we're going to save this as save short link record or short link visit let's do something like that and in here this will be then our short link record ID now that's not great because it's called show link and stuff like that certainly get a little bit confusing so I'll just call this save link visit and this will be our link ID now again the link ID and the link visit make more sense in terms of this visit table what we're actually trying to save so the link ID is the field name that we are trying to save it's not necessarily the name that's stored in the database but it's the name that we have inside of drizzle and XTS so we want to save it here now we've already seen how to save something but just as a reminder we'll go ahead and do insert and we where we're going to insert it which is the visit visitors table or visits table rather and then we'll go ahead do values and then pass in links or link ID and Link ID so we could just say link ID value just so that it's not super confusing between these two things this of course is the key inside of the visits table schema and there's the value right there so that's how we would actually go about saving it so let's go ahead and copy this and we want to bring it into our page here and we'll go ahead and import this one and so of course the question becomes well how do we go about saminess or what should we do to go about saving this should we actually save it right here on this short page or should we save it somewhere else let's go ahead and start off with saving it here and see some of the downsides to potentially doing this so we're going to go ahead and await save link visit really all we need is the actual short records ID right so this is the record we have our URL here and then we'll go ahead and say ID which we also want and we'll go ahead and say if ID then we'll go ahead and now save that value okay cool and so we save that refresh in here and so what I want to do now is we'll go into this this value here we'll run it a few times I refresh like several times there now back into the console we'll just look at the table itself for these visits and we got a visit right so I've got an ID of six we'll explain that later but right now it does visit it it only shows one although I wanted many of them right and so of course this is the downside of doing it this way when I say I want many of them I want one stored every time I visit this page now this is actually mostly easily solved by going into the API we're going to make a new folder in here called visits and then a new file in here for route.js and hopefully you already see where I'm going with this and that is we're going to go ahead and do our export async function for host it's going to take in a request here and we're going to go and do const data equals to a weight request.json and then we're going to go ahead and grab the link ID from that data and then we're going to go ahead and do const results equals to oh wait and what are we doing here well we're going to save that link visit so save link visit and we'll pass in that link ID GCS code's great okay and then next we'll go ahead and do the uh next response dot Json empty response and we'll do a status of we could say 201 in there because it's creating it and we can verify the results and all that I will let you do that on your own so for now we've got this results visit here I'm actually going to go ahead and console log the results so we can see what that is and we'll say save visit results in the console log so we can see it okay so with that saved back into our page what do we do now well this goes back to something else we have already seen but I'll go ahead and do it again we'll say async function and then we're going to go ahead and say trigger visit and it's going to be the link ID we're going to pass in that link ID as well so I'm going to go ahead and grip give my options here and the first thing is our method is going to be post the next thing is our headers we're going to go ahead and pass in our content type being application Json and then our body data is going to be Json Dot stringify and we said link ID and that's going to be passed in with the link ID argument there those are our options now next up is our domain so git domain like we've seen before and then finally our endpoint which is get going to be dollar sign domain slash and that was API visits this right here and then we'll go ahead and return oops not Ruthie but return I'll wait fetch endpoint and options and then down here instead of save link visit just trigger visit that's it so now we no longer need that save link visit we'll save that and we'll take a look so go back into that page here again it's no longer doing the redirects we'll go back into our console for the links or the visits themselves and now we've got a few more let me visit again and again and again and okay okay great so we can also verify this inside of the request itself so what we're seeing here is the post request is a hit to the cache but then the actual visit is not cool so this is the post request into the SQL database for the value that's this right here this is going to be a post request and then the actual trigger visits which is going to be this one is not going to be cached or at least it shouldn't be cached now we can we can further verify that it's not going to be cashed in a little bit but the idea here is the reason that this one's not being cached is because neon is doing that work it's making sure that hey you're actually doing a get request you're trying to retrieve data but it's done through an HTTP post request which is what's being shown here but it's still using the cache which is why it's coming back really fast so in other words getting that actual URL value we want that to be incredibly fast right we want that to be cached as much as possible for this particular short string whereas actually updating our database we don't want that cached we want it to be sending it on demand as we see here now if you get into a situation where it is actually caching you can pass in cookies into these headers to then make sure that it's definitely not caching because of this fetch but how it's set up the route and the actual triggering visit that those things should look pretty good and work pretty well in terms of storing the actual visits so now what I want to do is I actually want to see these links display I want to see all of this data I want to see the not just obviously the links stored that we've already done but also all of the related data in terms of the visits themselves now we're going to do relational queries inside of our database lookup for this API data here now if you actually look in the documentation you see that it says db.query.users this of course is different than what we have which is simply db.select we declare the different fields that we want to select and then where it's from like what actual table it's from and so in order to use that db.query method we need to change things just ever so slightly or import a few new things so the first thing I'm going to do is import all as schema from dot slash schema and I'll pass this in to my drizzle declaration here I'm also going to go ahead and import SQL as SQL d as in SQL drizzle the only reason being is neon and drizzle use the same sort of designation for how to use this SQL magic command and they actually do conflict with each other in only minor cases and that's probably not going to last for much longer nevertheless we are going to declare SQL D just like this and so this will help us with our request links that we're trying to get here so we go ahead and copy this get min links here and I'll keep getting in links and then I'll say and visits and then we're going to bring this on in to the actual route for it so the API links route we're going to just change it out just like that and if we refresh in here we do get an error and we'll look at this in just a second now the reason for this error is has to do with the fact that I have a little typo so my visit stable has dot link ID I put visitstable dot links ID this should just be one s there and we refresh and things go back to normal okay great so back into the actual querying itself we're going to just change this to being basically the same by using dbquery so we'll go ahead and return oh wait db.query dot link links table and then dot find many and we'll pass in some arguments here very similar arguments to what we saw down here which is limits we can pass in the lookup limit offsets we can pass in the offset or look up offset we could also pass in the order by and there's going to be an array that we pass in and it's the same thing as we just did so it's like we can just copy and paste that one right in there okay so we save that and let's take a look we refresh in here and now we have some of that data coming through great it's all of the data right now so we can we can change all of the data right now if we needed to in the sense that we can come in here and do columns and we would say something like ID true URL true or actually let's get rid of the ID let's just do URL and let's say for instance like short true okay and perhaps we'd want our time stamp in here as well so go ahead and keep that in or I'll do created at for now and say true okay so we refresh and there we go so same data roughly speaking but I can now enrich it with my relation data so I can actually say with and now we can use the related table light ID here and we can just say true so what's this related thing here I'm actually going to change this ordering up here uh where where did this come from where does visits come from well going back into our schema it's this table relation right here so remember we're looking it up through the links table so then we're doing the relation From Any Given link to its visits right there and that's exactly what's happening in this query so if we save that in refresh we now see all of this data coming through which is pretty nice and then what's cool about this as well is we can take this one step further as well and we could just do created at and saying true right so maybe we just need the time that's all we really need is when that when it actually occurred so we can save that and we can refresh in here and let's make sure that that's all good oh silly it needs to have columns as well so columns and then created that so just like the one before and we refresh and there it goes okay great now we could also most likely do limit and lookup limit or let's just do a limit of five now that actually is going to be on the important side for related data because your related especially with visiting things it could start to get really really big and this could be a really expensive computation because it might take a really long time so more than likely you're not going to necessarily be doing it this way very often but in some cases you will and so that's why we need to know about it now there is one more thing that I want to look at and that is by enriching this data a little bit by adding in something called extras and so what I want to do here is I want to pass in a count of something what is it that I'm trying to count I'm actually trying to count the number of visits for any given link so to do this it takes SQL d and then in here we're going to pass in count which is built in to SQL and I can use dollar sign visits table dot ID and then we set dot as and count we can save that refresh in here and now I've got the visits count that's actually happening for any given short and so if I go to localhost and the short string there go to it a couple times refresh in here uh oh do we have a problem here I'm coming through nothing so if I go into my neon console and go to the visits I've got what six in here more so the way this is being looked up isn't necessarily going to show me everything let's get rid of that limit there and now we refresh and what do you know the count is there so it's not looking up everything it's looking up what's being what's coming through with the query itself now to make it look up everything it starts to get a little bit more complicated and it starts to get outside the the context of this particular lookup or this five mini what you might actually consider doing if you actually want to have a up-to-date count of some kind is actually adding a new field in your links table that gets updated through some sort of Cron job or regular scheduled job that really just queries this table let's say every 30 minutes or something and it actually updates the links table itself because realistically we shouldn't have to count everything on a query all the time that starts to get expensive because it's doing the math literally every time it's going to count how many items are in some related table every single time not incredibly efficient but it's possible you totally could do it but it's just things that you need to think about as you start to scale and also in terms of how serverless Works in general we don't want to have these long queries going we want to have short concise ones going every so often but it is really nice that we now have this related data and we can see all of the events that are associated to anyone actually coming to Any Given URL which I think is pretty cool foreign and create user sessions with a package called Jose and cookies in nexjs so if you're familiar with the concept of cookies but it's a way to pass around data on your application so that the user can have a hopefully a really good experience on your app right but the problem is we don't want to pass in sensitive user data in this case the sensitive data is just going to be simply the user ID now whenever you use cookies there's a potential for someone tampering with it and so we want to address that by encrypting these things so if somebody tries to Tamper the cookie it's encrypted so that then the encryption will fail and require the user to re-log in and thus creating some security within our application so to do this we are going to jump into our project here and we're going to close this app I want to import a couple things or actually install a couple things that's going to be Jose so pmpm install Jose and then we will also run pmpm install Dash D TSX and hit enter as well TSX will allow us to create a command line element which we'll use to generate uh some things related to our secrets now before we go any further going to the GitHub repo for Jose is a good idea because what you can do is you can just scroll down to the encrypted Json web token section section and go to encryption because this is the first thing that we want to do I'm going to go ahead and copy this and bring it back into my project under the in the library and we'll call this sessions dot JS and I'll paste this in here okay so this is what we're going to want to work towards and that is encrypting our data so this right here is an example of our data so to get to this point we need to do a few Imports first off we're going to import everything as Jose from Jose and then I also want to create an exportable function so export the constant of encode user session and this is going to be an asynchronous session because we see a weight here and then we'll go ahead and pass in what data we want to pass in in my case I'll just pass in the user ID because really that's all I'll need for this one okay and then I'll paint uh paste this stuff in here okay so the user ID is what we're going to encode here so I'm going to just change this to being I'll just leave it as simple as just user and then pass that in so that's the encoding that we want to go ahead and do now the next few things we need to extract out of our encode user session for a good reason which I'll show you in a second but at the very end we're going to go ahead and return the token of jot so if we go back into Jose and go back to decryption we're going to go ahead and see how to decrypt this same thing so go ahead and copy this and then we'll go ahead and do export const decrypt user session or decode you could call it decode just to make it less ominous I guess and we'll go ahead and say equals to async again this time it's going to be a jot token that we pass in here and then we're going to go ahead and return some data so I'll paste in everything that I just had okay so one thing we noticed that's the same is the secret itself right in both places this is the same but of course if we expose this secret that means that well anyone this is no longer a secure jot token at all because this is exposed so of course you might be wondering well what do we do well we put it into our environment variables so in this case I'll call it my Jose session key and I'll put it into string right here and I'll go ahead and copy this okay so the length of this actually does matter as you would see if you made it too long so this secret is going to be reused in both of these functions here so I'll go ahead and cut it out and paste it here and just get rid of this one and of course this this decoding process would be now process.env and then the Jose session key okay it's in both places all right so obviously this key right here is not one we will want to use in production just yet but I will say if you change this key then the jot token that is associated to it will no longer work uh in other words the payload won't be undone at all so the next couple things that I want to do is set issuer and set audience I want to actually take those out as well so I'll go ahead and say issuer equals to and we'll take this out paste here and then const audience equals to this right here and these things have to be the same as well and then the time so I'll do const expires at and we've got two hours here I'm gonna actually change it to just 10 seconds for a moment so go ahead and do expires at like that okay so now we've got quite a bit better in terms of our jot token and of course we can reuse all that data down here so down here we'll just go ahead and change this to issuer and audience to audience okay so uniforce resource name I'm going to go ahead and do jrefio and jrefio so obviously both of those things could also be environment variables because they also help with the signing process so the more things you abstract out that aren't directly inside of the code is probably a good idea for security reasons but I'm going to keep it in there for Simplicity and also so you can easily recreate this on your up the other idea is maybe the algorithm itself also being protected perhaps we put those in environment variables as well okay great so this jot token is not the one we're going to use with the coding but instead we're going to do something a little bit more like this okay so at this point what I want to do is I actually want to test this out right I want to test out getting that payload so I'm going to go ahead and create a new function and there's going to be an asynchronous function and I'll just call this uh you know verify session and we're going to go ahead and create first off I'll say user ID equals to the string of one and I want to grab my jot token equals to a weight and we're going to await this encoded user session with that user ID and then const and uh you know payload or we'll we'll actually return the payload here so let's return payload that okay I don't necessarily need that protected header although it could be one other thing that you verify uh but I'll go and say payload equals to a weight this user decode session from that jot token and the payload itself is this data right here right so that also means that I could say user is equal to this payload and now I can console log the user the payload and then the fact if user ID is equal to the user itself great and then I'll go ahead and verify the section with this and we'll console log verify and then we'll do a catch error console log error okay so we'll save that and open up the terminal and then we'll run MPX TSX and then grab the relative path to this session hit enter and we've got expected string but found Jose as an error oh it looks like I didn't put a string around here oops okay now we'll run it again and we got invalid Arc Type okay so this might be a little bit more complicated to figure out the idea is TSX well doesn't necessarily read.emv local so there's many different ways on how we could go about changing or fixing this problem so I can copy this and paste it directly in here and this is just what I'll do for Simplicity purposes just to verify that these things are working with a lot of the defaults so let's go and run it and sure enough it is we've got user one user one here's all that payload that's everything that's coming back to us when it expires all that and then whether or not it's verified great so what I want to do then is I want to also update how I decode this session now the reason being is if I just change this to gibberish like as in an invalid token and try to run it again I get this invalid error right and also if I change it to where let's do two tokens so one's going to be correct and one's going to be incorrect so token one and two and this one is going to be just simply like that so this is the invalid one and the one that we're going to try to actually validate so jot token here right so let's go ahead and try this out and run it again and now we've got invalid I mean one's a it's a real token but it's it's invalid in terms of the other part and then if we make it an in especially invalid token with just adding another character to it as in somebody tampered with it and we run it again now we get another error coming through here so generally the idea is the decoding part is the part that will need to change slightly and so what that means is we'll actually put a try catch statement in here and I'll go ahead and bring in this right here otherwise we'll just go ahead and return null now if you remember the payload itself will have the user value in there as a key so I can actually come in here and say user is equal to that payload and then I'll return back the user so if the user is not in that payload then I can also know that this value is incorrect so now I can just say user as well we don't need that entire payload at this time and then I can run this and I get payload is not defined oh yes so we need to get rid of that let's try it again and sure enough I got null and false and then of course if I changed it to being the correct one as an user ID save that and refresh null and false so that's not a good signed let's go ahead and oh yeah that extra a in there is what caused that so now I get one and true everything's looking a lot better as far as the session is concerned now I'm actually not going to need to verify this session very often more likely what I'll need to do is handle a null error as in no user ID itself which will likely be hey go log in somewhere now there are all sorts of errors here and how you can handle the messaging and all that I'll leave that to you but at this point we now have a way to verify this user session and I'll actually I'll leave that in there by comment it out and then I'll also get rid of this session key here and bring this back into being you know process.eng just like that okay great so now we're at a point where we can start putting this into cookies to see how that all plays out for our user data which is something we'll do in just a moment foreign so still in our sessions module we're going to go ahead and create two methods here to create or set the user session and then also to get it so we'll go ahead and do export const set session user and it's going to be an asynchronous function and it's going to pass in the user ID and then we're going to go ahead and grab that so new session value equals to a weight and this is encode user session of that user ID of course that's the name of this method up here and then we'll go ahead and use cookies so to use the cookies we'll go ahead and import the cookies function and this is going to be from next slash headers and then we'll go ahead and come down here set the session and we'll do cookies dot set and we'll just call this our session ID with this new session value now do keep in mind that this needs to happen in routes.js basically so wherever you have routes this is where you would call this so call in route such as great so that's setting the session value now we're going to go ahead and also export const and we'll go ahead and get session user and this again will be an another asynchronous value here and I don't need to call or I don't need to pass anything in here because we're going to be using git for the cookies so do const cookie session value and that's going to be equal to cookies dot get and what do you know what's the same value as this right here and that's going to be session ID and then we use dot value to get the actual value that's stored there and then we'll go ahead and say if it's not anything we're going to just return return null or just return and if it is something then we'll go ahead and say extracted user ID equals to a weight and of course we are going to be awaiting to decode that session and make sure we pass it in here and then again if it is not extracted then we'll once again return null and then finally we'll go ahead and return that extracted user ID great so we have a way to set it and we have a way to get it so what I want to do then is I'm going to go ahead and do p and PM and we'll just run our Dev project here and we'll take a look at it and so I want to go somewhere where I know for sure it's going to be doing a database lookup as well as it's going to actually render some data out so as far as this is concerned I will go into my links into the page itself and just remember we've got this links table HTML which is coming through because of a fetch lookup with use SWR which of course is in my API so it's in routes.ts like I said this has to happen it has to be in ras.ts ideally it's going to be in a post method after you actually authenticate that's when you're going to set the user session but for now I'm just going to keep it in the git method because we're just kind of testing things out here so I'll go ahead and import the set session user from the session itself and then I'll go ahead and do const and or actually I don't need it I can just do a weight and then I'll just pass in a user ID of some kind one let's use the actual integer of one and see what that does okay so we set the user session here so if I refresh in here and I inspect the element here what I might see is inside of network or rather application under cookies we see session ID here so I'm going to go ahead and delete both of these things here refresh and I see that session ID it's a brand new one from one I just had okay great now I want to just verify this so back into my main page I'm going to go ahead and verify it here so this one will go ahead and import our git session user and I need to change this function to an asynchronous function so go ahead and say const user equals to a weight and git session user and then I'll go ahead and console log this that's a log user okay so going back into links and then go into my home page and what I will see is what if I refresh again what again one but eventually it's not going to be one anymore it's going to be null so in other words this session is no longer valid so that means that I actually don't have a user any longer which we get even further verify by putting in something like user and and you know div of user and so if we say that we see nothing right and then if we go back into links and this should actually recreate that session and we come back now we see user one and you might be wondering hey why is this going away the actual session value is not going away but the user value is well that has everything to do with the fact that in our session when we went to create it we gave it an expiration the session actually expired here so that would mean that the user would have to log back in and do all of that which is cool that is something that we still have yet to do but what we have now verified is we can have a session for user and we can also get that user ID so the things that we can think about here is do we want to put the user ID directly in when we go to create something so let's see save is that what we called it no add link we could probably put that data in here for that user ID we could probably grab what that is so let's try that out and so I'll say user equals to and it's going to be get session user okay so let's just make sure it's doing the correct import here it looks like it is and so again I'll go ahead now just go ahead and console along the user itself so add link and links are all at the same place so if I go into links here it should refresh that session basically every time I refresh this page if I hit shorten it shouldn't console log here necessarily but if I come in here and scroll up I realize it's a bad request because of the links itself but I get oh I did not await it so let's go ahead I'll wait our user session and try that again and I'll just go ahead and run that still a bad request that's fine and we got null here probably because of all the seconds that wasted let's go and shorten it again and scroll down and there's my user id of what cool so it's definitely working and we could use it directly in when we go to add the link itself in the database method itself but of course that also means that perhaps we should have things to handle when there's permission errors and stuff like that but of course before I can do really any of that routing the login and all that I really just need a user table which is not something we have just yet so let's go ahead and create that user table and get all of the relations and all those things done correctly necessary to create our users table to create users so what we want to do here is we are going to copy so much of this links table that we might as well just copy and paste it already and change the places where it needs to be to users table and here here and here and then the actual store table will be users and then we want to change a few things here first off the short itself should be our username and the reason is we want to limit how long usernames would end up being 50 characters for a username is massive but we'll leave it in there as 50 and I'll say not null the URL itself maybe that's going to now be email and then email and we can allow that to be null username and username and then pretty much everything else is kind of arbitrary right so we can add other fields if we wanted to like first name last name and so on but I'm going to leave it pretty simple like this and let you modify it how you see fit next of course is we still want a unique index for this username so we'll go ahead and do users here and it's going to be our username index and username underscore idx and it's going to be on users dot username great so unique usernames now great fantastic so the user tables relations we don't need visits right we need it's parent we need the parents of the visits which is the links and so we can bring this in here and just say links cool so with that in mind we also need to do something similar that we did to visits but now to the link table and that is going to be user ID and we could use basically the same thing as this links ID thing here and just change it slightly for user ID the integer being user ID references directly to the user table now this part's rather important to make sure that it is a foreign key relation so that when I attempt to add a user ID that doesn't exist in the user table an error happens uh which I think is cool and important so the final thing to wrap this up is inside of my links table relations I need to add a new one which of course is going to be our user ID just or rather a user just like what we had here and we'll just go ahead and instead of it being user ID just simply user this time it's not links table but rather the visits table or the user table and so references to the user table and this one is to the user ID just like that wow so now we have relations in many different ways well once we actually migrate everything we will have it first off our user table is connected to our links table which is connected to our visits table but the links table well we might actually not have a user so let's go ahead and leave this as null let's allow it to be null because you know perhaps we want to allow just random people to add links in here as well one other thing that I want to get rid of in My Links table is I actually don't want to have one single URL especially because I'm adding in the links themselves for users I want to allow the users to add as many links for the same thing as as possible because we're just looking for that short URL itself so that's it now that we've got this let's go ahead and run our migrations with pmpm run migrations and of course as you remember that's just simply calling npx generate from drizzle kit and so that's going to create these migrations for me so what I actually want to do is delete all that because I've changed the structure quite a bit so I'm deleting all of those migrations going into my SQL editor here I'm going to drop all of these tables in fact I might even drop every table really uh inside of my database if I had any other tables in here you'd want to drop all of them or maybe even just create a brand new database altogether but the idea being that we're now sort of starting from scratch and so now I'm going to run these migrations again and so that I only really have one migrations file in here because this is now what I want to run okay so I'm going to go ahead and copy this go back into my database here and I'm going to get rid of all of these statements here because we no longer want those and I'll just go ahead and do SQL backticks okay now the important part of this as you may recall is to break up each statement so whenever you see a statement break points you'll put SQL and a backtick and then close off the back takes a course and then SQL and the backtake and we could actually put them on the same level as well and there we go and then SQL backtick and back up get rid of the SQL breakpoint and then SQL backtake down to here again SQL backtick and there we go okay so I think I completed that tedious process um and there we go that should be everything so the reason I did this is so that I don't have any alter any additional alter tables that just aren't necessary so that when I go to run it again PMP and run Dev that my databases and everything should be all aligned so let's refresh in one of the pages here and I'll take a look s like everything was okay refresh again and yeah okay good so we aren't having any issues let's go ahead and shorten this URL sure enough it shortens and if I go and take a look at it or actually visit it and then go to API links I see the link coming through one visit great everything's working so far with that let's go ahead and just change the response a little bit so I'll scroll down here and I'll go ahead and put my user id being true save that refresh in here and I've got null great okay so one of the things you might be tempted to do is based off of when we talked about add link you might come in here and say user const user equals to a weight and this was git session user and then basically saying if there is a user we'll go ahead and do new link and we'll put user underscore ID in here just like that now this should be the database value right because we're inserting this into the database but it might be not that so we'll try it out in just a second and I also want to console log this as well console log what is coming through on that new link okay and so back into my links here I'm just going to grab a random value to see if I can shorten it we'll hit shorten and I get not valid okay so why is it not valid well let's go ahead and console log the name and message that's happening or the actual error itself so we'll save that again we'll attempt to shorten it and it says Canary property of undefined name so let me just I just want to refresh something here and write it again and I'll paste that same Link in shorten it and again not valid so we're still getting undefined name okay so why is that well let's change this to user ID like it is in the user table save that and we are getting the user ID coming through but maybe it's not the valid one let's go back into our terminal and we'll refresh in here again just paste in a link of some kind still not valid and with the dev running now now we see the error that I was going after which is key user ID equals to one is not present on table users okay so what we learned are several things here number one when we insert the values themselves they have to match or correspond to the key values or the declared values here from any given table right so that's what's happening with that that's why it was named or declared this but then when we try to insert it in since it has a foreign key it looks in that other table to see if it even exists and it does not exist so it causes an error saying hey you can't do this right because we don't have any users in our in our database yet because we still need to make that part we haven't done that yet we just made the table that's it but it is interesting to see that this is the the case this is what's happening here um so yeah that's pretty cool that's actually a nice feature of this in terms of when we are trying to add in our user that maybe there's going to be issues related to it as we saw just now pretty cool so now of course we need to actually start registering users and all that but before we get there we need to talk about how to store our users passwords which we never even created a field for so we'll have to do that as well now in a real project that had users as a part of it as a part of its core I would actually create this user table first and I would spend a lot of time thinking about all of the fields that should be in there the glaring one that's missing is password right so we actually absolutely want to have a password field in here and I'm even going to give it a character length of 75. so a character a password with 75 characters is massive but it's likely going to be pretty secure itself I'm actually coming back to this from the future which after we create this field we need to run those migrations so first off I'm going to do is delete this migrations folder here and then I'll run my pmpm run migrations so that I can come back into those migrations files right here and grab this one single thing bring it on over into my DB schema for the users themselves right here we'll go and add that in and then we'll go back into the neon console drop everything and then we'll run our server again and then just load right back into links and then that way we have all of that data in there so then in our database when we go back and look at the user itself we see that password is definitely in there great one of the key things about a password field is to never store raw data you never want to store a raw password itself in your database for a number of reasons one of them it's likely to be hacked instead what we're going to do is we're going to Hash the password uh using a salt key so that's where we want to go towards right and this process is done with a lot of different authentication but especially with storing passwords so to do this we need to actually create another key or key in the first place right so if we think back to even our session data this key is not very good the one we currently have for the session data so let's solve that one first in conjunction with the password one so I'll go into my app here I'm going to make a new folder called CLI and inside of here we're going to call this generate secret or let's just call it generate key.sh and I want to import crypto from node crypto okay and so I want to export the function we'll call this the default function actually and we'll call this generate key and we just want to return crypto dot random bytes we'll do 16 and then two string hex okay so we'll just console log this out to generate that key save it and then and we're going to go ahead and copy the relative path here and then in our package.json we'll come into our scripts and we'll go ahead and generate key and this will be npx TSX of that file save it and now we can run pmpm run generate key hit enter and this should give us a new key and we'll do it twice in this case so the first one I'm actually going to go into my Jose session key I'm going to go ahead and change this one so with this change this is no longer a valid key for this session not this Secret at least so what we need to do is instead of this one we would say const secret equals to new text encoder dot encode and then process.env Dot and it's going to be the same key this should now work as well if it doesn't work then you know you might have to do a different method but this should actually encode the secrets now based off of that value now if you did it too big if you did it at like 32 random bytes it's going to be too large for the Jose session key so the next one is going to be our we'll call this our salt key and we'll pass that in as well so the salt key is going to be generated for our passwords so inside a lib we'll go ahead and do password utils.js okay so the first one is we're going to declare the salt key value and it's going to be process.env dot salt key yep and then we'll go ahead and we'll basically just go ahead and say that's the key otherwise we'll use just simply salt not a great salt is not a great backup the other key is much better but the as far as the length of this key it's a lot more generous than how the Json sessions work with Jose we're also going to go ahead and declare our hash iterations and I'm going to do 10 000. okay okay so next up still from crypto we're going to import the pbkdf to sync and it's a capital s from node crypto and now we're going to go ahead and create a function called export function hash password and this is going to take in the Raw password string and we're going to go ahead and declare our key here being PB kdf 2 sync that's going to be our raw password string the salt key and then our hash iterations 64 and Sha 512 not 612 but 512 and then we'll go ahead and return key.2 string hex great so that will hash the password this is what we'll use to store the password into our database next up we'll go ahead and create something called is matching password so again we'll go ahead and do our entered or let's say for instance our raw password let's change this to entered raw password and then are stored hash okay so it's very similar still but now what we want to do is we want to create the same thing but this time we'll just call this our hash and enter password this time so again same exact method as how we're going to end up storing it and then we want to just verify that the stored hash is equal to the new one or the verify hash and that's pretty much it so what we're going to do then is I'll go ahead and create another function that will just call I'm not going to leave this going for very long but we'll go ahead and do our function and then verify password working and I'll do const PW equals to abc123 and we'll do const hash equals to or let's do PW hash equals to the hash password oh PW and then what could you is valid and we'll do the matching password from PW and the PW hash okay and then we'll just go ahead and call this all right let's copy the path here I'm not going to keep this very long instead we'll do is just run MPX TSX that file itself and we didn't console log if it's valid of course so console log is valid and we'll run it again and we've got false okay so let's go ahead and verify this there's a problem here and that is that we did not do dot to string of the hex like we did above let's try that again and now it's true okay great so the other thing is if we wanted to make it invalid let's go ahead and try this again and this time I'll do ABC one two three four and hash two right so it's just a different password that we will then compare the hashes to and we run that and that's false so what's happening here when you end up doing this on your database level when we actually do the login and authentication and all that we are going to allow the user to enter their password and their username the username will find the database entry and then once we have the database entry we will compare what they entered to the hash that we store on our database and that's what the point of that is right there so that's our password utilities here I do want to just verify that our session key is also working so let's go back into our sessions here and I should be able to verify it by going back into my home page and seeing one as in user one because of going to links and then coming back so so yeah our sessions should still be working and we're definitely a lot closer to being able to actually log in with the user based off of all of this data register and log in of course thank you now we're going to create our register and login Pages they're both very very similar to what we did with the links create form and the original Links Page so inside of our app here we're going to go ahead and create uh we'll call it register slash page.js and then I will also create login slash page.js okay so the first thing is page.js in register I'll go ahead and copy the links one and then I'll also copy the form itself the create form and this is going to be called my register form and I'll even rename this to register form as well registerform.js but everything in here is almost exactly what I want the API is going to the wrong place this should be probably auth and slash register at some point we don't have that just yet and then we will update our actual Fields here so we want to get rid of this default value we definitely don't want that anywhere at this point but we'll leave it in for now we're going to go ahead and say username and then maybe email and then maybe our password and we also might want to have something to confirm a password so we'll go ahead and say do confirm or password and confirm okay so email is of type email and the placeholder should be your email not your url so email pick a username and so on right and so the type for password is password and true with confirming it your password and confirm your password great okay so now that we've got this we'll go ahead and do register it won't have any results yet so we'll leave that as is but the idea being we now have a register form on this register page so we'll do register form from dot register form and we'll render this out it is not going to look great but we can still take a look at it let's make sure our server is running again so pmpm run Dev and a refresh in here and the reason I do the register one first is because the login one is basically the same thing almost identically the same thing so go ahead and copy and paste it and then copy and paste that I didn't really need that original page and I'll rename this to page and then just simply log in form and update the inputs Maybe we'll go ahead and change this to login form and then the only things that we need in here are password and username okay so your username and your password this will just be log in okay so page should go login form from login form and then this one should be registered for okay so we got our register and login both of these things are not great looking really because they aren't good forms as far as how they're rendered which we will still fix but for now we are after testing to make sure that they are working correctly so the first thing I want to do is I really just want to verify the data that's coming through and I'll just do it with register for now in terms of console logging that data so I'll pick a username and pick an email they could pass a password to whatever passwords I'll go ahead and inspect the element into the console and I see this object here and there's our data so we've got a username email a password and a password okay so if you're already familiar with react.js what you could be doing is you could actually verify these passwords inside of the the the um actual you know function itself the functional component itself we can actually rent verify those things here so we could say const verify uh password and have an event that comes in here for when it changes and we could put these things on change I'm not actually going to implement it but I will console log ENT dot Target value so you can see what's happening here with this so that your user interface could then start actually verifying the passwords right inside of the user interface versus just on the back end but I'll leave that for you some other time it is nice to have those event handlers in there it can also improve the user experience quite a bit but the reason I'm leaving them out is because we absolutely want to make sure that we're verifying those things on the back end we want to make sure that the back end will not let invalid passwords or non-matching passwords come through and of course if we try to submit this data we can see the response in there as well so console log the response let's see what that looks like and go back into register and we'll do you know some invalid stuff here hit register inspect we see in console we get a response here and we get a 404 not found because because that URL is not not configured yet of course right so there's no real way to show this just yet so errors and all that sort of stuff we will still need to render out but that's the login and register page now we just need to start implementing the actual functionality for it and of course registration takes in that hash password into consideration which is something we'll do very soon foreign so if we go to our Links Page and try to shorten the link of course we get this not valid error with whatever URL we're on assuming we just refreshed because of that you know user does not exist error so what we want to do now is actually make it possible for that user to actually exist so to do this we're going to go ahead and copy a lot of this links route so I'll just go ahead and copy this and paste it into the API and what I'll call this is register but I'll also put it into another folder called auth so really just auth register and those are the routes we do not need a get request in there and we also probably won't need to set the session yet but we will have all of this other data and so if you actually think about it the data itself is going to be from the form that's coming through so if we console log this data we will be able to see that and right now we'll just go ahead and say it's an invalid URL which we'll just leave in as false but I really just want to see the register data right that's what I want to look at so going back into our page for register I think I already had that API endpoint we'll verify that in a second but I'll go ahead and put a username in here put an email in and then put it actually.com because the browser will validate it and then put some whatever passwords hit register I'll go ahead and inspect the element here into my console I get a 500 error which is fine and then I get these responses here and then there's the object right there and so if we go back into our actual server side we see the registered data right here great so we've got the 500 error it has to do with the fact that I just removed a bunch of things like URL from that response but here's the data that's actually coming through so the to save data if you will is in here as well which I'll leave in here as we'll call this our to save data and it's going to be our username which is data.username and then it's going to be our password which is data.password and then if we have an email which will say if data.enail then we'll go ahead and add this in as well so to save data email equals to data.email because that was an optional value anyway cool so that's going to be our to save data so the next thing is of course whether or not it's valid data so is valid data would be related to data.username we want to make sure we have data.username and data.password and that's it if we have those things great if not we'll say username and password are required just like that or something like that right so username spelled correctly so we can make this a little bit better though so what I'm going to do is I'm going to say username and password and also password confirm okay is equal to data now again that if it valid data we can get rid of data Dot there is another validation that we want and I'll go ahead and copy this and paste it right above and that is data password is not equal to password confirm then we would come in here and say passwords must match please try again simple enough to get rid of this is valid data method again and there we go so we save that now the first thing it will test is you know that password is verified we hit register password's Buffet yes we are on the right track now again we would want to probably put this in our user interface as well because we don't need to hit the back end if we don't need to hit the back end this is a very easy thing to test on whether or not it is hitting the back end but of course at the very end of the day we want to make sure that it is correct so I'll go ahead do one two three one two three hit register and so I get this server error again which is fine but it's not the 400 error again so the thing about this is as well is we probably want to have a method for verifying a good password I'm not going to worry about that method just yet that would be something I'll leave for you but for now we have some validation inside of our post method here all together so after we finish all that validation then we can actually start to add this data in which is going to be where well of course just like ad link it's going to be in our DB so let's go ahead and go into ad link it's going to be very similar to this ad link function I'll go ahead and copy it paste in here this is going to be called register user and it's going to be our user new user data okay so there's a lot of things in here we just simply don't need and we'll go ahead and say uh to insert data equals to new user data and this or rather this is going to be first off our password or rather a username and it's going to be our new user data dot username and then our password what is our password we're going to be do you remember do you remember it's going to be hash password so we come in here and do hash password so type out hash password for the automatic import and new user data dot password and then yet again we'll go ahead and say if new user data dot email then we'll go ahead and put that two insert data of email equaling to new user data email great so now we've got our data here we don't need any of this stuff we don't need the new link there we do have a response here that we probably will want as in like registration register uh you know failed to register please try again so now Link's table is no longer links table but rather users table we can use schema dot because we imported schema dot but I'd rather have users table right there so we'll come back down to that and users table and then our new new user data still returning everything like that duplicate key might also happen as well but what we want here is actually the username so once again I'll go ahead and do columns to username equals to the new user data and just update this where I need to I could probably do it within other data points as well and we'll say username is take it great so in register user this might be another place to just verify that the user is the usernames available perhaps but more than likely you'll want the verification to happen on the post request when it actually is trying to happen where the DB function itself is more about inserting it the only reason I do the hash at the DB function level is to make sure that that is always going to be hashed no matter what okay so now we've got this registered user function here so let's go and import it in we'll import register user here and then we've got our validated data to save data all that now we'll go ahead and register that user with this to save data and hopefully we get everything back correctly so we'll go and save this I don't need these things in here any longer and we'll save it refresh in here and let's attempt to log in and we'll do something like this got a real password or a real username let's try one two three and one two three hit register and what do you know we have a user it did bring back this password which is peculiar that's not at all what we want but we'll look at that in just a second in the database we should look inside the console here and there is our user and it is storing that raw password that's not good at all so we absolutely have an issue somewhere in here so let's go ahead and just verify everything first off we've got our true save data goes to our register user let's go back into our register user and take a look at that new save data new user data to insert data ah there it is we didn't use the two insert data we used the new user data so there's the issue right there save that and we'll go ahead and refresh into first off I'm going to go ahead and drop my database tables and then we'll go back into register here we might actually have to go into links to make sure it it works and just refresh a couple times registers should probably work too but let's go ahead and try that again so adjust the Mitchell and then another email that just simply doesn't exist abc123 abc123 hit register and fail to register try again uh oh very too long for character type varying 75. okay so cool issue cool problem that just came up and it has everything to do with the fact that we hashed our password right so what we actually want to do back to our schema for this password is not have that at 75 but rather just change it to being text so we'll just change it to text and just like that not null again everything's fine and so what we can do again is just delete these migrations and I'll go ahead and run my migration so p and PM run migrations and of course that's gonna change that a little bit only just the definition for that table which is really simple it's just text not null and so back into db.js we will navigate up here and just change that to being text not null save it again go back into our database drop everything and we'll go back into register now we need to make sure everything's running so P npm run Dev and now now it should actually work let's let's see let's see if it works now uh so go into register Mitchell Justin Mitchell and abc123 abc123 register and the moment of truth is fantastic so we get it back it did register if we look into our console into our table into our user here we see that raw or that string of password this is something we'll have to verify with the next login which is great and then as far as the data that comes back um from registration I actually don't want to bring any data back so as far as registered user that well I could bring data back but I really just want to bring once piece of it back so let's go ahead and just bring back only part of it so instead of returning here or we'll leave we'll leave returning in and we'll just change the response a little bit to something different so that it is only a few items here and we'll go and say let DB response equal to that and then the response itself is going to be username and DB response dot username and then created at the DB response.created at that's it we also might want to bring the ID in dbr response to ID potentially so we save that and we'll try it again with it let's try it with the same user and see what happens first abc123 abc123 register and Justin Mitchell's take it great news let's change it adjustmental 2 register and I don't have any indication on whether or not it's loading but there we go it looks like it didn't give me that data back that I wanted um the response turned in oh yeah because it wasn't an array potentially and the response being an array now let's just double check what that response is so we have that data coming through so ABC ABC at ABC one two three one two three register and we're getting an empty data coming through here so it is returning so that is the DB response ah yes we need zero try that again with abc2 hit register and fail to register cannot read undefined of zero okay so let's go ahead DB response data equals to DB response and zero let's try this one and here we go run that again there we go all the data we actually want in this response and for this user fantastic you now can register users the next step of course is the log user's in now it's time to create our login page this one is going to be slightly different than our register page in the sense that it needs to do a lookup request on the database it needs to get back that entry and then it needs to verify the raw password with the hash password so those are the number of steps that we want to do so we want to verify each step individually as much as possible so I'm going to go ahead and copy the register path from the API path and just call this login and then we'll go into our route here and I'm actually going to go ahead and comment out a lot of things up until we'll just get the data first so let's go ahead and actually get and validate some of the data here so first off we don't need the password data here and I don't need to confirm anything I just need to make sure I'm getting the raw data coming through so we go ahead and console log username and password okay and then the response itself I'll just go ahead and give it an empty response back with a 200 status code great okay really simple username and password coming through so of course how do we get this data that is coming directly from our login form and this should just be simply off slash login and then we just want to make sure that our form names are the same username and password and sure enough they are okay great so let's run our project p and PM run Dev and we'll jump over into our login screen here and let's see it running there we go so I'll do ABC and one two one two three we'll hit log in and we get abc123 okay great so that part was successful so what we want to do is we want to get my user DB record right and so how are we going to go about doing that for now I'll just leave it as an empty dictionary but the idea being of course is from the database itself so inside of db.js under registered user we'll go ahead and Export async function and I'll call this get user by username maybe func function in here okay and so we'll pass in the username and then what we want to return of course is a weight DB dot select Dot from and it's going to be the users table and then we'll go ahead and where it's equal users table let's do users table dot username and then we're going to pass in the username great so get user by username back into our route instead of register user we'll have git user by username and then we'll go ahead and say const user record is oh yeah we'll go ahead and do a weight and username and now we'll go ahead and grab our user record here we'll save that and let's refresh in here abc123 now it's possible I don't actually have a user record for that but I do so there's my user record and notice that it's coming back with multiple items here right so what I want here is DB response and then the const of user record Being DB response up zero and then now what I want is stay say the stored hash so it's cons stored user hash equals to user record dot password and as you recall the stored user hash is how we're going to go ahead and verify the raw password right here is matching password so we'll go ahead and say const is valid password request equals to is matching password we'll have that automatically import just like that and then we'll go ahead and pass in the entered raw password which was this right here and then our stored hash and then we'll go ahead and say if is valid password request we'll go ahead and say console log welcome to the Jungle okay so we'll refresh in here ABC one two three this is probably invalid ah it is the correct one so that's the correct password so let's go ahead and try it with something different just to verify that yeah Okay cool so the second request did come through but the first one did so this is now a valid password so all of this other stuff we probably don't need okay now we could totally return back a you know some sort of Json web token back with it in crypto token back with it or we could just set it we could set that user session now so with this in mind we have the user record so we'll go ahead and say user record ID equals to user record dot ID and then we can do a weight set user session and that user record ID okay and this of course is if it's valid but if it's not valid I want to just say something like I don't know basically invalid creds please try again okay so otherwise it's going to set that record so ABC one two three boom I logged in looks like everything went okay because it just rendered an empty dictionary there and then I can come back in here and I see my record of four that's the fourth ID that is the user ID the valid user ID so the way I'd actually go about handling this is in my login form is basically if my response is valid then I'll go ahead and redirect it to the home page so let's go ahead and do that with console log response I just want to see what the response is so go back into slash login here and ABC one two three log in inspect the element here go into the console response and I got a status code right there so basically if the response.status equals to 200 then I'm going to redirect from the navigation to the home page now let's hope that we can just use the raw string like that I believe I can but let's go ahead and try it out with logging in and I get the next redirect we've got an error here that's not actually allowing me to do that so it's probably because of how that navigation Works might not work on the client so what we're going to do then instead is window dot location dot href equals to slash let's see if that works there's definitely better ways to redirect things in the front end of react but there we go log in it logs me in fantastic so response is correct um I do not need the results really right so that's the other thing is I definitely don't need the results in here uh showing you uh I might want to have it load and stuff like that but these are things that you would Implement with the front-end react now get rid of that redirect that's almost certainly like a a back a um a server-side function itself but there we are we now have a way to log in so if we go into links here I believe this comes from at this point already comes from the other one so we got that create form that goes into the API that API goes into our route here which calls well we've got our set user session we no longer want that so I'm gonna have to come back and re-log in actually to reset my user session but the idea being that in here we should have our uh add link so going back into our DB and we've got add Link in here where to go maybe above add link there and there's our user ID from the session so let's go ahead and try this out again we'll log in and we'll do ABC one two three logged in fourth user let's go ahead and add a link in here shorten and there is user idea four there's that shortened URL we can navigate to it and take a look and then we go to API links and what do you know so we've got four is in there and this could also be verified inside of the neon console and there's user id4 showing that up and now we have login register and all that in Associated users to their actual data super super exciting [Music] go ahead and narrow our results based off of the user that's logged in the first thing that I want to do is update the links that I can see which is this get min links and visits so we're going to go ahead and say const and we'll say session user equals to await and get session user and so with that we can actually come down here and say where and this will be EQ and then what does it equal well you might be tempted to say oh well user table dot ID is equal to that session user but that's actually incorrect because we're narrowing down the links table not the user table so I'd grab the links table and then come in here and say links table dot user ID and then through that session user and then that is actually how I would go ahead and narrow those things down which we can verify so let's go into our project here and let's actually log in and I'll give a user of ABC one two three and go into my links here and what I see is Three Links in here and I'm actually going to add a few more remember we got rid of that unique Clause so there's several different links that are basically the same and I'll go ahead and log in again we still need to logout function we will do that in a little bit but right now we've got abc123 and here's just another user that I have and I'll go ahead and take a look at my links here and I only have one link so it's actually really just that simple you just say where the user ID is equal to that and this also works on the other one right so you just do dot where and EQ again links table dot user ID and then the session user which we would then bring up like this and there you go so yet again we could just change wherever we need to to that as well so that's a really quick and easy way to just narrow those results down as we see fit right and of course we can expand on these things to have multiple pages to make sure that we can iterate through over everything that's not something I'm going to do at this time but that is how we can at least narrow down a session user based off of the data they might have it's pretty cool foreign so now we just need a way to log out it's actually very similar to log in except for a few slight variations so first and foremost we need to go into our session and I'm going to go ahead and export a const called end session for user and again it's going to be an asynchronous call here and it's really just going to be cookies dot delete in session ID or the value the name of the cookie okay so now that we've got that we're going to go ahead and jump into our auth I'm going to go ahead and copy the login method here paste it and change it to being log out and then go into the route itself and instead of set session user we're going to go ahead and end session for user I'll go ahead and get rid of basically everything else change the status to Simply 204 and then I'll just go ahead and I'll wait the in session for user and that's it okay so the reason we have to do it in an API route like this is because we're modifying the cookies that's true for creating the cookies and it's true for modifying them as well so back into this route how do we actually call this route of course well we're going to go ahead and again copy the login page and we'll call this our logout page now and this time it's not going to be a login form but rather a log out form and so we'll just change all of these values accordingly and the log out form really is all about are you sure you want to log out that's it there's nothing more to it than that right and then calling auth blog out like that okay so then if the status is 204 then we'll go ahead and return to the login page I don't probably don't need anything else in here and then I'll go ahead and get rid of this and just basically say like a div saying are you sure you want to log out yes continue okay and then if we wanted to go back I'll just do link so link is built into next.js itself and I'll do href going back just to the home page no go call something like that okay and we don't need the set State anymore and let's take a look so into our logout page again to run it to pmpm run Dev go into our log out page here now a big part of the reason you would have it wait so if I say no go home it should go home and it should be fine go back into logout say yes and continue and looks like maybe I have a server error somewhere here yes cookies.delete is not a function oh of course it is going to be cookies gotta initialize that okay so back into logout yes and continue and it looks like we have another issue here invalid response status code 204 okay so it's not letting me say a 204 I'm not exactly sure why but I'll just go ahead and say 200 204 use means empty content that's essentially what that means so let's go ahead and try this again we'll first go into login and I'll do ABC one two three and then we we've got our user ID here and then I'll go ahead and go into log out yes and continue and looks like we have another error let's take a look oh yeah no the error is not actually there but rather it was here okay so we go back into our home page that user is gone up we got another error here ah yes so we actually don't have a value so in this case the value is null so we have to update that so let's go back into our session here and we'll go ahead and say if that's null then return null then we just dot value here okay there we go surprise that didn't come up earlier but it did now so we'll go ahead and log in one two three there's a user and we'll go and take a look at our links here there's our links and if I log out I should be able to log out and sure enough there we go great so uh we've got the logout function working now we just need to improve the navigation overall and maybe some of the the user interface of it all but overall we've got a lot of things going in terms of how our application works we can log in we can register we can log out key things for user authentication and then of course we can associate data now we just need to make it look a lot better if you're anything like me you probably already attempted to deploy this application and run into some issues and so if we actually look at the deployments and we read through we see that reading from node crypto is not handled by plugins so in other words built-in node.js features aren't necessarily available yet I have an inkling that this might change in the future but in the meantime since it hasn't changed yet and I haven't seen any announcements to it changing we have to modify how we handle a few of our hashing passwords as well as our command line interface right here the command line one is super easy you just change it from crypto uh you know import crypto from crypto basically and that solves that problem we also might want to export the const runtime equaling to node js now the other thing about this in particular is well it doesn't actually matter that much that we have this feature so we could totally delete it all together um I'm also going to change this to an await here and the reason for that is because of how this version of crypto the web API version of crypto requires this to be an asynchronous function but it's essentially the same and so then what we're going to do here in the generate key we'll just go ahead and do then X and console log X and we don't need to take this whole thing doesn't need to be in a console log just the parts that we go to generate this so then we should be able to do run or generate key function here and this should work just fine and there's a new key for us that we could use whenever okay cool so now that we've got this let's go ahead and go back into our password utilities how do we actually fix this PD uh kdf to sync function which is actually going to be pbk df2 just the just the regular two no sync involved whatsoever and so I've actually created another gist for this one so just.github.com coding for entrepreneurs you can look for the next JS Dash PB kdf2 and this is going to be what we'll end up using now a big part of the reason to put this into a gist is so we can improve it and so inside of my lib here I will go ahead and add pbk df2.js and paste this in here and there's our new function and so back into our password utilities instead of doing this we're going to go ahead and import the default one from the file itself and we'll get rid of this node crypto here and there we go okay great and so the next thing is we actually don't need this tostring method here any longer and we also are going to be calling no longer sync but just everything else so otherwise it's basically the same I will also change the runtime here and this is going to be simply Edge this should work on edge no problem if you have any issues with it working on edge just let me know but the idea being that we now have this just modified for versl so there's a couple other things that I want to do before we actually push this which would be to remove all console logs just anywhere we have console log with the exception of generate key maybe error functions is fine but the user itself we don't need to console log that and we also don't need a console log requests you know you just want to go through and just get rid of as many of these console logs as possible these were really meant to just kind of show us what's going on with things but we definitely don't need them especially when we expose Secrets I think there's a part where I actually do expose some secrets in here which of course we want to get rid of altogether cool and if you need to you can always go back and change and update things and console log things as you see fit but it's important to get rid of them just so we don't have any leaked data in here whatsoever this verify session we probably get rid of and verify password also get rid of the big one is in the register form we want I want to get rid of that console log as well because that was logging out the actual password that was signed up with and there we go I think we're pretty good on the console logs now and let's go ahead and close everything out I will commit it and do prepare for prod and we'll Commit This yes and then I'll go ahead and sync these changes and then I will let versel finish with the deployments so let's go back into our project here and also into our neon console I want to drop all of these tables because I made some changes to how we actually hash the password there's slight changes but their changes nonetheless and it's not going to be hashed exactly the same as before it's very close but it's not exactly the same so there's a likelihood that that won't be working correctly so we just want to drop those tables and then we'll let this this actual deployment finish all right so now it looks like our deployment was successful at least as far as actually pushing it let's actually see if the website is working correctly so go on there and first thing I need to do is of course register I'm going to pick some random username that's not real and a bad password we'll go ahead and hit register and we've got created at perfect so it actually is working and let's go ahead and log in now again with our user and that password and what we got is invalid creds so it looks like maybe we have an issue with the actual password unless for of course I actually registered it incorrectly so let's go ahead and try again and I'll do cfe2 oh yeah at cfd.com and we'll register it there we go so this time fingers crossed it works see if we two okay so it failed again so hey there jumping in from the future one of the things that for sure failed with our project was the fact that our environment variables do not have the Jose session key and the salt key so be sure to add those things right now and then we'll take a look at the other reason so back into PD kdf2 we actually see that this is an asynchronous function and my password utilities are just simply functions so of course that's a problem we need to change these two asynchronous functions so this is a weight and then async a weight and then wherever we hash this password or whoops not that but rather oh wait here and so we need to check where we hash and where we match these passwords so hash password of course is right here already an async function thankfully so go ahead and do a wait to Hash it and then the next one would be to matching and let's go ahead and check this one and it's already an async function as well so again I'll wait really simple issues that we just needed to fix and so added async to hashing methods commit yes sync changes okay and we'll go ahead and let this deployment work as well in the meantime I'll also drop these tables again because again when we actually registered the user it was incorrect now in the long run what you would actually probably want to have happen is the ability for the user to reset their password by sending an email that's just outside the context of what we're doing here that email would then give them a new route that they would confirm their email and then be able to modify their password there which would then use that latest version of whatever the hashing function that you're working with now of course you're not going to want to change that all the time because it's a bad user experience but that's not something we're going to worry about here it's much more about just getting this working correctly and as securely as possible at this point let's go and check the deployment now and it's already ready great so let's go ahead and register again CFE CFE at cfe.com and we'll go ahead and register created great we log in now actually before we log in what we could do too is just look at the table for that user and see that it looks like a hash password the other one probably was like promise in here it probably didn't actually have a hash password like that so now we'll go ahead and try it out and successful okay great and it even tries to log me in because I redirect or save the login credentials and all that fantastic okay so we solved the major issues here now of course we need to actually make it look quite a bit better than what we currently have so let's go ahead and take a look at that now now we're going to go ahead and integrate flow byte into our application now flowblant has a package called flowbyte react which also has support for next.js but the thing about flow byte is you can actually really easily make your site look a lot better by using a number of the components that are in here without integrating next.js or anything like that so if you actually scroll down and went to say like badge for example a badge these are examples of those badges what you can do is you can just copy the classes here just like this and then come back into your project and we'll go ahead and just grab some sort of element here let's go ahead and go to our login form and down into our button here we'll go ahead and do class name like it's standard react class name we save that and then we go back into our local project and just do log in and you see that it actually changes and that of course is because of Tailwind CSS so the reason that you use flow byte is it gives you a ton of examples like this but as soon as you want to use different kinds of components let's say for instance the navbar component which is something we want and you break this down into different sizes you still need this toggle to happen on your project and that happens through JavaScript which is why we'll end up using you know flow byte react but as far as a reference is concerned for all sorts of Tailwind you know UI elements that you you can just copy and paste flow byte is fantastic for that but as soon as you want some of the more advanced things like even like a mobile and you want to toggle that right you need to do this with JavaScript which requires additional you know extra features that just Tailwind by itself doesn't have okay so with this in mind let's go ahead and Implement flow byte react now we've got all of these items here that we're going to be adding in we already have some of them because of next JS but we'll go into our project and we will run pmpm and and then we'll just add all three or all four or five of those and then we'll just go ahead and let that do its thing and what we'll see of course is in package.json a lot of those things being added like flow byte and flow byte react Chris you could put these in manually and it'll probably work just fine but we're going to skip that next up of course is their exports that they have here in post CSS config I would imagine these are already there but let's go ahead and verify post CSS config already there fantastic again next.js is great Tailwind config this is something we will definitely need to add at least the flow byte related stuff so I'll go ahead and copy these into the Tailwind configuration and so we already have some in here right as you see there so I'm going to go ahead and go one by one and that's going to be this one first and we want to bring in the node modules flow byte so it actually can use Tailwind to look for classes that are inside of that module same with all of our components as we see here we've got app everything and app components and pages so if you use the page router you would still be able to render out all of the Tailwind classes if you weren't already familiar with Tailwind next of course is the plugin itself so go ahead and grab that into plugins and just paste it in there and then go next up is adding in these components here I think these are already here if we go into Global CSS and yes sure enough they are already there that is a standard Tailwind item this is corner I think assuming that you don't already have Tailwind installed and now we can actually start using the flow byte react let's actually see their example here and I'll go ahead and put it into the login form once again so I'll go ahead and import alert from Flow by react and I'll go ahead and add in that alert there and we'll just go ahead and make it a button or an alert after the form itself and so we come back in here and there's our alert now we can actually make this a little bit better and use it if there's a warning right so basically um we'll go ahead and say const and message equals to result and then basically I want to actually we'll let's go ahead and log console log the result first and we'll just see what that result actually looks like with the message because it might be an array so if we put in some gibberish here and we console logged it so let's go ahead and look at the console and we'll see uh that we get a 500 error well that's not good let's see why I'm going to go ahead and just refresh this whole thing and go back into the login page here again some gibberish and again a 500 error Okay so not exactly sure why cannot read undefined of ID so let's go into the route itself is right here so we didn't actually end up handling the login issues so let's go ahead and do something like this and basically say if not response there we go and then the user record I think that would also be another one that's a valid item basically get that user record and then if not ID and password right so stuff we did with the register but we just didn't do it here so if not this and and the stored hash and again and let's try this out hit log in very good okay username and password are required invalid message but nevertheless it does send back a message cool so this is why we go through this stuff is to see if there is a message so then we've got message and and and it's going to be warning and now we can go ahead and just do message here just like that save it and we'll go ahead and get rid of that console log there and this message is actually incorrect we have to do const message and set message and we'll go ahead and do use state of an empty or we'll just go ahead and say null and down here this is where it will set the message and say if result Dot message then we'll go ahead and do set message result Dot message great and so now now that should actually work because we're again we're using reaction here and there's a client element here okay cool so now we can do some gibberish hit log in username and password are required this is obviously not the correct message we no longer need to render out this results here any longer instead it will now render out the message as need be cool so this exact same thing we could do in our register page a register form rather so let's go ahead and bring it in and again we'll go and do const message and set message and they will go ahead and use state of null and again the response if response.message they will go ahead and set the message of the response Dot message actually should be results Dot message again so result there we go and instead of this we'll go ahead and copy the login again copy that and right there there we go so we've got our message and we no longer probably need to even render out the results but we'll leave it in there just in case we do at some point okay great so with this in mind the actual message I just want to change a little bit and say um maybe invalid user or something along those lines so not response or invalid credentials I'll just say invalid creds for now just to make it simple and we come in here replace all of those oh yeah so we've got invalid creds please try again down there and so here we go log in and invalid creds perfect okay so that's exactly what we wanted register let's go ahead and use the same username we just did and this one should also say some sort of error here we've got a bad request coming through so it looked like it didn't even get to that message here so let's go ahead and console log what that is because it should be the same but maybe it's not so we'll save that and we'll run it again and now we've got an array coming back so I actually made a mistake with how I did the issue with either one right so we can look at it either way so go bang back into our register Round Here so the message itself a lot of the messages are just like that right but then when I actually had an issue with the database issue which would be this right here that's the problem that actually came through I believe of course this just takes some intuition to go through this but also remembering back to everything we just did which I've been doing non-stop for the last few days whereas you might be like oh how would you possibly know that well let's just go back into the DB and see our message response here right so we've got this one register user it is inside of an array just to make it the same as the other response the actual returning value when we query the database which I actually don't want I want to make it uh the same sort of single object message coming back all around so let's go ahead and look at the URL as well same thing this just will simplify how I can return any given message and so I just want to check if there's any other brackets here and it looks like we're good okay great so back in here to our register we're going to go ahead and try that again hit register and now see if he is taken correct so um we would almost want to say like it's not available or something like that of course those messages can change but now it's actually working exactly the way we want and we have a much better rendered out message altogether so from here on out the Flow by integration is just going to be a matter of going into Flow by react and finding various things related to it and then actually implementing these components right so all of the components are here not all of these are necessarily needing to be inside a flow byte react you don't have to use this button you can just use the CSS class that's available for that button right now using the button itself just saves time from writing all of these things out right so you don't have to write all those things out and when we want to customize these things if you were to go that route this is a lot easier to customize because you already have some of these colors defined and things that you can customize with Flow by react specifically that's not necessarily available in the standard probiot itself foreign Implement flow byte react to update our user interface quite a bit first off we're going to change the navigation and then we'll add a few other elements this block is going to be a little bit on the longer side mostly because of all of the sort of nitty-gritty things we need to do but overall our actual functionality is pretty much complete now it's just a matter of improving the user interface little by little until it looks and functions exactly the way we want so let's go ahead and jump into the flow byte reactor flowby react.com and go into the docs and into components I'm going to start with my nav bar here so I want the nav bar with drop down so go ahead and click on that one and we'll go ahead and copy this code so in our project we'll go ahead and make a new folder called UI and inside of that folder we'll go ahead and do navbar.js and then I'll paste this in here so go ahead and copy this this import into our layout layout is where we can change all of these things as you may have seen and yes you can actually use these layouts inside of Any Given app route as well to change things if you need to which is really cool but something outside the context of where we're at now so what I want to do is import this nav bar with drop down from dot slash UI navbar now I'm actually going to call this navbar uh for user so let's just rename that to navbar4 user right here okay great so we save this and then I'll go ahead and render out above the children here but still in the body element we'll go ahead and render out this nav bar for user and if we refresh into our project here we've got Avatar is not defined so in the nav bar itself we've got an element in here called Avatar so go ahead and bring that in just like that and of course that's not defined because of you know something with the documentation that was just overlooked but here we go so we now have a few elements here that are really nice now the first thing is the image itself right we actually want to change this to be Ico we say that and then refresh and there is our actual fave icon that's in here now actually rendering images this way is not preferred instead what's preferred is to use the image class so if we type out image directly from next Js and then we actually put all of these things into that and close that out this is the preferred method for rendering out images but of course it's asking for a width and height property so we just want to add those things in and I'll go ahead and say 40 and height being 40. I don't think that that's probably a little too high but the CSS class should actually adjust it as we need to so whenever you see images even if it's flow byte or anything else any other package just use the image class from nexjs this will optimize it quite a bit more and it'll give you warnings when things are not working correctly and that's also true for something like this this Avatar here it's probably fine using that Avatar but I'm actually going to not use that Avatar instead I'm just going to come in here and use that image itself again and just like that and then we'll refresh in here and there's our now our new Avatar and of course the Avatar itself if you wanted the styles for it you'd come into Flow by and.com so just standard Flow by and then you would look for the one that you might want right so if you scroll down you got a bordered one you've got different placeholder icons you've got all sorts of classes in here that you can absolutely use right and then rounded is just simply well we just come in here and do rounded and that is a Tailwind CSS class the height we can actually change this to like let's say three and small being four something like that and then we refresh in here it looks quite a bit weird so go ahead and do with beam three as well and then SM with being three as well or four I'm not actually sure if this particular image will be great for an avatar but nonetheless we can see that we can use that image feature for all of our images which is I think rather important okay so the next thing is are actual links themselves so we've got our navbar brand here and we've got an ahref2 flow byte we don't want that we just want to go to the home page so it actually comes to our home page here and then you know this right here looks a little bit more like a logged in user so I want to actually get rid of some things related to it uh one of them being you know maybe you want to have more details on your user how we actually cache the user and all that you could totally add those details here if you were so inclined I only have the the user ID itself but like I said we could actually have all sorts of other things in here I'm actually going to get rid of a bunch of things related to this and just say uh maybe we'll get rid of the dashboard header there and we'll go ahead and leave just that item of dashboard and maybe we'll put in links as well and then sign out okay so that's going to be our nav bar so let's take a look and there's those things now to make them links what we do is the built-in link element from xjs as well and we use href in this case the dashboard is just going to be actually the home page and then we would want to do this same thing with the sign out method and we'll call it log out because that's what we called it at the URL just like that and then maybe instead of settings we use something like links and links great so the main thing for this is just to improve the navigation altogether and let's go back in here and say links it took us to the wrong URL because I capitalized this on exit let's change that and links and there we go okay cool and so the next thing of course is changing that part of the nav bar which is not a whole lot different and here we can just do that and maybe a links and I'll go ahead and get rid of this and change that to that and there we go so perhaps this is all I want on my home page perhaps not it's really up to you on how you play around with what you want here in some cases you might have to actually change the element to not be directly with flow byte react some cases you will want Flow by react itself okay but this is for the user let's go ahead and copy this entire function and change it for Adnan or anonymous for not just like that so in this case I actually do not want the drop down anymore so I'll go ahead and get rid of that drop down altogether and then I will keep links in there I'll add another one called sign up and then another one called login so register and log in save that and we got the export default again this should be just simply export function and of course it's not showing up this user is not actually logged in so how do we adjust that well it's going to be in layout.js certainly not in the client itself as you may recall the actual server components can use something like git user session or get session user rather and if you recall this is an asynchronous function so we need to change the root layout to an asynchronous function as well so we can have this user and really we want to just check if they're logged in so logged in is equal to user is not equal to null basically that's what the session user should do it's either going to return back the user or return back null and then if they are logged in then we'll go ahead and say navbar is equal to well logged in is navbar for user otherwise navbar for Anon and we can actually initialize these elements here just like this and then we just come down in here and render it out like that okay so now if we save in here we've got our Anonymous navbar we can log in and we do CFE CFE I hit log in this should redirect me and what do you know my navbar changes now there are react pokes in all sorts of context things that you might want to use here potentially if you were going to do this on the client side but I think overall since there's a server component this works actually really well because we were able to grab those cookies and do this really really seamlessly and easily for our project Okay cool so naturally what we want to do is we want to actually update our links here right so I want to be able to see the links themselves and I want to see a bunch of other things related to this so let's log back in and I think I have a problem with perhaps I have a problem with the actual length of time that I've got a user session here let's shorten that and if I refresh there's that link okay great let's go back into our our login element for when we actually save the login we've got our set session user and that's going to be where 10 seconds is way too short and I definitely changed this at some point but we're going to change it back to being two hours but notice that it does log the user out right and it automatically does it for us and we don't really have to do a whole lot so I'm going to go ahead and log in now and now I should be able to see all my links and stuff like that so the the real last thing that I want to adjust here is well that navbar link is not wanting to work there it goes okay so the last real thing I want to change here there we go is going to be how we render out these forms so into react uh Flow by react we can see there's a bunch of different options for rendering out to Any Given form so this is what I want to do I'm going to go ahead and grab this actually let's go ahead and grab the entire example here and the first one we're going to change is our links create form I'll paste this in here and we want to change a number of elements related to this first off the button of submit that sounds good we'll change that one and of course I'm going to go ahead and call this shorten and keep it in as a capital S we want to get rid of that default value we no longer need that default value and then I'll scroll back up and let's make sure that this is not a default function itself I'm going to go ahead and copy the form classes these are directly from um you know where we would look on flowbuy.com or you could also find these on Tailwind as well okay so that just updates that class a little bit next up is going to be the label and the input both of which I definitely want to have I'll go and paste this in here label html4 this is going to be URL and then this will be url.here and the ID we can also use URL and then your url to shorten and it's required just like that and now I can get rid of this element here and just leave the button that's all we really need now I should not need this results thing anymore in the form itself that was mostly just to see what actually happened and then of course the used client has already declared so I can get rid of that and I'll now get rid of this default form here we will come back to that default form again but for now I'll just leave it just like this so we save that and let's go ahead and take a look at our links now of course it says your email that's not correct so let's change that to something else to being like uh enter a link to shorten and there we go so now I have the ability to shorten any kind of Link let's go ahead and just grab a random one hit shorten and what happened let's go ahead and look into our inspect element here and we've got a server response error so we actually do want to see what that response would end up being perhaps it's not a valid response of some kind so let's go ahead and take a look here and I think it's going to be the message thing that we just didn't set here so go ahead and do message and set message and this is going to be use state of null basically if result Dot message then we'll go ahead and set that message and result Dot message and now we'll go ahead and do our alert which I can just type out and it will automatically import it for me and this alert I actually don't remember what the color was we used warning so we'll come back in here color the warning and we'll do message and of course it's going to be message and and then we could save that there we go so we refresh in here let's go ahead and grab any sort of URL I'll hit shorten null is not valid so it's not actually submitting the URL here so perhaps we've got an issue and that's it right here so this type is actually text and the name is URL so it's submitting a no value which is just showed me that you know perhaps I did the input incorrectly now it's the correct input and there we go so we now have the ability to shorten it right there just like that simple enough and a nice and easy way to just show that shortened next of course would be our table itself right so we'll jump back into the docs and into table and then we'll just navigate down and we'll just get this default table here I'll copy this in and inside a table.js here I'll go ahead and paste it in okay and of course this is not what we're going to export I'm actually going to go ahead and copy this entire thing here and we will get rid of this default table call here and so this is actually where I want the table itself and that's going to be right here so granted I don't need all of the rows so one of the things that you can do here is you can toggle down each row so that we only really need one row that we are going to iterate over and that's the point of this right here so go ahead and put the data iteration here and then we'll go ahead and open it up a little bit and we'll go ahead and do maybe our blink.id and we also want to return this value here and then we'll also put a key index in here as well which will be simply our link Dash dollar sign idx I think we did that same thing before we've got a link ID let's go ahead and do our link URL and maybe our I'll go and do my jref.io and then slash link.short and get rid of this table cell and this one we don't need all those Okay so we've got our table rows in here now and what I want to do then is I've got an error with my table body so perhaps I have an issue with some of my cells here let's take a look if they're all closed by just closing them okay and then is our row closed yes so perhaps we need to do a fragment here around the data and it looks like perhaps that's not going to necessarily work so I'm just going to go ahead and put in a t-body element instead of the table body I'll just do tea body and T body see if this causes any issues with it and we're still getting a problem with that we'll have to solve that in a second but let's go ahead and close this out and change the table itself that head cell this is going to be ID this is going to be URL and then short link and then I'll go ahead and get rid of these head cells here okay so let's go ahead and tab this in we've got t-body and t-body and then our actual data class is not wanting to work I see why we need a parenthesis right there and we need another curly bracket there we go and so I could probably bring back the original table doll body class just like that okay so now hopefully we've got a little bit better of a form itself as well as a table for our links okay so let me just see here oh I got used clients in two places of course we don't want to have that and I'll go ahead and import the table at the top and there we go this looks so much better now this link itself the reason I don't actually want it clicked or clickable is I don't want to accidentally click it the ID is not necessarily rendering which let's go ahead and see why this should be link.id it's possible that I actually don't send the ID back with this lookup which is the likely scenario here so I'll go ahead and change that into my DB I think we called it getman links this one right here and sure enough I don't have ID in there so I'll go ahead and say true I could also put created at and all that but there we go so we have this ability uh fantastic this looks so much better in my opinion as far as the shortened links are concerned there's still a good Gap in between here that we don't necessarily need to have but it's kind of cool that we can do it notice that that's not valid cool what about CFE dot sh there we go there's a shortened link that we can copy and go to it's not in it's not in production just yet which it will be soon as far as jhref.io but we're now much better as far as how that looks so the last few things are going to be of course when we go to log out let's go ahead and log out are you sure you want to log out we've got this issue of these buttons here so let's go ahead and and update that in our logout page for the logout form so this time I'm going to go ahead and just do the we'll bring in our button Flow by react and the type being submit and then I'll do color equals to primary we'll save that and primary is not it maybe default we'll look at what the colors are in just a second so let's go back into our buttons here and we've got color gray light so default is just empty let's go ahead and get rid of default and save that and take a look at it there we go so yes continue and then no go home so the link itself can we actually link buttons so let's do href do a quick search for href it doesn't look like the button links itself which is peculiar a little bit so I'll just leave the link in here and instead what I'll do is go into the CSS classes for buttons and now I'll navigate down into let's just do light for the other one which would be maybe the second one we'll do alternative actually and I'll just go ahead and copy this whole thing bring it on over and we'll do class name equals to that whole thing save that come back in no go home okay so the buttons don't really look that great so go ahead and add a margin here and there's going to be margin bottom let's do like I don't know 10. and we'll save that great and our form itself let's go ahead and go back into those forms again and I'll go ahead and add this class right here to our form say that and we'll come back in here it looks a little better it still not necessarily great margin 10 is probably too much let's do two and there just slightly better overall the button class is still kind of big so let's actually change this to just simply button and let's put the href on there and see what happens so I'll do color and we'll leave this in as maybe alternative or secondary let's look at the buttons again for the different colors we'll leave it in as Gray and button okay so no go home and let's click on no go home and it actually does okay so href ends up working on there it's just not in the documentation which is cool so I don't actually have to change anything but now it looks I think a little bit better as far as log out so we'll go ahead and say yes and continue and of course the login page we need to update so let's go into the login form itself and change this one so back into our Flow by react we'll go into our forms here what do you know the first element is a login form so go ahead and copy that and we'll paste this in here we're gonna get rid of that client element there and we probably won't use this whole thing necessarily um which is interesting because all of this is mostly still using just standard Flow by like that form element there so we'll go ahead and do one by one I'm going to cut this out and bring it down here of course and then the actual input itself perhaps we want the label perhaps we don't I'm going to leave the labels in here so I'll go ahead and copy the first few inputs for the password as well as the username element here and we'll bring this down I'm going to put it at the top the first input should actually be username not email because we did not do that the type is text the name of course is going to be username and we'll go ahead and say your username and this should be username and then your username okay password it's not password one but rather just password and then name is password okay and so those things should now be solved and we'll go ahead and do our button and we'll do a type of submit and log in hopefully that imported let's see it looks like it did okay we'll get rid of this login button and we'll come back up and get rid of this whole element here we no longer need that one okay and cut those things out let's look back at our login page much better okay and then we will put our placeholder for a password and we'll just do a bunch of stars great so let's try it out CFE login log in and there we go and it gives a second there we go so naturally we might want to show it loading and stuff like that but I'll leave that for another time and then the next and final one would be our sign up here and this is going to be very similar to our login so I'll go ahead and copy the form itself and go back into our register form and we're going to go ahead and paste this form in okay so of course I need to bring in label from Full bite react I need to bring in text input from flow byte react I need to bring in button from flow byte react great next of course we need so we need an email and we need two passwords one's being password confirmed so your password I'll go ahead and copy this same block here and paste it below and it's going to be the name is password confirm and this is going to be password 2 as far as the ID is concerned and confirm your password as the label the username is pick a username and we'll go ahead and copy this one as well which will be let's see this element to this element I believe yes I think I missed one on the further one so this needs another div around it there we go and we've got that password we've got that password we've got two usernames this should be now email and your email and just use email email and email and then your email okay and we refresh in here what do you know looks a lot better than it did and then I'll just go ahead and add this handle submit oh it's already there great let's go ahead and get rid of that save that and we'll go ahead and do ABC ABC at gmail.com ABC ABC login actually that should say a register okay and I think the user was registered go into our login and we'll do ABC and ABC and sure enough they were great so we can log out now and continue there we go so we now have a way to sign up and register and then what I really want here is if the results actually are successful um then I want to go ahead and redirect them so I'll go ahead and do console log response I just want to see what that response is so abc2 at gmail.com hit register let's go ahead and see what that that response is in our console here and we got a response of 200 so then we'll go ahead and say if response dot status equals to 201 then we'll do window dot href or rather window.location.href equals to slash login and so this is a clientelement which is why I'm doing it this way so let's try another username in here I've got pick a username username let's let's change that there we go and we'll do abc123 all throughout register and boom cool not a very good password as it shows you and we go ahead and log in and there we go so I can do some links here and let's go ahead and grab a link of some kind shorten it and there we go fantastic okay so yes there's a lot of things that we're going to prove still and we'll talk about that in a little bit but for now what I want to do is deploy this and I also want to see a custom domain in here so go ahead and improve we'll put out improve UI we'll commit that yes and then we'll go ahead and sync those changes I can't imagine any major issues happening because we only just changed some things about how it's laid out and so that actually might complete the code itself unless of course we have some major changes that we need to address but at this point uh pretty good pretty good place to be in terms of how this looks and what we can do as far as changing things and just rendering out just general Pages all together it's pretty exciting and let's go ahead and take a look at the custom domain on for cell foreign so go into your project into settings under domains and we're going to use jref.io we'll go ahead and hit add now I don't want www.jref.io instead I just want just the plain root domain here now the reason for that is so my URLs as as short as possible I'll go ahead and add that and then of course if somebody does go to www dot then I'll go ahead and redirect that to jref IO I'll go ahead and add that okay so what we see here if we look at any of these we've got this permanent redirect here as a redirect for it now once we actually prove that we own this domain then it'll start to work correctly and then we'll reassign things a little bit because right now it's just the versel version that's working correctly with no redirect but once we actually verify everything and all that then we will actually redirect that to where it needs to go now in my case I'm going to leave it as a permanent redirect because that's what it's going to be it's so that caching ends up happening where redirects to the correct place but I'm not going to do that just yet because I need to verify the domain so to do this you log into wherever you purchase a domain name and wherever you're hosting that domain name usually or oftentimes if you're new to this it's going to be where you purchased it is where it's going to be hosted you can also transfer this or host it elsewhere both things are are options themselves but the idea here is first cell needs to know that you actually own this domain so you can verify it now in your case you can't actually verify jrefio because I own that domain and you won't have access to changing the records right so you'll need a domain name that you actually own in order for this part to work so I'm actually going to go ahead and verify it now and then look at the next step and I'll come back when that happens all right so after I configured it and did some refresh in here my actual domains are configured correctly and I'm actually routed to them correctly as well I'll show you one of the things that you also need to add to make sure it's routed correctly and you get this same response and that is if you go into learn more to the versel and maybe click on custom domains itself what you're going to want to do is scroll down a bit and use the IP address 76.76.21.21 you're going to do an a record after you verify the domain so after you do that verification process you create an a record for each one of these to that IP address of 76.76.21 2021 once you do that then your domain names will be working correctly as we see here the final thing would be to change the production the versel version of it to then redirect to the jref.io and again I'll do a permanent redirect and save that and now I've got my project deployed and ready to go and I should be able to log in here and see a shortened URL and see all of the various links in here and then finally the last and biggest step that we will have is being able to see an individual link itself and it failed now there's a few reasons why number one we actually need to change our domain name as well so I did a quick stop and added an API for the URL that was coming through this is what we should see but it's not what we're seeing instead we're seeing the versel domain so we need to adjust our local project to do that accordingly and of course you can pretty easily create this URL route here it's this right here that's all it is not a big deal and what I did was I went into our domain so git domain I just changed it to public URL and so then inside of her cell I went into my project settings into my environment variables and I went ahead and added that public URL for my actual public URL especially now that it actually exists the next thing that I did was I actually changed my page.js to have a different runtime and then also to have this try Block in here for triggering visits all of that seem to solve all of the issues that I had with the shortened URL and I think at this point you probably have enough experience to make all of that happen so what I'm going to do here is I'm going to do cfe.sh GitHub and I'm going to go ahead and grab that shortened URL bring it in here paste it hit shorten there's my shortened URL now I should be able to go to it and see this granted I already pushed that code it already built and it already went to production and now it's actually working as it should and then I can also verify that I'm getting the actual stored links so inside of my tables here inside of visits on neon I can navigate down and there is that recent link here and if I go to it one more time one more time and one more time I should be able to see all of that data come through in the table as well just do a quick refresh and then scroll down and there's that same one going through okay great so now it's actually officially working fully end to end we have a way to actually add some links to do that shortening URL foreign hopefully you've got a lot out of this one now I want to leave you with a couple challenges number one how do you implement a feature to ensure that your users are creating good passwords then number two how do you allow them to reset those passwords and that is sending them an email with a special link that link could then be confirmed and then you change the password there that's exactly what I would want you to do from here now of course if you want to see other projects built with nexjs please let me know in the comments so we can get that happening now a big part of this is thanks to neon neon sponsor this project but of course we covered a lot of things Beyond just a database to make this thing happen so thanks again for watching and I look forward to seeing you next time thank you
Info
Channel: CodingEntrepreneurs
Views: 46,428
Rating: undefined out of 5
Keywords: nextjs, vercel, reactjs, react, neon, postgres, serverless, edge functions, tailwindcss, deployment, production, flowbite
Id: NfVELsEZFsA
Channel Id: undefined
Length: 346min 28sec (20788 seconds)
Published: Wed Jul 19 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.