Building GraphQL APIs with Prisma - Eve Porcello | Prisma Day 2021

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
(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)
Info
Channel: Prisma
Views: 1,443
Rating: 4.9166665 out of 5
Keywords: prisma day, prisma day 2021, graphql, eve porcello
Id: U8TKbNwgcSQ
Channel Id: undefined
Length: 91min 41sec (5501 seconds)
Published: Wed Jul 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.