Prisma - The Easiest Way to Work with a Database in Next.js (UPDATED)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
(upbeat music) - Hey, it's Ryan at Prisma here, a little while back I did a video on how to integrate Prisma into a Next.js Application and since that time, things have changed a little bit with the Prisma CLI and in particular the commands that you would run to do migrations and that sort of thing, those have changed. So I figured I'd do a fresh video, show you how to wire up Prisma in a brand new Next.js project again, use the new commands and also at the same time show you how to do things like insert data. In the previous video, we just saw how to query for data. So let's take a look at that today, through the context of this Contacts application, just a really simple app built on Next.js of course and using Tailwind in this case and so very simple functionality. We can add a contact in, why don't we add Niko? He works at Prisma, so we'll add him in just like this and I've got his avatar there on the clipboard. Just a quick tip if you didn't know, you can get your avatar from GitHub, if you just do github.com/your GitHub username.png that will give you your avatar. So there's Niko. The problem with this setup right now is that everything is just happening on the client side. So I start with a single contact here, that's myself and then I can add additional contacts but that's just using useState. Everything is happening in the local client state and obviously this is no good. We want to back this application via a real database that has real persistence. So for example, I can just refresh and away goes that new contact. So that's what we'll take a look at today. Let's wire Prisma up, let's get some data into the database and then we'll see how to use it across this application. So to start, why don't we get Prisma initialized? I'll come to the command line here and I will do npm install as a dev dependency Prisma, that's going to give me the Prisma CLI. So this will be a dev dependency and then we'll also need another one for Prisma, which will be a regular dependency and that's the Prisma client. So this one will be npm install @prisma/client and once that's in, we'll be able to initialize the Prisma and get going. So to do that, let's do npx prisma init and Prisma init creates a directory here called Prisma. It creates this schema.prisma file and then you'll also notice this .env file, which points to a database URL. In our case, we're not going to use the default Postgresql that comes here, instead we're going to switch it up for sqlite. So there are a number of different databases that Prisma supports right now. We've got PostgreSQL, SQLite, MySQL, MSSQL and support from MongoDB is on the way, that's actively being worked on at the time of this recording, so document databases are coming as well. So I'm pointing to a URL of file/ dev.db. This is just going to put a dev.db SQL database in the file system under the prisma directory. I've got this concept of contacts in this application of course, as it is a contacts application. So let's create a table to model out those contacts. So I'll create a model called contacts. We'll start with an ID. We will want an ID for this, and I want to mark it with @id saying it's the primary key for this table? And then I'll give it a default value. And I will say, I want to use collision resistant unique IDs, a couple of options here. You can do a uuid, universal unique ID. You could set this as an hint and then just auto increments your IDs. I prefer to use collision resistance unique IDs. We'll need first name here and that's going to be a string. We'll need last name of course, that will be a string as well. We'll have email as a string and of course avatar as a string as well. All right, so we've got our table modeled out and we are ready to run migrations to create our database and get this table into the database. To do that, we will do npx prisma migrate dev and this is a bit new since the last recording. The command now is prisma migrate dev. Prisma migrate has changed somewhat. It's still under a preview feature at the time of this recording, but general availability is on the way. So when we run that, we're asked for a name for the migration, we can say, it's the initial migration and what we get is this migrations directory, which has a SQL file. This SQL file is what's used to actually put the table into the database in this case. And you are able to go and modify these SQL files if you like, before you actually run the migration, so that you can make any changes. So there is the option to go and inspect everything, make modifications, and then run the migrations. So we've got dev.db here. Let's take a look at what's inside, to do that we can do npx prisma studio and this will open up Prisma Studio in the browser. Here we have our contact table and we have all of the fields we expect. No data in it right now, but why don't we add something in? We can just add me in like this. (keyboard typing) I'm going to paste Niko's avatar and just change up the user. That should be good. So I will save that change. Now we've got one record and the idea now is we want to take from the database, when we render that initial view to give us some data, instead of using that hard coded data like we've got up here. So the way to do this is going to be, to get the Prisma client into the mix here and we can use the Prisma client in a few different spots. We can use it here in the, getServerSideProps function and that's because even though this kind of looks like it goes alongside the client stuff, and indeed it does feed data to the client side. This function actually runs on the server. So if you've been around Next.js for awhile, you probably know how it getServeSideProps actually runs on the server and then when it finishes doing it's work, the client view will be rendered. So this is how Next.js does server side rendering. So why don't we get the Prisma clients? We will import PrismaClients from, @prisma/clients. And then we can give ourselves an instance, let's do prisma is a new prisma client. And then instead of hard coding in here, let's do a query. So for that, we can say, const contacts equals await prisma.contact. So there is our contact model and we can do a findMany. So we'll find many contacts. And then once we have that, let's put contacts right there. All right, so if we save this and if we take a look now in the browser, back at our application, I'll just refresh to make sure it's working and everything is working like we'd expect. So we are getting data from the database already. That's perfect. The next spot that I want to adjust, is when we go to save a contact. So instead of just using this, useState update method here set contacts, we still wanna use this, but we also want to of course, save our contacts in the database. So to do that, we can create a function which will be responsible for taking in some data and then saving it off to the database. So this is going to highlight the other spots. One of the other spots we can use Prisma in a next project and that's in an API route. So API routes are of course, routes that run on the server. That's what they're meant for, these are serverless functions and because Prisma needs to be used in a backend environment, this is a perfect spot to use it. So I'm going to import prismaClient here again and in the real world, in a real life scenario, you probably would want to reuse a single prismaClient instance. You would want to do some kind of Singleton pattern and I will link up a video on how to approach that in the description. For now just for ease of use, we're going to new up the Prisma client here in the API routes as well. So import prismaClient from @prisma/clients we'll do our instance again, we want a new prismaClient. And then here in this handler, I've got some setup already going, so that I'm looking for post requests only and I will take in a post request. I will take in the data from it and then save that off to our database with Prisma. And in fact, we can start here by looking for the data. So we can say our contactData is going to be, on the req.body. So req.body. And what we can do here is a JSON.parse and that's because I'm going to be sending this in with fetch and I'm going to have to stringfy the body when it goes to the API with the fetch. So I'll want to parse it here and as I get that, I can do const of savedContact equals await, prisma.contact.create. I'll use the create method and we have to give it some data. And I can say contactData is what will go in. And then once I've got that saved, I will respond with these savedContact. (keyboard typing) All right, so everything should be good here. We might have to do a little debugging once we get a bit further along but we will roll with that for now. So now we'll need a function to send our information to the API route, to actually save that contact. So let's come down here and let's give ourselves an a sync function called saveContact and we can expect contact information to be in there. So we can start here by giving ourselves a const of response equals await fetch and then we will pass the actual path we need, which will be api/contacts. That's going to go to our api routes into this context file and it's going to want to listen, in this case for post requests. So we need to do some configuration here. The method we want to use will be POST and the body for that. We will do JSON.stringfy and we will stringfy the contact information that comes through as an argument here. So now we'll want to check to make sure everything went through okay. And we can do that like this. We can say if response.okay, is false then let's throw an error. So throw a new error. And the error that we want to throw is response.statusText that will give us our actual status. However, assuming everything goes through just fine, we can return await response.json. This is wrapped up in a promise. So we just have to await it, so that we can make sure we actually get the content. All right, so we've got this function now. Let's use it here when we do our onSubmit. So we will still set our context on state like we've been doing. But before that, we will await saveContact and we'll pass through the data that's coming through here. All right, so let's give this a shot. We will save this and let's head over to the browser and let's try putting Niko in again, Niko Burk, here's his email, and let's put his avatar in. Once we do that, looks like Niko's in. If we refresh, we get Niko there persisting and if we check over here in Prisma Studio, there he is as the second record now. So everything is in place for both reading data and creating data. We've done that in two different varieties. We've got getServerSideProps, to give us our initial query for some contacts. And then we've got an API route to where we are posting data to. There's an additional step we can take here with Prisma to improve the developer experience and that is we can use some of the generated types, that Prisma gives, to decorate our code and give ourselves more information about what we can do here within our code. So if we take a look in the node modules directory and the .prisma directory, everything you see in here, within index.d.ts, this is generated by Prisma. So here is our generated contact site. That is what comes from our model, our Prisma model that we created initially and there's a whole bunch of other type information here that we can use across our application. So for example, we might want to bring in the contact type that we just looked at in node modules. And we might want to say that context here is going to be an array of type contact. If we do that, we are able to get more information about what's in that context array elsewhere throughout the application. So for example, down here we can do something with that contact type. And we can say that as we map over a contact, it is of type contact. And that means that we could, for example, pull off various bits of that contact object. We've got all of the properties showing up here, as we create our templates. We can also apply it to useState up here. So we can say that here we will have a contact array that helps to decorate our code a little bit more. And then there's another type that we might want to use from Prisma as well. This one's going to come from a top level namespace of Prisma. And the one I am looking for here, is going to be this, Prisma.ContactCreateInputs. So ContactCreateInput, is what is expected as input, to actually save data in the database. So the issue that we might run into here, is that maybe our database model doesn't map exactly to what's expected elsewhere in the application. That is probably something that you should expect. It's not really the case that you would always have a one for one between your database tables and what goes through the rest of your application. In simple cases like this, you might want to use these generated types from Prisma, but in other cases it might make more sense to generate your own types, maybe deriving from the types generated by Prisma, but maybe not using them, just one for one like this. So we've seen how to use Prisma in a Next.js application, from initializing it, to you getting some data in a database and querying that data and then saving some data as well. We saw how to do so in the getServerSideProps function, as well as at an API route. Another spot to look out for, if you are doing any kind of static generation, is you can also use Prisma in the getStaticProps function. That's an option as well, lots of options within our Next.js project. Let me know if there are any other topics, you'd like me to go over in future videos. You can leave a comment for that or check us out on Twitter. It's twitter.com/prisma. Thanks for watching. (upbeat music)
Info
Channel: Prisma
Views: 18,590
Rating: 4.9548874 out of 5
Keywords: nextjs, javascript, typescript, prisma, sqlite
Id: FMnlyi60avU
Channel Id: undefined
Length: 14min 32sec (872 seconds)
Published: Wed Feb 17 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.