(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)