(bright upbeat music) - Hello everyone. And welcome to the GraphQL
with Prisma Workshop. Welcome everybody to
Prisma Day officially. I'm really excited to be here. My name is Eve Porcello. You can find me all over
the internet @eveporcello. You can always send me an
email eve@moonhighway.com. Whenever you have questions
feel free to use that. No statute of limitations
on that. (laughs) You can always feel free
to send any questions my way right there. So thank you all for joining. This is a really awesome group. I'm excited to see so many folks here, some familiar names are on this list. So thank you so much for being here. As I said, thanks to the Prisma team for having me here today. Thanks Natalia for having me here today. I'm really excited to get into it. I'm joining this morning
from, it's morning for me here in Tahoe City, California. I work at Moon Highway. Moon Highway is a training company that teaches JavaScript
and Node.js and GraphQL and React and all sorts of things. We've created some courses
for LinkedIn learning and egghead.IO, and we've written
a couple of books as well. If you wanna share where
you're joining from, that would be really cool too. Northern California is where I am. It is very hot in this
little box today. (laughs) So hopefully it's a little cooler. Oh, no way, we got somebody
joining in from Truckee and Evelyn joining from
Truckee, which is my name. So we have a lot in common. Haiti, Cape Town,
Birmingham, Portland, Oregon, all these west coast people I hope you're hanging in there okay. I think right after this I need to go jump in a body of water. My face is gonna get
progressively more red as this course continues. Oh wow, this is so cool. We got people joining from
the Alps, from Germany. Now that chat panel is where
you can share any questions that you have throughout. There's also a Q & A panel. I will be monitoring both throughout. So if you have any questions that come up, feel free to drop those in there. A little word about our... This is the most worldwide
international audience ever. This is so cool. Little note about our schedule for today. We'll run for about two hours or so today. We're gonna start out with a look at the GraphQL Query Language. We'll look at a quick
introduction to Apollo Server, and then we'll build on that
using Prisma and TypeScript to build and generate our own GraphQL API. So this session is being recorded. I do wanna let you know that and yeah, let's just go
ahead and jump into it. There's a question here. Will you use Nexus and Nexus Prisma? Yes. So we will talk about
that a little bit later in the course today. We're gonna start out
with a look at kind of the GraphQL Query Language
as a baseline for us all. Then we'll use that to
talk about how GraphQL and a tool like Apollo
Server might work together. And then we really talk about
how Prisma gets involved and really powers up
our development process. So we'll talk about kind
of the schema language way, and we'll talk about the
nexus way as you mentioned, which is the code first way. So how do we generate our
GraphQL APIs using our databases? So, yeah good question here. Will we get a recording and
access to the code base? Absolutely. Speaking of that, it's
like I planted you there to ask that question. Here is the repo for the course today. Something I always do is
add links to this page right afterwards depending
on the types of questions that we get. So this is starting
out kind of bare bones, but we will add both the final application that I create no matter
where we end with that today. And then you also have the
slides and some links here that you can get used to get you started. So if you wanna take a
look at that, you can and this'll be what we
work with for today. So
github.com/eveporcello/graphql-with-prisma. Okay, cool. So let's go back to our slides here and we wanna talk a little
bit generally about GraphQL. So if this is your first
introduction to GraphQL, we wanna think about GraphQL
as being this query language that you can use for your API. It's a language that you
can use to ask questions of your data. GraphQL emerged with
kind of one goal in mind. It was to take all of our data
sources, our cloud services, our databases, our rest APIs, and figure out a way to
repeatably get that data into a front end application. GraphQL is a spec. So GraphQL if you look
at the graphql.org page and you click on spec, you'll see that this is really describing a
couple different languages. So the first language
that the spec describes is a query language, a repeatable way of asking our data sources
for this data back. So the query language is
specified in the spec. The schema definition language
is also specified here. So not only do we get
this awesome language for designing in APIs or the questions that we ask of the API, but we also have this awesome language for designing all of our types. So all of the queries, all of the types that are part of our data sets, we can specify all of that
using the query language and the specs specification language. So that's something just to note as we're moving through this is that we have these two different
languages that we can work with. And what's really nice about
a schema definition language, or some sort of language
that defines your types is that everybody can come together and kind of agree on
what is in that schema. So even if you're auto
generating your schema from your database, or if you're
writing your schema first, everybody can use this document
to kind of coalesce around and then go build their own separate parts of the application. All right. So this is kind of how our query looks. So when we send a query from our client, we're gonna send it here to the center, to our GraphQL server. The Graph field server that we'll be using in the course today is Apollo Server. And Apollo Server is going to
work harmoniously with Prisma to collect the information
from the database and return everything to the
clients in a single response. So this is sort of what the
architecture looks like. And because we have that
schema definition language, we can use a ton of the tools that are part of this ecosystem to auto-generate quite a bit of code. So this is one of the really
exciting parts about working with this stack is that we
don't have to write everything from scratch instead, we can
tap into things like TypeScript and the schema definition language to do all sorts of auto
generation, which is pretty cool. All right, so with all of that being said, I wanna start out just
with a little bit of a tour of the GraphQL Query Language. So if you miss this before the video will be shared absolutely, and also all of the files
for the course will be added to this repo here. So a lot of the stuff is here already, but we'll add onto this as continue. But I wanna take a minute to
take a look at a GraphQL API that's already in action. And I'm gonna share that
with you here in the chat. If you wanna head over to
https//snowtooth.moonhighway.com we are going to ask for a little
bit of data from our APIs. Yeah, so there's a good
question here about kind of what will the coverage be of
schema definition language versus code first approaches. We're gonna go through all of that today. We're gonna get a good baseline
with the query language, then we'll get into how
we build a small server. Then we'll build kind of a
schema first version of a server, and then we'll talk
about some pros and cons. Absolutely. Cool. So thanks for that. Keep those questions coming. I'll do my best to stay on top of those. There are 75 of you and one
of me, but I will do my best. As far as continuous integration
and continuous delivery. We aren't gonna get super
into that topic today, but we can point you in
the direction of resources that will help you with the next steps. So really good questions. Awesome, awesome. So let's go ahead and
send a couple of queries just to get us started
just to brush the cobwebs off of our GraphQL life, and just a little bit of
backstory about this API. It is a fake, we have
somebody from Truckee here. It's a fake ski resort
with a real GraphQL API. So we're gonna send a couple of queries. So the whole idea of a GraphQL API is that we can send a query to
ask for some information about our API types. So we will add all Lifts, name and status. Now, when I click play on this, we should see all of these
fields being returned. So this is kind of the core
element of a GraphQL API. We write a query, we define the fields that we
want as part of our query, we send the query to the
API and then it returns the data back without
any extraneous fields. So nothing more, nothing
less is being returned. We know that the GraphQL
API using a tool like this, we have the GraphQL playground. So think about the GraphQL
playground as being this in-browser IDE that we
can use to send queries and ask questions of our data. So the GraphQL playground a couple things about its anatomy here. In the center of the screen
we have our GraphQL endpoint. With GraphQL there's
only a single endpoint. So this is an important thing
to remember as we move along, unlike rest where we have a constellation of different API routes. With GraphQL we have the single one. And we use the query language
to define what we want from that API. Now over here on the right-hand
side of the screen, rather we have all of the different queries that are available on this API. So we can use that as a guide, or we can always take Control + Space to surface a list of all of
the fields that are available, and this is going to
return capacity as well. So again, even if the Lifts had a thousand different fields on them, we're going to be able to
specify exactly what we want and get nothing more back
than what we've asked for. So again, that's kind of the core feature of the GraphQL API. We have a query that is
going to get some data. A query can also, instead of
just returning a list of Lifts, it could return a single Lift. So if I added Panorama here, this is going to allow me
to access just the data about a single Lift. And we do so, we define what data we want by sending a filter here. So we're filtering this
data based on this ID. So question here, will you touch on authentication strategies
locking down API access? Yeah, definitely. So we won't go too deep on those topics, but we will definitely talk
about them as we move along. It's always not always,
but it's often a good idea to build this authentication
into our schema itself. So we'll talk about that as we move along. Okay, so here's our
query for asking for data from a single Lifts. Another thing we should know about the GraphQL query language is that while queries get data
mutations are those values that change data. Those operations, I should
say that changed data. So in order to demonstrate this, I'll leave that previous example up, but I also wanna pull up another API to demonstrate these changes. So I'm gonna go over
to vote.moonhighway.com you can join me over
there if you'd like to. And this is going to be our
demonstration of mutations as well as another type
called a subscription. Again, here in the center of our screen, this is our single API
or a single endpoint for this GraphQL API. The other thing I wanna open up here is in the results tab. This is the front end
for this application. At the moment when we first load this API, we should be able to send
a query to get some data about our two candidates
here, Alex and Eve. So just a little bit of
backstory about what this app is. A long time ago when you used to be able to go to conferences, you could have two different
MCs at a conference, like was the case for Alex and me. Alex is my... And we have mutations coming in already. I love it. So Alex and I were deciding
who should be the host for the rest of the conference. And so we put it up to a vote
using GraphQL, of course. And we already have some votes coming in. So I love it. So when this thing first
loads kind of our types that we're working with, are
results for Alex and Eve. And this is going to let
me know what the totals are for these two different people. These are voting totals for Alex and Eve. Now this is our query. It's going to get some
data about those totals, but as a few of you
have found out already, there's also a mutation called vote. And the mutation is going
to take in a host argument and we'll either vote for Alex or Eve. Now, as soon as I send that
mutation, we see vote here. If I look at the documentation panel, we see that this takes in a host, which is an enumeration
type for either Alex or Eve, and then it returns a string. So it's returning just
thank you for voting, each and every time we do that. So a bunch of people are
voting already, I love it. And we'll notice if we do do
some more voting in real time, we noticed that our UI is
reflecting changes rather quickly. So let's talk through what's going on here on the backend to make this work. (laughs) Very fun. So queries get data,
mutations change data. There's a third type of GraphQL operation called a GraphQL subscription, which listens for data
changes in real time. So we're gonna write a
subscription for a result. These are going to be named just like our queries and our mutations. But now when I click play on this, we see that this is listening. And since you all are very helpful, you're going to send
a mutation for voting. And then all of these changes if we take a look at our playground here, all of these changes are
going to be reflected back to the client in real time. Unlike a query, which
we asked for some data and we get a response or a mutation where we change some
data and get a response, a GraphQL subscription is going to listen for those data changes in real time. This is gonna work over a web socket and GraphQL subscriptions are just kind of built-in paradigm that
is part of the query language and the schema definition language itself. But then these are supported
in tools like Prisma and Apollo Server and many, many more. So these GraphQL subscriptions
came out of Facebook when they were first rolled out. They were used for those live videos where you saw little emoji
heads flying all over the screen and a GraphQL subscription
is gonna help us to keep track of all of this stuff. All right, so thank you for that. I'm gonna say that Alex won this one, and I'll thank you all for voting, participating in the democratic process. Another thing I wanna point
out about that API I suppose is and this is hosted at HTTP. So one other thing I
wanted to point out here. So every time we send
a query or a mutation, it's an HTTP request. So if I click play on
this, we can send along some HTTP headers along with this request. So I mentioned before that
building authentication into the graph into the schema
is typically a good idea. I'll show you some more
examples of that as we continue, but I just wanna remind
you that you can send along authentication details
or any sort of headers that you would normally send
with a GraphQL requests. So for example, we could
send off authorization, or wait, this one is super delicate. So we can set a super delegate
to true, send a mutation, and then what's happening here
behind the scenes is that, and let's pull it up again,
just to see it working. It's way more exciting
when you can see the UI. So the super delegate
here means that my vote is counting 10 times. So that's why all of that
is happening rather quickly. See, someone who's voting for me, we've set those super delegate headers. But the whole point here is
that we're sending that along with that HTTP requests. So all of our clients, like
if we copy curl, for example, and we pulled up our terminal
kind of in plain sight here, we can copy a curl request, which is essentially the
most lightweight version of a GraphQL requests and
alongside the query itself, alongside the location where
we wanna send this mutation, we're going to also send
a little bit of headers superdelegate true. Kind of funny. Okay, cool. So let's go ahead and talk
for a second more about some authentication stuff
and perhaps a better place to talk about this would
be in a different API called the Pet Library. So the pet library I
will share with you here, and I'll make sure to add
that to our list of links from before. And the reason that I wanna
point this out is because, let's go ahead and open up
our documentation panel. So here in the mutations we
have a create account mutation. So I wanna think about as we
start to build our Prisma API and start to think through what types of mutations
are gonna be there. Whenever we're trying to
model some information about our user process. So in other words, when a user is, and in this case our user
is called the customer. When we create an account for a customer, we're taking in an input
type where we have, let's see name, username, and password. So this is a really common request, right? We're sending a create account mutation and then we'll create an account. So let's go ahead and do that. So we're gonna send a mutation and here we'll create an account. The create account mutation
takes in an input type with a name, a username, and a password. And then it returns some
details about that user. Once I've created an account, the next step of my kind
of authentication flow is that I'm gonna create a
mutation or use a mutation for logging in. Log in is gonna take in the username. So EP22 and password. That's password for
everything don't steal it. Just kidding. So then we'll return some
information about a customer, will return their token, and now I've authorized this user. This user is logged in. So now I can mimic the kind of process of authorizing this user
by adding this token to our HTTP headers. So if I wanna add more than
one operation to this document, I'm gonna add log-in here, then I'm gonna add a query called me. Now the me query, think
about this one as being like an authorized user query. If you take a look at say,
Google Chrome over here. So you see my little face in the corner. This just means that
I'm logged in currently with this browser. So I could potentially
send a query like that of me query to populate a
little bit of information about that user. Now, in order for this to work, I need to pass these in as headers. So I'll say authorization, I'll use the term Bearer
and paste in that token. And let me paste it in right. And everything needs
to be pasted in as JSON or handled as JSON with
quotes around the key and quotes around the value. So now let's try to send the me query and it looks like I've been authorized. So there's two things
kind of at play here. Inside of our schema with our
kind of schema first approach, what we've done here is we've said, Hey, there's a type called customer. And anytime I send the me query, I wanna be able to return that. I also wanna move through the... I also wanna move through kind of the, let's see the flow of logging in, of creating an account, of checking in, of checking out, et cetera. And Daniel just shared
a great article about the kind of schema first approach versus the code first approach. So I wanna talk about this
a little bit as we go along. The whole reason we're kind
of moving through our examples in this way is because taking a look at the query language first,
then building our own schema and then using a tool like Prisma kind of shows how there are
trade-offs with everything. But it used to be that we could kind of think about our GraphQL servers
from the schema first only, but now there's a bunch
of really cool tools for auto generating a
schema based on our data. So this is a great article to check out the whole idea of schema first design just to define it means
we're gonna write a document and we'll do this in a second. We're gonna write a schema document first and then we'll write all of the resolvers. We'll write all of the functions to return data for the schema. But obviously there's a lot of other ways of approaching this and
a lot of trade-offs. So thanks for sharing
that, that's really useful. So those are some examples
of how we can build authentication into our schema. Just thinking through
kind of how this works, no matter which approach are you using, it's really important to
build that into your schema because kind of handling
authentication is going to affect everybody all over the stack, and this is a good way to
think about this stuff. We've model it in the schema and then we can write the
resolvers to make that stuff work. What questions do we have so far? All right. Cool. Well, yeah keep them
coming if you have them. Asking about questions is not
just so that I can (laughs) not just so that I can drink water, but that'll get us started. Okay, cool. So let's go ahead and we're
going to do a small demo using Apollo Server, and this will get us in the mindset of using a schema first approach, which we will then
build upon using Prisma. So we're gonna take the next
little while to work on this and we're going to do so, we're gonna first create this locally. And if you get stuck
anywhere along the way, I will upload all of the
code right after this. So you can always feel
free to just watch along if you'd prefer. So I'm gonna open up a terminal, then I'm gonna pull up an example. And there's a good question here. Are we only going to touch on net nexus or are we going to do
a full implementation? So a little bit later in the course today we probably will touch on nexus. We'll be prioritizing
a Prisma implementation of a GraphQL API, but I'll
definitely show you how all of that stuff works together. Great question. Another good question here, and let's pull up our
API to talk about this. This is great. So for a general GraphQL
response best practices, is it recommended to send back a response with the structure of data and air where one of them is populated
depending on what it is. I remember having an issue
wrapping my head around how to do responses properly. So that's a really good
question and it's a question that I feel like it depends who you ask and it depends on the situation. So your question is a good one. Let's say I have a query for a Lift. Currently our Lift query
returns a Lift type.. But there's another prevailing theory in the world of GraphQL that we shouldn't actually
be returning a Lift object. Instead, we should be returning what's called a GraphQL union type, which is either going to
be a Lift or an error. So this kind of idea was
popularized by Sasha Solomon. I just had to clear out my history because of a website that was broken, but there's a really good air
handling and GraphQL example. I'll add this to your resources as well, as well as drop it in here. And kind of what the
approach here says is that instead of just returning a user, we could return either
a user or some errors. So this is what's called a... Let's scroll down a little bit. This is what's called a union type. Now a union can return one of
a couple of different things. So for example, you could
model all of this directly in the schema. So regardless of which
approach you're using, whether you're using a code first approach or a schema first approach, it is sometimes useful to
think about a GraphQL request as being in one of a couple states. Either it's fulfilled we
have some data to return, or we have an error. So I will hesitate to say
that that's the best way to do it or a best
practice, but it's certainly an approach that has gained a lot of steam based on this conversation
because we wanna be able to handle all sorts of
different use cases. We wanna be able to handle situations where we get some data back or partial data responses
or things like that. So if you want more information about how to set this up in your own APIs, you can check out this article. I think it's a really good one. There's also a video that you could watch if you're more of a video person. And somebody just asked the resources mentioned here will be
available on the GitHub, which will be shared, absolutely. So right now I mentioned that our GitHub is a little bit bare bones and that's sort of
intentional because especially in a group of this size, I
go off on a lot of tangents, but you'll see I'm putting
together a list of notes here and I'll add all of
those links to the repo as soon as it's over. Great question there. So yeah, I would definitely check out this air handling idea,
think of a union as being where we can return one of many things. So a good example of a union
is here inside of our query. We have a search. And the union is going to
return a search result. What is a search result? Well, a search result is
either a Lift or a Trail. So what this means is
that I can send a query for a search term. And if I search for say
S, this is going to return a list of all of the Lifts and Trails that match that search term. So it's allowing me to return a list of different types here. We also noticed with this
search for a union type that it's only letting
us select the type name and that's because I
have to use what's called an inline fragment to
actually access this data. So here I could say on
Lift and then for each Lift that is returned as part
of this list, I should say. We're gonna ask for just
a name from each one. So now we see Snowtooth, we see summit. And I guess that's it. We could also add this for
a Trail I could say on Trail and add name and status for this. So now if I scroll down a little bit we'll see that name and
status are returned. Anytime we're dealing with a Trail object, just name is being returned for a Lift. So I think it's really
important to talk about the query language early and often when it comes to any
discussion of anything in the craft fuel ecosystem. Because as soon as you start
to work on these projects, you're going to need to know how to ask for the correct data. And this is what's
called an inline fragment and it'll help us return specific fields about these unions like search result. So that's a little bit of an aside, but a worthy transition over into that. All right, so what I'd like to do next is I wanna show you a brief
demo of an Apollo Server that is the backing for our Snowtooth API. And the reason I wanna show you this first before we get into the Prisma stuff, is because this will show you
some of the building blocks of how this Apollo Server is put together. But it's also going to show us
kind of some of the benefits that we get from using Prisma. So what I wanna pull up is a repo here and you can choose whether
or not to download this. I will share this here in the chat, and we'll make sure that this is added to your student resources as well. Now, this starter kit
here is an Apollo Server, which we will run using our terminal. So the first thing we
wanna do is make sure that we're somewhere on our computer where we wanna download this thing. Then we wanna get clone that repo. We wanna then move into the
repo, the Snowtooth API, and run an NPM install. So what this is gonna
give us is a whole list or let's go ahead and open it. So what this is going to
give us is a whole list of Lifts and Trails that are
inside of our data folder. All right, so visual studio
wants me to trust the author, wants me to trust myself. So here we have some data for
our Lifts and for our Trails. And really the whole process
of setting up an Apollo Server is that we're gonna need
to handle getting the data and serving it up on a GraphQL API. So we're gonna take this really minimally just to kind of show the
core pieces of how this works and then we'll build onto
this concept using Prisma. All right. So first things first, I want to require Apollo
Server from Apollo Server. The next thing I wanna
do is to put together my type definitions for my data. So specifically here, I'm gonna
use a function called GQL. And GQL is going to take the
string for my GraphQL API, and it's going to make this
available on our server. So we'll get to that in a second. We're also going to define
some resolver functions, and finally we will
create a server like this. So we'll say const server is
equal to a new Apollo Server. And this takes in the type
depths and the resolvers. The final step here is that
we'll call server.listen, we'll chain on a dot then function. And we'll see that this is now
running at localhost:4,000. So the default port server running at URL. Another thing I wanna
mention here is that the API that we're building, if
you wanna take a look at how this continues GraphQL workshop, there is a complete branch
that you can use instead. So how would I model this
data in a schema first way? Well, what I would do is I would take a look at my data source, so my database essentially here, and I'd look at all the
fields that are part of this, and I would decide which of these belong in my GraphQL schema. So this is a very manual process. I'm going to open this to the right, and then we're going to say type Lift. The Lift will have a
name, which is a string. It'll have a capacity, which is an Int. We're using the GraphQL
schema language here to define our schema. And we're doing this writing it by hand to model all of the fields that we want. So let's add night, which is a Boolean. I'm not gonna do the whole thing here, but we'll just decide which
fields that we want here. And then we'll say type query. And the query type is going
to have a query for all Lifts, which should return a
list of Lift objects. So obviously pretty minimal here, but we're able to start
to put this together. The other piece that every
one of our GraphQL APIs has is resolver functions. So think about resolvers
as being functions that return data for our API. So we might have to write
resolvers for all of this. So I would say all Lifts should return. Whatever I've said it should
return inside of this query inside of the schema. So to keep it real minimal,
I'm just gonna return Lifts. So I'll return the entire
JSON object right here. Cool. So the next thing I wanna
do is start this thing. The way that we can start the project is we're going to type node index. This will say that our server is running at localhost:4,000. And if I check this out in our browser, let me zoom in, we'll see name, capacity. I should be able to send that and we should get that data back. Really good question one. When is it not advised to
use non-nullable fields? So over here in the schema, the way that we say that
something is nullable or non-nullable is to
add an exclamation mark. So when we add an exclamation mark, it means that the value is required. So if name didn't return a
string in a certain situation, there would be an error. Now when GraphQL kind of started, it was advised to use just
make everything non-nullable. Everybody was using an
exclamation mark everywhere. And then what I would say is
that a more moderate approach is probably a best practice
when it comes to nullability. So what I mean by that is
if you truly need the value, then make it non-nullable. So things like IDs, for example probably a good idea to
make that non-nullable because everything should have an ID. But if something feels kind of extraneous, like how long it takes to get up the Lift or the night or something
like this, I would omit that. So there are a lot of good articles about nullability in GraphQL I will share a bunch of those. I'll share one of those now. And let's see. So if you wanna learn a
little more about kind of the Prisma client approach to it, I've shared that over there in the chat. But what I would say is that
if you truly need the value, then make it non-nullable. But if it doesn't seem like
that important of a value, then you can probably skip it. And there are some schema design
techniques that you can use to make that a little bit easier as well. So we could spend probably a 24-hour class on nullability in GraphQL
to decide what's best in what situation, but as we use tools like
Prisma and things like this that will help us to handle
nullability a little better just because a lot of our
code will be auto-generated. So I hope that helps a little bit. I know it's not too deep on that topic. We will share some
other resources with you toward the end of the class and make sure that those are added to our list of links. Let's also add that to
my notes for myself, so that that makes it in. Okay, cool. So back to our example here. Now, this query if we click play, this is kind of the approach of a schema definition
language first approach. We take a look at the data. We model the data in GraphQl's
schema definition language, and then we write some resolver functions to return some data. I think it's really important
to understand the relationship between the schema and the resolvers. Just think about the
schema as being the types. The resolvers are the
functions that return the data from wherever it is. Now, building on top of this though, we do want to reap the
benefits of a lot of the tools from the ecosystem. So I wanna take a little break. When we return from our break, we will start to build our own demo using a combination of
Prisma and some other tools. And then we'll talk about
nexus and how that fits into everything we're
talking about this far. But let's take a little break. We'll take a 10-minute break. I'll set a timer. I know there are some questions coming up I'm gonna flag them all and not answer them during the break 'cause I wanna encourage
people to go on the break, but feel free to drop those questions in and we will talk about how to... We'll talk about all of
those as soon as we get back. So 10 minutes, I'll see
you back here real soon. All right, everybody welcome back. Welcome, welcome. I said my face would get
progressively more red as this course continued and I'm making good on that promise. I'm glad to see it. (laughs) We will all survive our heat wave here, but before the break, we talked about how to build
a small but useful API. Let's see, kind of using
a schema first approach, building our own resolver
functions and things like this, but it's often useful
to reach for other tools to help automate some
of this stuff as well. So within your student files, we're going to use from
this list of examples. And I just wanna point out this repo 'cause I think it's incredibly useful. If you look at this
repo of Prisma examples, these are some example projects that are kind of ready to go, and they highlight all sorts
of different approaches to the same types of problems
that people run into. So depending on which stack you're using, which approach you're
using, et cetera, et cetera, this is going to help you get started with some of these starter kits. Now specifically the one
that we're going to use today is an example that includes
Apollo Server along with Prisma. So what I've done here
is I have a list of... Or I have a curl command that I'd like for everybody to copy. Will it be bad if I paste
a curl command into Zoom? What if that just like made Zoom explode, but it seems to work fine. What we're gonna do with
this is we're going to use this command in our terminal wherever we want to create this project. So let's go ahead and do that here. We're going to navigate
to the Prisma demo folder on my desktop. Then we're going to
paste that curl command, and it will install the
project inside of the demo app. So let's all make sure
that we get to that point. Let's see. If you have any struggles
downloading that project, just let me know. Or you can put your favorite. Can you put an emoji into Zoom, probably. Yes. So you can put a smiley face and if you're able to download that or whatever emoji feels right to you. Totally works. Sunglass emoji 'cause I'm
feeling cool now that I did that. And then wanna just open that up in our folder or in
our code editor rather. So I'll go to GraphQL SDL first. Nice. All smiles. Good stuff. So once we have this downloaded,
what we can do is again, navigate to the correct folder and then we can install some dependencies and we'll walk through what
is part of this project. Essentially what we're doing
here is we're adding one level of functionality to our schema definition language first approach. And this is going to use a
couple of different tools. So we'll walk through
what all of those are in just a second. While this is we can open
it up in our code editor. For real this time we can. So what do we have inside of this folder? Well, we have a couple
of different things. We have a package JSON file
that is using Prisma client. It's using Apollo Server. It's using GraphQL. It's using a package
called GraphQL scalars. So these are for creating
custom scalar types without having to do much work. We also have the dev
dependencies, so types. We have Node, we have Prisma,
we have TypeScript node and we have everything
we need to kind of set up a full-stack project or a
SDL project with TypeScript. So that's that. We also have a Prisma folder. Within the Prisma folder
we have a Prisma schema. Previously we created a schema using the GraphQL schema language, but this is a schema that uses
the Prisma schema language, the PSL, the pumpkin spice
latte, something like that. And all of these models are defining what are the possible types
that are part of our API. So you're seeing right
now how kind of useful the whole stack of Prisma
and Apollo Server is because not only do we
have a Prisma schema, but we also have a schema over here that's defined with TypeScripts. If you wanted to use just plain
JavaScript, that's fine too. But this is defining in our
type definitions like before all of the queries, all of the types and everything else we
need to make this work. Similarly, if we scroll down a little bit, I wanna scroll down to our context. So here we're creating a
schema with our resolvers and our type definitions. And then we also have this
awesome list of resolvers. And resolvers remember are these functions that are gonna be called
to return some data. So in the case of our queries,
we have an all users query. And this is going to return
the context of our Prisma user. Now over here in our context file, this is what's creating
that client relationship. It's creating that
connection to our database. So finally we wanna look at our server. This is just the server
constructor that we saw before we created a new Apollo Server. We listen on port 4,000
and then we run the thing. And now what we wanna do next
is we actually want to create a SQLite database file using this model. So the way that we'll handle that is we're gonna run a command and I'll paste that command
in your chat in a second. Actually I wanna use it over here so we can read it a little better. We're gonna run NPX, which
is the node package runner. So we'll run NPX Prisma, migrate dev, and then we'll send it a flag of init. So we'll send the name
flag plus init there. And let me share that here. We'll say NPX, Prisma migrate dev--name init. So this is gonna create our SQL file. Check it out. It's here inside of
this migration's folder. And basically any time we
want to create a new database we can do so. This'll just be based on whatever
is in your Prisma schema. So if I have a model for a user,
then this should correspond to a user that is a SQL table. Writing this stuff by hand is not that fun auto generating it is way more fun. So that should generate that for you. Again, the migrations folder
will contain any instances of new migrations that you add as you adjust your Prisma schema, it will auto generate
all this stuff for you. And the database is just
over here in this DB file. But of course, if you wanted to set it up where you're connected to some
sort of external database, you can always add an
environment variable file. And then what you would do
is you would just change in your Prisma schema. Instead of using this URL, you would have some long online URL or local hosts, whatever. The data source DB is really important because you define what type is it. Is it SQLitet? Is it post grass? Is it SQL server, et cetera. And then where that location is. The next thing that we're
gonna do is we're going to add some sample data to this database. So the sample data that it's provided here are these awesome Prisma
records for posts and for users. So the way that we'll see
the database or add items, add records to the database is we'll say NPX Prisma DB seed preview feature. And I also want to share that
in the chat with everybody. There we go. So this will either be a TypeScript file or a JavaScript file depending, but this is just generating
kind of some dummy data for us. I wanna also delete that
empty environment file. Not the server file, no. If I delete the server
file, I'm in trouble Environment file, not so much. Okay, cool. So at this point what we can
do, is we can run NPM run dev. This is going to start Apollo Server. It's going to start our
API on localhost:4,000. So this is already in use. Let's go ahead and kill
that other process. This will be easy to do
by killing it over here and running that again. Nice. So now what we can do, we'll find this running
on localhost:4,000, we'll see the GraphQL
playground that we saw before that nice little interface
for sending these queries. This time we're dealing with users and some posts for some mutations. So what I can do is I
can say query all users, grab their ID, their name. When I send this, we're gonna
see all of that data returned. Pretty cool. So all of the operations
that are available of course you can find in
the documentation panel, you can also take a look at the schema, but hopefully that works okay for you. All right. So the next thing I wanna
do here is let's see, we're going to take a
look at how to migrate. We're going to take a look
at how to add a little bit of extra code to first our Prisma schema, and then we'll show how
to auto generate some code based on that. So here's what I wanna do. In our schema.prisma file, we're going to add another field here. So to the user, we'll add a profile field and this should return the profile type. We don't currently have a profile type so we wanna add this model. Think of the model as
being like the Prisma type. In the schema definition
language we have a type, in the Prisma schema language
we have a profile model. So for the profile, we wanna have an ID which will be an Int. And this will be, we'll say
defaults, auto, increment. So every time we create a new one, we'll create a new incremented ID. We wanna have a biofield,
which will be a string. A user field, which will return a user. And the way that we're gonna
relate the user to the profile is we'll use the @ relation directive and the fields that we wanna
look up by our author ID. And we'll use the reference of ID. User ID is what it actually is. There we go. And then finally we'll say
user ID should be an Int and we'll say @unique. Now if you haven't
downloaded this already, I would highly recommend it. If you're using VS Code,
you can go to the extensions and find Prisma. Prisma will... And it's a very popular
and highly rated extension for VS Code. This'll allow you to add
some syntax highlighting an auto-completion for your schema. So I highly recommend that
if you wanna add that. And if anybody has any other
cool Prisma developer tools let me know and we can share
those out with everybody. So once we have added this, we've added the relationship
between the user profile and the profile model. The process that you'll
go through with this is then you will auto
generate these changes. So I'm gonna stop our server real quick. I'm gonna run NPX Prisma, migrate dev. We'll send a flag of name
and we'll say profile. So now check this out. First of all, let's... Here we go. The next thing I wanna do is check out. So this is our most recent
one that we added, right? So this is adding the profile. It's creating that
foreign key relationship. And we are gonna have
these little timestamps of all of these moments where
we're creating new changes to our schema. So it adds another
migration and it creates the new profile table in the database. So that profile table
is then added to our DB which we can't see, but it's there. So the next step is that
we need to update our code for our schema. So over here in the
schema TypeScript file, we need to create a new
GraphQL type for the profile. So all of this is gonna be added to our existing type definitions. So here we'll use the a
schema definition language to make this work, we'll say type profile. It should have an ID, a
bio, which is a string and a user, which is should return a user. Let me actually move
this up because really what we should be doing
is associating this with our user type. So if the profile, if we
query this user fields, it should return the user object, but we wanna make that a
two-way data relationship attaching the profile to the profile. So a one-to-one relationship
with our profile and our user. So once you've done that,
and this is sort of typical of a schema first approach, we're gonna create the
change to our schema, but we'll also create a
change in our resolvers. So let me share this with everybody. I know that that's long, but that's the change that
we made to the schema. Now, if you haven't worked too
much with resolver functions, just understand that the
resolvers have a very tightly coupled relationship with the schema. So the schema has an all users
drafts by user or whatever. And then all of these
are going to be related to that example. What we need to do here is
because we're adding a field for profile, we need to add the profile as a trivial resolver. Think of a trivial resolver
as being accustomed function that's going to be executed
whenever we ask for the field. Well, whenever we query the
user field on a profile, we wanna be able to find the right user. So we'll say parent, args, contexts. And the context is
whatever that context is. We wanna return the context Prisma user, or sorry, Prisma profile that find unique. And we're finding the
value where the ID matches the parent ID. And then we'll call the
user function on that. So find this and then
return the user details. So that's one of the resolvers
that we need to write. We also need to write one for the profile. So here we'll say whenever we
query the user profile field, we wanna call this function. So this is a function. I don't know why I'm
writing it as an object. So that'll look similar
parent, args, contexts. Cool. So again, these are just
functions that are gonna fire for whenever I'm asking for this field. At this point, I should be able to... Oops, don't wanna run that command again. I wanna run NPM run dev. This should run the server on 4,000. And now in the documentation we should see a couple new things here. So in the user you should
see the profile field ID, bio, user. So we should be able to add it. This returns an object can
grab the bio and the ID, and that should return that value. Let me just check this. Oops, there we go. Cool. So if you look at the data at this point, it should be no for the user, or sorry, the profile information because we haven't connected that, but we could create new
profiles using a mutation. But at this point we just wanna be able to see the profile information here. If it returns, no, that's okay. We expect that. So a couple of things going on here, we're adding in some relationships between our data sources and our types. The layer that we're adding
here is that our models are going to define all of the fields that are available for our
profile, our posts, our user, it will create a connection
with our database, and it may feel like the extra
step of the Apollo Server in here might be a little much, but here's where things
can get kind of cool. Let's say you have a database that is serving up most of your data but you also have a rest API that's serving up some data as well. You can use these resolver
functions flexibly to request some data from those sources. So let me show you an example of that. We pull that up in another window. Give me one second and I'll
share the link with you in just a second. Okay, cool. So now this is an example
of one of these servers where maybe I don't have
time to port this data over, or maybe I don't want to port
this data over to a database instead I wanna use a rest API. So you'll notice here
that we're incorporating some data from... And I see you have your hand raised there feel free to drop your
question in the chat or in the Q & A panel,
and I'll get to that. So here's an example that uses Strava. So we have this simple Strava sample. Strava is a rest API that
gives you information about your activities. So things like your hikes or
your runs or your ski days, things like this. And what we've done is
we've modeled this data using GraphQL. The first step is we have a type, my video just froze there so
I wanted to freeze myself. And if anybody can't
hear me just let me know if we're good we can do a thumbs up. We're all good in the chat. Okay, great. Thank you. Sorry. You never know with Zoom so I have to ask. All right, thank you for that. So anyway, we're modeling our
activity type with Strava. Then what we do is we add
a custom query to this using my activities in the query type. And then here's the magic part. We're using a resolver
function to fetch some data from the Strava API. The Strava API is a rest API. We send a fetch request. We specify some headers
where we pass a token to authenticate ourselves. And then we convert those responses to JSON and return the results. Now what's really cool
about this is that we could, let's say we were trying
to incorporate this into our own API with a Prisma. We could just fetch some
data externally there and use this GraphQL server
as a orchestration layer around our different data types. So that's just something to keep in mind that there is flexibility there. You can wrap a single database, you can wrap multiple databases or you can fetch from
rest API APIs altogether. So pretty cool stuff. Very cool stuff. So does anybody need me to
scroll up and down anywhere? Let me know, I'm happy to. All right. So why don't we add a
mutation to this briefly. The first place that we'll
add it is to our schema, and then we're gonna add it
to our resolver functions, and then this will help
us to kind of connect these different types here. So let's take a look at it. We're going to first in our mutation, we're gonna add a mutation
for add profile for user. This should take in a bio,
which will be a string and user unique input, which is the type user Unique input. And what this should return is a profile. Now, the next thing we wanna
do is use the create function. That's part of Prisma to make this work. So we've added this to
our type definitions. There we go. And now what we wanna
do is in our mutation, we'll scroll to the bottom of
this mutation context here, and we'll say add profile for user, we'll bypass the parent, and we'll take in some
archives from our user. So we'll say UserUniqueInput. And this is of type UserUniqueInput. And then our bio is a string. Outside of that curly race we
wanna use context and context. So that's kind of long I
will share that with you after we've moved through this. No worries. So the next thing we
wanna do is add a return. We'll say we'll return the
context, Prisma profile.create. I'm actually gonna move
this to the top because it's hard to read. So we're inside of this mutation context. Awesome. Thank you, thank you for being here. If you do have to leave, I totally get it. We'll wrap up here in about
10 minutes, 15 minutes or so. I'll try not to punch my microphone again. That's the last time I'll do that. Cool. So the next thing we wanna
do is we're going to create an inside of this create function. We're going to pass in the data. The bio will come from our arguments. So whatever the bio is,
we'll go here, args bio. And then the user, we'll
use this connect key to pass the ID and the email. So args.userUniqueInput?.id, email argsuserUniqueInput.email. We also need to add,
well, let's just do that. Nice. That looks a lot better. Let me give it a try and if something's wrong,
we'll troubleshoot it. But I just wanna make sure that
we're able to add a profile. We're able to see this mutation. I'm gonna put this back in one second. I know I'm taking it off the screen and that's super annoying,
but I promise to put it back. Let's go ahead and send the
mutation for adding the profile. Add profile for user. It'll take in a bio, we'll
just say cool person. That's my new bio for everything. And it would be sort of true. userUniqueInput. And then what do I need here? I need an email. And one of the emails
we need to check out. So in our seated database,
we can use this one, Alice@prisma. And our ID, I don't know what it is. So let's find it. ID one, that'll do it. Let's go back. And then we wanna return
the ID and the bio. Let's see, what is our air here? So it's saying we only
need one argument there. There we go. Nice. So that should work. We need one or the other. I spun out of control on looking for an ID and I didn't even need it. So here's our mutation. I'm gonna drop that in the chat. Boom. And then over here, I
will leave up our current server and schema, and I'm happy to scroll
elsewhere if you need me to. So that is there should
be able to close that and then we're able to connect
these two different types. So I think when we're
talking about Prisma, when we're talking about adding
this to our GraphQL stack, we're talking about
allowing for type safety, full stack type safety. We are creating this
nice data relationship between our database and our GraphQL API. So it allows us to take what
we like about the database, but also use what we like about GraphQL. We're able to make available
this great playground for everybody to access
the data that they need. And we also saw how we can
incorporate data from rest APIs and use this as sort of a
orchestration layer as well. So we are reaching the end
of our time together today. What I want to leave you
with are a couple of things. So the first thing I wanna leave you with is this mutation. I wanna remind you that
I will post everything that we've worked on
inside of that repository. So let's take one more
look at that real quick. So if you go to
eveporcellographqlwithprisma, this will be updated shortly to contain absolutely everything that we've used. There's also these slides. So let me open that up real quick and I'm gonna skip to the end. Cool. So couple things before we wrap up today, if there's ever anything I can help with as you continue your journey with GraphQL, don't hesitate to get in touch. My email is eve@moonhighway.com. So you can feel free to share
that or use that at any time. Also, our website has a bunch of articles about GraphQL thing. So if you wanna take a
look at that, you can or find me online @eveporcello. I would highly encourage you to check out Prisma Day Tomorrow. Prisma Day isn't just this
workshop day, but it's also, we have a ton of different... I say we like I have done
something cool to make it happen. I've done nothing, but the team at Prisma has put
together an amazing program for you with all sorts of great
talks on everything Prisma, everything Nexus and so on and so forth. So I would highly recommend
checking that out. I'm gonna be there for sure. So join me for that. Also keep an eye on the
Prisma documentation. So they do an excellent job of kind of keeping these up to date with reference guides
and things like that. And if there's anything
that you're ever missing, it's probably here. All right. So I appreciate each and
every one of you so much for being here today. I hope that this has
been useful in getting kind of ramped up on
some of these concepts, but I know that's just
the tip of the iceberg. There's so much cool stuff
we can do with Prisma and with GraphQL. And I hope you have a lot of
fun building these things. Stay in touch if there's ever
anything I can help with, but thank you all so
much and I'll hang out as long as you'd like
to answer any questions, or point you in the right direction, but looking forward to
seeing you at a future event. Thanks so much for being here today. (bright upbeat music)