- [Narrator] Hey guys, welcome back to CodingAndCaffeine Channel. And today, we're gonna
build a simple NextJS full stack application with Prisma. So this would be a basic application. So that way you can
get started with Prisma and understanding the
basics of this Node.js and TypeScript ORM. And so we'll use NextJS with this project and for the front-end UI, we're gonna use Semantic UI React and we'll connect the database
with a postgres container in a Docker container. And let's get started creating the project and adding a few dependencies. Okay, so I'm on my desktop and the first thing that I want to do is that I want to create
a new NextJS application with the command npx
create next application. And I wanna give it a name
as my-next-prisma-app. Let's create this one. Okay, so I'm in the project
so let's add dependencies. So in yarnpkg.com, let's find. First thing, I'm gonna use TypeScript so I want to add typescript. Then I want to find a Prisma client. It will be prisma/client. I wanna also add prisma. I will need types/node. types/react. I will need semantic ui css and semantic ui react. When I open project with this code and these are our dependencies. And since we are working with TypeScript, I wanna quick rename my
index and app.js files, and also the api. Or the cancel and make sure
you want to run yarn dev and see if everything is going correctly, it's detecting TypeScript. Project and localhost 3000 We have the project. Okay, now we are ready to actually initialize
Prisma in our projects. So I want to stop the server
and type npx prisma in it. So what we have now in the
project is the prisma folder where the schema prisma
and environment variables. So actually we want to create our schema that we need for that. So I want to actually
create a model called User. So this will have an id of type Int. Just a couple of annotations. Default autoincrement. We will have a firstName of type String. lastName as well, type string. We will have a role of type
of Role that we don't have, but we will have in a moment,
so these will be default. We'll use like developer. Email of type string and an avatar. This will be actually
githubrepostory.png url for creating the avatar. Here we can have the enum Role. So this is user, admin, developer. Before pushing these migrations actually in the database, I want to create actually the docker compose for
initializing our Docker containers. I will maybe accelerate the
speed when I wrote these and you can follow the docker compose. (lofi music) (lofi upbeat music) Okay, this is the docker compose yml. Let's create the container in the batch. docker compose up in detached mode. So I was going to create
my next prisma app in the dashboard of every containers. So as you can see here, is up and running the my next prisma app
in the Docker dashboard. Make sure you grab this
username and password in the environment variable here. So instead of johndoe, random password. You copy and paste this. This will be the database URL that Prisma is going to
use for the connection. So now we can do the migration with the prisma migrate
dev --preview-feature and is going to. Actually, I had another container, but in your case, it will
be your first migration so I will type yes. So in this case, you will
have the name of migration and I just wanna type init. And now in your project here,
the migrations here of init. Okay, let's move on and
create our first API. So actually I want to rename this create. So this will be our first API for Prisma, for creating the user. So this will be exported default async. So request, it will be, I would just wanna
actually zoom a little bit. Request will be of type NextApiRequest and the response, NextApiResponse. This is the function and
instead of doing this. Just wanna write so if req.method
is different from POST. I want to return status,
res.status, this will be 405 and give it a json, a
message, method not allowed. We'll have a trycatch block. In trycatch, I want to
actually create a body. So this will be req.body. I get used to do this, but I realized that I
have some arrays actually. So if you import this and
you do, UserCreateInput and you parse actually with this. Maybe it's going to work initially but then if you want to
create complex objects, but suppose we put this in common. So for me actually, it's
working also this one. So conts user the structuring
the variable req.body. So let's create another variable. savedUser equal await, because
we are in sync function. So prisma.user.create, but as you can see is not
going to recognize the user because we have to run
this command, npx prisma. Actually, it's npx not npm. Okay, so now. So instead of using the
prisma import like this. If you have a lot of connections
is going to give an error. Actually I want to create a
new folder here called lib and in this folder, I
will have a prisma file for having the prisma client globally so I want to write declare. (lofi upbeat music) Okay, so now we can
import prisma from lib. Prisma. So we have the user and
let's create first query and give it data and
this will be the user. And actually, I can cut this one and pass actually the savedUser. And in case of error, I
want to response that status of 400.json, our body will have a message of something went wrong
and I wanna save this one. Okay, now we can close all of this files. Now we want to focus on
the index that we have here so we can delete these main
and also the footer here. We can actually so delete. We can have the Head and
actually we want to use the cdn for Semantic UI
so this will be the link. I want to save this one. Okay, so we will have
a container importing from semantic UI react and this container, just
want to give it a style for having a little bit
of space so margin of 20. Of course, I want to close my container. So we'll have a header as well. So it would be an h3, so this
is the syntax for Semantic UI for having the h3 title. So you can write, this app is
powered by NextJS, Semantic UI and we can also import package.version, and you can import the package version from semantic ui react package. So now it's complaining that we should have one parent element. So I want to actually close
all of this stuff with this and it's not longer complaining. This is pkg.version. So as you can see, we have details. So let's move on and we want
to start under the Header to build the Form. I want to close the Form
and this will have onSubmit. So we'll have async method. We can start to build the body. They will pass to the query
so Prisma.UserCreateInput. So we'll have a firstName, the lastName, a role, email, avatar. So all of the properties are inside here in the node modules of
the Prisma user model. Okay, so now I want to create
actually another lib here, but I will put this one in
the folder called utils, and this utils will have
a file called fetcher. So everything they will
fetch, it will be here. Fetcher. This will have the url
and data as parameter. So fetch. We have the location.origin + url. We can pass the method. Not this but this one. Data or POST, GET. We have the credentials, include. I want to pass headers for
avoiding course problems. You can write Content-Type,
applications/json. And finally the body. We can JSON.stringify. What am I writing? I don't know. The data. And then, lastly,
callback response to JSON and this are fetch lib. So in the index, I want to
continue writing our query so since we are in async
method, await fetcher so you import fetcher from the lib. This will be the URL, so
in our case api/create then we'll pass the
data, so it will be user and we want to pass the body. So this stuff are complaining because of course, we
have to create a hoax. Just after the home, I want to create a
parameter of initialUser. The way we can fetch from
the Prisma every user. The first thing that I want to do, I want to create outside the home here. I want to create an async function. Actually, I just want to
call it getServerSideProps. Even if this normal this function, you write this in the
dedicated dynamic api, but just want to call it
for the love of the meaning that this is a kind of a reset prompts, 'cause it's going to interrogate
the prisma actually query for find the many user. Our users will have a type of Prisma.UserUncheckedCreateInput. And this because in this
one, we have also the id. We're gonna grab this and this will be equal to await prisma. So from with prisma user.findMany. So this is it. This will be the function for
actually interrogate Prisma, giving our users. So return, props of initialUsers and this will be returning the users. So I wanna create hoax for that. Let's destruct to write this so users, setUsers equal useState import
from types of react index, Prisma., actually is the same of this. Well, I'm actually wrong because this is UserUncheckedCreateInputs. And so, again, complaining
because the import here, we should have @. And this will be the initialUsers. Okay, so other hoax will be firstName, so setFirstName, useState. I want this string. Actually, I want to copy this and paste. This will be lastName, setLastName. This will be the email, setEmail. Avatar, setAvatar, useState. And finally, the role of setRole. So we save this one. This is actually just empty and
it's not longer complaining. So under these fetcher, we have the await. So I want to use the setUsers state. So our users and the body. The rest the operator. Set firstName, because you
want to emptied the inputs when we save the first user. LastName. The role null. Set email of empty. Okay, we can move on. Under the Form tag, we can
start to build the Form.Group. Form.Group will have widths of equal. We'll have a Form.Input. This will have fluid the
property, the label, FirstName. So just wanna save this
one and give it a look. Okay, it seems to work. We can have also a placeholder. Same thing. The value of firstName. Lastly, the method, onChange
when we type some input and event as parameter and
set firstName e.target.value. Actually, we can close this Form.Input. Actually I want to just
give it a empty lines so copy this one. This will be the second. Last Name. Last name. How do you call the last name? And setLastName e.target.value. And we will also have the avatar. This will be the avatar. setAvatar e.target.value. Okay, so now instead of having Form.Input, we can have Form.Select. It's gonna be the drop down
actually for selecting. So the value, it will be the role. onChange, just write handleChange and we are going to create this function. So before the return, const handleChange equal, I wanna have a perimeter of event and the value as object. Use the setRole state
and will pass the value. So the handleChange is calling here. So it's complaining
because as you can see, property options is missing in type. So this type Form.Select. So we want to also create
outside the home here. Couple of options in the array. You can also use key for that. I don't know, m, text,
developer and value, developer. So I can copy and paste
this for our three roles. So it will be the user. And a lock, admin. So now I can pass the
options to our Form.Select. So options equal options. I wanna save this so we have the value. Actually you can also fluid
the property and label Role. We can also have a placeholder Role. I want to save this. Let's take a look to our
page what it's look like. So it seems that we have a
few prominent suite, the CSS and we should take a look to our head. And of course, instead of
using a rel in the link, we should put a stylesheet like this. So if I save this one, as you can see, we have a nice and better UI here. Okay, so let's now create a save button. So under the Form.Group, we can have Form.Button and
this will be the Submit. And we have here the Submit's button. And I'm noticing that I have problem because this input should
be aligned on the same line. So let's take a look and of course, these Form tag should surround everything until here before the container. And as you can see, we
have a better looks. We have John Doe, first user again and let's grab a URL and add .png. Let's say I'm an admin and let's see what happened
if I click on submit. It seems that we have
a here a good response. So I want to actually open
tablePlus, this is a free tool for creating your own
PostgreSQL Connection. This was actually my awesome prisma-next. Connect and let's see what we have here. Okay, I forgot to add an email input. It's because we fix this. You can download the tablePlus
for Mac OS and install and having this kind of
motherboard for checking your user. So let's fix the email that we have here, so we can put this before the avatar. This will be the Email. The email and set the email. Okay, so if you want, we can
cover another user, GitHub. I don't know, John Doe
if we have something. Yeah, you know, we don't
mind because it's just empty. Maybe like this or not,
but actually Jane Dane. No matter what kind of Jane Dane. prisma.io. .png. She'll be a developer. Submit this. We have find a nice response. So as you can see the
first one email was empty. So we have here, Jane Dane developer. Jane Dane prisma.io and
this will be our avatar. So the next part is to
create here a simple table and you can find this in Semantic UI. I'm skipping actually
the part where I show you where we can find the
components of a Semantic UI because the aim of this
is just to showing you how we can have knowledge about Prisma. So in this case, we are creating user, but we can have also a delete because this we will need the delete for deleting also the users. So in this case, will be
an export default async, request, response. So trycatch block. And again, as the body
of here, we can log this but this one will be the id, because you have to find the
user id for deleting actually. And the first condition, if
there is no id, response that. What am I writing? Okay, so we'll have an
error, you should have an id. I don't know, you customize
your error message. And return or we create a
user in a variable, prisma. Yeah, our imported user, delete. Where the id. So you don't need to do something like id. And res.status will be
200, return our user. And in case of error, res.status
of 400, json, body message, something went wrong. So we have the delete api method. I guess we can move on and create a table under the Form actually. So the first thing is a called Divider and the Divider could have
also title in the middle so horizontal and we can write Users. We have this kind of code
line for a separate table with title users. And under this line, we can
start to create the Table and a Table will have a basic property. They call this very, celled collapsing. And inside this table,
we can have Table.Header and the Table.Row. And we can have actually three cell so Table.Cell, we can copy
and paste twice times. Actually Table.Row,
this will be HeaderCell. So I have to copy and paste again. So Table.HeaderCell so capital User, Email and we'll create an Action for,
I think, a cool button here. Okay. Outside the Table.Header,
we can have Table.Body and we can start to map
into our users here. That way we can show, because
we have already two users. Open the current braises and users.map. This will be our function for mapping. You wanna have a user
and an index actually. And now we start to create the row. So Table.Row will have a key of index because that should separate the children. A Table.Cell and in the Table.Cell, we will have a Header as. There'll be an h4. We can pass an image. And the image, should
import this one actually. We can take it from user avatar. This could be rounded
size, mini if we have one. So we actually have our avatars here because these, we grabbed
before the last one was the John Doe. So let's continue this
and under the image, we can have the Header.Content. In the content, we can have
user.firstName plus empty, space plus user.lastName. We can have here, Header.Subheader and I want to create a
function for capitalizing. Actually, I want to show
you what it looks like if you put just u.ROLE. So like this admin, so you want to just
capitalize the first letter. The function of capitalizing
will look like this. So under the handleChange function, we can have const capitalize
and this will s as parameter. So, if typeof s different from a string or return empty actually. Otherwise, return s.charAt
0 .toUpperCase plus s.sli. Yeah, I think, it's slice 1 toLowercase . I want to save this and now
we can have this function in the SubHeader. So I want to surround this, capitalize. This is sad, actually. As you can see, we have the code admin. Just want some letter big
texture in admin and developer. Okay, so let's go ahead and we are under this first Table.Cell. Actually we can have
another Table.Cell here and we can have actually user.email. And first one doesn't have because I forgot to put a twin
if made the first request. Actually, let's copy and paste this one. Start to create our third cell. Okay so we can have a Button. I did fast but you should
import all of this stuff here. So don't forget to import
everything from Semantic UI React. So I am on the Button so the Button, we can also have you take
a look in Button here. We can also have some kind of animations, like, you know, this you have
these free animations here. So I'm gonna use just
the fade, so animated. Fade, we will have a color
of red and the onClick. This is the interesting
part for us, so async. No parameters. So again, await, call the
fetcher lib that we have here. And as you can, we have
the api/delete as the URL. We can pass an id and
this will be our user.id. So user.id. Okay, so await setUsers and make sure you want
to then filter our users, because I want to be
able to delete the line and having the other users. User. Let's go usr different from u. Gonna call a naming but you
should follow the convention. Okay, so under the Button actually, I think I have to be here like. Button.Content visible
and this will be Delete. Just take a look until now what we have. It's kinda like a cool. We're missing the other icon. And this will be the
Button I forgot to put. Content hidden. Inside of here, we can have
an Icon name, user delete. Okay, so we have our user delete here. So actually we are done. We should test the button here so let's clear the
console and the network. And if I delete this one. We're good. So we have did delete, but
we actually a problem here. So as you can see, the set user work but if I refresh, I didn't
actually deleted this one. Just want to try to restart. So maybe just a matter
of restarting the server. Refresh this and delete and delete. Okay, so in this case, it's successful. Let's grab another user. I don't know, Jacob? Some random name just
for having a postery. Sorry for you, man, but just for. jacoba@gmail.com. The avatar .png. User. He has no visible 'cause. Daniel Key. Just some danielk@prisma.io. The avatar .png. Let me sync. Yeah. Oh, I forgot. Yeah, but we have here. We have this. Oh, this was before. Well, we have as user, three users. So if I delete this one, we now have. Okay, something, yeah. I delete this one and this was deleted. Our APIs works well. So I'm sorry that I didn't
explain maybe a lot of stuff about the Semantic UI, but this is fine. I found this UI framework very cool. So I hope you guys enjoyed the video. And if you have questions, don't forget to subscribe to my channel and leave a comment below and
thank you again for watching, and I'll see you in the next tutorial.