Let's Learn Prisma!
If you need a database for your app, Prisma promises to make it easy. Nikolas Burk will teach us how!
Links & Resources
Full Transcript
Click to toggle the visibility of the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
Jason: Hello, everybody. And welcome -- oh, my god. I didn't unmute us. Hold on! Hello, everybody. Welcome to another episode of Learn with Jason. Today on the show we have Nikolas Burk. Thank you so much for joining us today. How are you doing?
Nikolas: Jason, I'm doing really well and excited to join you on the screen. identify watched a don of episodes and switching sides.
Jason: We will talk about tech. Before we do that, I would love anyone not familiar with your work, give us a little bit of a background?
Nikolas: Yes, of course. My name is Nikolas Burk. I actually used to be a mobile developer before I started dipping my toes into the web ecosystem and working with JavaScript and TypeScript. For the past four and a half years, I have been working with a company called Prisma that we will cover today as well. Initially, though, as I joined the company in 2017, I believe, the company was still called Graph Cool and building a backend as a service. And now we have ripped off the backend as a service and left with just a database layer, basically. And, yeah. In general, my role at Prisma is anywhere between developer success, developer relations, just in general being in touch with the community and helping developers be successful with the tools that we are building. And I really enjoy this because it's just -- it makes basically learning and teaching. Which is something that I've always enjoyed doing. So, just the perfect job for me, basically.
Jason: Absolutely. Yeah. I -- it's -- I mean, you and I have always had pretty parallel career paths, I think. Your role at Prisma sounds very similar to my role at a few of the companies that I've joined. I've joked that role is human duct tape. The company is changing and you have new needs. You just do the thing that needs to be done to move things forward. That's actually one of my favorite places to be. I love this idea of being able to kind of fill needs and make sure that everybody else is able to move forward. So, okay. So, you have been doing this for the last four and a half years at Prisma. And you mentioned this started out as graphcool. I remember those days because at the time you were doing that, I was at IBM. And the way that I actually got introduced to you and your product was at the GraphQL Summit where I was introducing a different GraphQL thing that we open sourced at IBM and nobody used. Which was not really related to this at all. It was closer to like Apollo Federation.
Nikolas: It wasn't the schema stitching days, right?
Jason: It was in the schema stitching days, right. And Graphcool was an early way for someone to quickly say I want a GraphQL API and you could click a few buttons and graphcool could do that. Thank you for the sub, Peruvifanidol. And a lot of people were using that, and instead there was going to be this company called Prisma. And Prisma at first was kind of like the GraphQL layer. Well, maybe it's not the GraphQL layer. Maybe it's something else. Maybe it's a data layer. And then it's like, no, it's something different than that. But it's definitely not an ORM. And then over time, it became, well, this really is an ORM. Just what could we do if an ORM was imagined differently, right?
Nikolas: That's amazing.
Jason: That's where it landed today, right?
Nikolas: You just summarized all the internal discussions that we've had at the company over the course of four years in a minute, basically. So, that's exactly -- exactly the kind of thinking that we had internally and the kind of discussions that we had around this topic as well. And I think what it comes down to is flexibility for developers. And we found that with these layers that we put on top of the database, initially with graphcool to initiate a quick GraphQL API. Including business logic and authentication and more integrations.
Jason: Right.
Nikolas: Developers were not flexible enough to account for all of their use cases with that system. It was typically nice to get something going quickly.
Jason: Yeah.
Nikolas: And that was the most common user feedback that we got at that time was, oh, I loved graphcool, it helped me prototype my app. So, thanks. Now I'm going to build this GraphQL API myself as I'm building a real app. So, that was kind of the feedback that we got initially. And that's why we kind of decided to leave that space of the backend as a service and develop down another layer.
Jason: Sure.
Nikolas: And that's when we came up with the idea of Prisma in the first place. Which the very first version of Prisma was, again, a GraphQL layer for your database. But it wasn't intended to be used by frontend developers. That was very counterintuitive for everybody who has used GraphQL. GraphQL is the technology for frontend developers. And as soon as a frontend developer sees a GraphQL play ground, they know this is for them.
Jason: Right.
Nikolas: That was not the case with Prisma 1. With Prisma 1, this API that was generated in GraphQL was why intended to serve the actual GraphQL API layer and make it easier to implement the operations and reinvolve the permutations that were coming on that API lier more easily.
Jason: Yeah.
Nikolas: After we did that, we recognized that the actual problem that we were solving for developers there was not necessarily the fast way to build a GraphQL API. But that we liberated them from all of the things that they had to worry about before with their database. And that's really when the actual kind of vision of Prisma was born because that's when we realized, okay. The value that we provide with Prisma is on the database layer and making it easy for developers to work with databases no matter what they want to build on top. Be it a REST API, a GraphQL API, they can choose whatever tools they want, what stack they want. We want to help them --
Jason: Interesting.
Nikolas: Work more easily with databases. That's the main point of Prisma today. Making it easy for application developers to work with a database.
Jason: Cool. All right. That makes sense. I'm with it. And so, when we talk about this, you know, you made a call earlier that like Prisma 1 was not really for frontend developers. So, with Prisma 2, is the intention to kind of bridge that gap again and make this a frontend developer tool? Or are we looking at a backend tool that would be provided to frontend developers?
Nikolas: So, what we were looking at is an operational -- an ORM. It's used on the backend. When they need to implement a REST API or a GraphQL API and that makes it easier for them to talk to a database. That's the kind of category that we're in. But because Prisma is so easy to work with and really abstracts away from the actual database, we often say that Prisma empowers frontend developers to build their own backends. Because from what I've seen when I talk to frontend developers, a lot of them actually know how to implement a REST API route. Or they know how to implement resolvers for a GraphQL server. But what's always the difficult part for them is working with the database. How you run migrations? How do you take care of like performant database queries? How do you model your data in the first place? Like, these are questions that are very difficult for frontend developers to answer because the database is so far away from what they're used to. It's also because relational databases that are the standard today, they have a different data model than the JavaScript and TypeScript programming languages which are object-oriented. We deal with nested objects as JavaScript and TypeScript developers and we're all familiar with that. When we are working with a relational database, we are working with a normalized -- with a flat data structure, tables, that link to each other via foreign keys. So, we don't have these nested structures. And performing the mapping from the tables, from the flat normalized structure to the object-oriented structure is something that has traditionally been done by object-relational mappers and Prisma is a next generation object-relational mapper because we don't follow the SQLized or type ORM, tools you might have heard of. They take a very different approach and we kind of develop a fundamentally new approach to the same problem. And that's also why in the beginning we somewhat refrain from calling ourselves an ORM. But by now I think we've all accepted that this is the category. Although it just throws a couple of people off that just in general don't like to use an ORM. But it helps people understand better what Prisma is.
Jason: Right.
Nikolas: And then we dive into the details to explain how it's different from traditional ones.
Jason: I also -- props to you for keeping it together while the chat was steadily strategizing on where to put the submarine on your head.
Nikolas: Yeah, I just noted that I have something on my head here.
Jason: So, maybe one thing that would be worth doing is I think a decent number of people in this chat, myself could included have a shaky understanding of what an ORM is in general. And so, when I think of an ORM, what I'm imagining is that the way that when I use something like Firebase, I don't write a query. Right? I get a piece of software. And then that API I say, like, give me a new instance of Firebase and then I can create things or update things or change relationships. And I do all that through API calls. So, as a frontend developer, is that what an ORM -- is that the gap that it fills? It's giving me an API instead of saying, like, here. Go play with data.
Nikolas: Yes, exactly. Because typically what you would have to do as a backend developer if you wanted to talk to a database. That's what you did 20 years ago, you would write plain SQL queries and return data from the database. But working in JavaScript or TypeScript with SQL is very, very cumbersome. SQL is for strings. You don't have a great developer experience, you can have typos, don't get syntax completing. Plus there's the gap between the mental model between relational data and object data. If you're writing plain SQL queries in the code, you get the data back in the normalized way from the tables and then you have to manually put it into a format that you can actually use inside of your code.
Jason: Gotcha.
Nikolas: And people tend to write their own object relational mapping layers if they're not using one specifically. But we basically took the approach of building a new one that just solves these problems for everybody, basically.
Jason: Yeah, okay. Yeah. So, we have a question in the chat from Ivor. He says, having used both Prisma and Hasura, like Prisma and Hasura are os sensibly in the same ballpark. Hasura is a way to set up a database and you get different ways to access that data. Prisma is also about databases. But they're not the same. So, what -- how do you differentiate? In your mind, what are the use cases of like when you would go for one over the other?
Nikolas: Right. So, this question was a lot more appropriate in the Prisma 1 days. Because during these days, Hasura and Prisma 1 actually were very similar. Because both were this GraphQL layer on top of a database. That was really the value proposition of both of them. With Prisma 2, this question is a little bit comparing apples and oranges now. Because it's not quite accurate anymore. Because Prisma just solves a different problem now. Prisma is now a tool that doesn't generate a GraphQL API. But it generates a database client that you can use in your programming language. So, Prisma you can use to build any kind of application. Be it a REST API, be it a GraphQL API. You'll have to do more work yourself on the API layer as you -- like always have to do when you're building an API from scratch, basically. But all of the problems that you had before with the database, that's what Prisma solves. So, like very quickly, I just think that Prisma probably covers a broader spectrum of use cases. Just because it gives you a way to talk to a database in code and not in GraphQL. And we are also not trying to tell you what kind of API you should be -- what kind of API you should be using, how that should be structured. This is all up to you as the application developer, as the API developer, to actually implement all of that.
Jason: Gotcha, gotcha, gotcha.
Nikolas: I hope that makes sense.
Jason: Yeah. It's sort of the ideas of batteries -- batteries included versus having control. And I think that ultimately mast always a matter of taste. What are your requirements? What are you trying to build? What do you want to be able to control? What do you need to do with it later? These are the tradeoffs that you have to consider with any tool. Okay. I'm really excited about this. I think we have done some really good overview of what Prisma is. I think, though, it is going to be much easier to understand by looking at it.
Nikolas: Yes.
Jason: So, maybe what we should do here is we should flip over. Let's do that. And let's do some pair programming here. Sorry, chat, I just reset all of your submarine work. You're welcome. So, first and foremost, let's do a huge shoutout to Amanda from White Coat Captioning who is with us today doing all of the live captioning. Thank you so much, Amanda, for doing that. It's -- it's great to have you here. And then we -- we're able to do that because of the support of our sponsors. We've got Netlify, Fauna, Auth0, and Hasura all kicking in to make this show more accessible to more people. That means a lot to me. I hope it means a lot to you. And remember, if you go to the home page, you can check out those captions right now. So, yeah. Definitely get over there. Remember, these are linkable. You can go click those. And you can watch this right here. Look at that. It's great. The things I say. I say something silly, Amanda has to write it down and I'm very sorry about that. [it's cool]
Nikolas: Thank you, Amanda. [ Laughter ]
Jason: Oh, my god, I love it. That makes me so happy. While you're looking at things on the Internet, make sure and give Nikolas a follow on Twitter for all things, what? So, I assume Prisma. What else is happening on your Twitter feed?
Nikolas: I am using Prisma almost at Twitter almost exclusively in a professional way. So, a lot of the stuff that you'll read there is about Prisma, about databases, about GraphQL, about software development in general. So, that's what folks can expect when they follow me here.
Jason: All right. So, you can follow me for nonsense, follow Niko for work. And today we're going to be working on Prisma. So, there's a link to go check out Prisma. And if I want to get started, it looks like there's -- there's a big button here to get started in 5 minutes. Is that where you should go?
Nikolas: That's the main quick start. Exactly.
Jason: Okay. So, let's do that.
Nikolas: But actually, I -- yeah, actually it's -- it might be a little bit faster to start with the starter project that we have there.
Jason: Okay.
Nikolas: That's perfectly fine. I have big plans for us today, Jason.
Jason: Oh, good.
Nikolas: First we are going to set up a relational database. So keep it simple for this one, we will just use SQLlite so you don't have to set up a postgres or MySQL server. We just have everything on the file system.
Jason: Okay.
Nikolas: And then just start exploring Prisma a little bit. Sending a few queries to the database from a simple script, basically. And then I want to build a REST API, implement a couple of routes with express. And if we have time, then I also want to implement a GraphQL API. So, we'll just wipe out everything that we wrote for express and do the same with GraphQL to give people a sense of how quickly they can start and build their own back ends when they're using Prisma.
Jason: Oh, dang. All right. So, if I want to start, is Prisma going to create the folder for more? Or should I create a folder to build the project in?
Nikolas: You can just go back to the quick start and get the first curl command that's going to create a starter project from GitHub.
Jason: Does it put it into a new project?
Nikolas: It has a folder.
Jason: Oops.
Nikolas: It depends if you want to have a new folder to keep the file system tidy. It will create a new folder on your file system as well.
Jason: Do that. Create a new folder. Where the hell am I? What am I doing here? This is not what I wanted to do at all. Okay. Let's move out to my actual GitHub repo for Learn with Jason and run that command one more time. And move that starter into let's learn Prisma, because that's going to be the name of this repo. Okay. So, we're in here. And does this have a Git? No. So, I'm going to Git init in here. I have a project.
Nikolas: Yes.
Jason: And it opened in the wrong window. Let's open this one up and let's take a look inside. So, I have Prisma client.
Nikolas: Yes.
Jason: We have to use node greater than 10 which I believe we are using Node 14.
Nikolas: Perfect.
Jason: Prisma, TypeScript and TS Node are the Dev dependencies. So, this is pretty lightweight here.
Nikolas: Yes, exactly.
Jason: I have a TypeScript file to get Prisma client. And then an empty kind of do whatever you want here.
Nikolas: Exactly.
Jason: Okay.
Nikolas: And that's an async function so that we can write our database queries without worrying about it.
Jason: Okay.
Nikolas: Let's start looking at the schema.prisma file.
Jason: Okay.
Nikolas: That's where all your Prisma projects start. And for the beginning, I think you can delete the post model right there. And we'll add it back later again. But --
Jason: Do I also want user?
Nikolas: You can keep a user for now.
Jason: Okay.
Nikolas: You can keep the user and now just delete that relation there as well. All right.
Jason: Okay. So --
Nikolas: What is this thing we're looking at?
Jason: Yeah, at first glance, this looks similar, but not the same as GraphQL schema definitions.
Nikolas: Very nice. Yeah, exactly. And that's, I think, also due to our history as a company that the modeling language that we use today for Prisma has been heavily inspired by GraphQL. And everybody who has written GraphQL SDL in the past will have a breeze picking up the Prisma modeling language. And another interesting thing about this is that a lot of people that are looking at Prisma, they initially say, oh, but I don't want to learn this extra query language. Like this extra modeling language. Other ORMs like TypeORM or SQLize, they use TypeScript classes for the models. Why do I have to learn this new thing? And then once they start using Prisma and get the experience of modeling data with Prisma also using the VSCode extension, they quickly turn around and it's like, they become our biggest advocates because they have now actually experienced it themselves. So, I regularly talk to people that bring exactly that argument and I tell them, try it out and see how it feels for you. And then oftentimes they come back and say, hey, you were right. And it feels pretty good to do it that way.
Jason: And you're sure that's not Stockholm syndrome?
Nikolas: At least I would hope so. At least I would hope so. And I'm not sure who would be the person --
Jason: Okay.
Nikolas: Yeah.
Jason: At a glance, this makes sense. This is human-readable. I do like that.
Nikolas: Yes.
Jason: The database, the database provider, SQLlite. And I see where it comes from.
Nikolas: Right there.
Jason: This is our database, SQLlite. Once we build this, I can put this up on GitHub and someone can download it and have the data. If they make changes, it will break. That's fine. This is exciting. I understand this. Then we have a generator for the client. We're going to use Prisma-client-js. That makes sense, I understand that. And then we have a model of a user and this is my data model. And I can infer that these are field names, these are field types. My assumption is that this makes it optional.
Nikolas: Correct.
Jason: Unique is pretty clear. ID. Is that like primary key?
Nikolas: Yes.
Jason: Okay. So, this is like -- this has to be unique and this is what's used to index the -- the file. Or the model.
Nikolas: Exactly. Yeah.
Jason: And then default is a default value?
Nikolas: Yes, exactly.
Jason: Okay.
Nikolas: When you create new users in the database, you don't have to provide an ID. But in this case, it's going to be an auto-incrementing integer that's going to be assigned to each new database record.
Jason: Okay. This is great. I've never used this format before. But I was able to kind of looking at it, I can understand -- like, I don't know that I could write this myself. But I can at least read another -- I can read this schema and I can say, okay. I know what's going on. We have got a database and it has users in it.
Nikolas: And you will get to writing it soon enough in the stream.
Jason: I'm ready.
Nikolas: Perfect.
Jason: Now that I've got this, what's my next step?
Nikolas: So, in the quick start, you already downloaded a SQLlite database file. I would say delete that because I want to start from scratch basically.
Jason: Gone.
Nikolas: We don't have a database yet.
Jason: Get rid of it.
Nikolas: Okay. At this point we really have nothing with respect to our database except for this Prisma schema.
Jason: I'm going to run an npm install. I realized we haven't done that yet.
Nikolas: Perfect. Now the first step, now that we deleted the database is to create the database.
Jason: Okay.
Nikolas: And along with the database, we want to have the tables defined by our model. In this case, one model mapped to one table that's also called user and have columns that we define as fields.
Jason: Okay.
Nikolas: And the way we do that is by using Prisma Migrate. That's a tool that takes care of migrating your database schema. It will create it for you.
Jason: I'm assuming it comes in here?
Nikolas: Exactly. We're using the CLI for that. That's part of the dependencies. You can type into the terminal npx Prisma migrate Dev. And enter.
Jason: Okay.
Nikolas: That's going to read the Prisma schema file and ask for the name of the file, call init. It is the first one, initializing with the single table. And we have the database.
Jason: Okay.
Nikolas: Before we do anything else, let's quickly take a look at the database in a more visual manner by exploring it in Prisma Studio. So, with every Prisma project, you get Prisma Studio which is sort of like a PHP my admin, but built for 2021.
Jason: Okay.
Nikolas: You can start it by running npx Prisma studio right here as well and then it will open up in the browser and we have this as a standalone Mac app that you can download. There you can now click on your model and start getting records.
Jason: ID, name. Oh! I can add. Okay. All right. So, I can be in here.
Nikolas: Yes.
Jason: And do one of those. I'm going to save that change.
Nikolas: Perfect.
Jason: I did it wrong.
Nikolas: You have to re-type the name. Before you click save, you have to like hit enter once when you create a new record. But --
Jason: Gotcha, gotcha. So, I don't have the field selected when I hit save.
Nikolas: Yes, yes.
Jason: All right. Let's add one more.
Nikolas: It's Bur k@prisma io. You can add me.
Jason: Niko or Nikolas?
Nikolas: Niko, Nik or Nikolas are all fine.
Jason: All right. Clicked out. Hit save. There we go. Now we have two users in our user database. And I'm not gonna lie, this is really cool. Like, I -- I did not know that this was -- that this was a feature. And this is a really, really handy feature that this is, you know, a thing that we can just very quickly stand up. I like that a lot.
Nikolas: Yeah. Cool. Yeah. So, now let's explore what we can do with Prisma in code. And for that, you can go back to our VSCode project.
Jason: Okay.
Nikolas: And open up script.ts file.
Jason: Okay.
Nikolas: It's basically empty. It just called this async main function where we can start writing database queries. We can query all users. You can write const users = await. And then Prisma dot. And here is the autocompletion that's kicking in.
Jason: Oh, boy. Look at it. So, I have user.
Nikolas: One like really funny side note about this, actually. So, just I think yesterday or the day before, like Ryan Florence, he built a -- a demo app with Remix, like his web framework and he used Prisma. And the first time he was writing a Prisma query as he was like streaming live on YouTube, he also just discovered this autocompletion. And he was like, wait. Where -- like, how do they know where the models come from? Where do the type definitions live and all that? And it was just hilarious to actually see him discover this feature. And the -- the autocompletion that Prisma provides actually I think is one of the biggest benefits that it has in general. Because it basically lets developers just explore the API at their fingertips without needing to look up documentation. So, the type safety that we provide with all Prisma client queries not only covers kind of the actual like safety aspect of it, but also --
Jason: Right.
Nikolas: Just the productivity with autocompletion.
Jason: And this is -- when you start talking about why you would use a tool like Prisma, this is it. The fact that as a -- like, as a developer, if I come in and I set up my Prisma client and I do Prisma.user and then I check. And I can see, oh, here are all the things I can do.
Nikolas: Yes.
Jason: I can find many.
Nikolas: exactly.
Jason: Let's see if I can get all of my -- okay. Here are my args. And I bet -- this is optional, I bet if I leave it empty, I bet I get all of any users. Let's see if I'm right.
Nikolas: How much are you willing to bet for that?
Jason: I'm medium confident here. I'm better than 50% confident. I think without reading the docs, I will log out a full list of my users. I should, if I guessed the API correctly, I should get a list of my users logged in the console when I run npm run Dev. Let's see what it looks like. Oops. Get back into the console for that. Look at that. Okay.
Nikolas: You have a great intuition.
Jason: This -- I don't, though. If I had to guess that, there's zero chance in hell I would have guessed find many. And there's also zero chance I would have guessed that I didn't have to pass in an argument if it didn't show me it was optional in the TypeScript autocompletion. That alone is worth the price of admission for something like this. This is the type of thing that makes these sorts of efforts to set up a database with an ORM, that's why. Is because now as a developer, if I walk into any project, I don't have to go read a database schema. I don't have to have a meeting with the backend team to get a diagram of how the data works. I can just import the Prisma client and start using autocomplete.
Nikolas: You hit the nail on the head there, yeah. In terms of onboarding new developers, it's also a whole new level. Nobody has to go and read API documentation. They just query the data. And that is something that GraphQL enabled on the frontend. And Prisma basically now enables this on the backend. So, I think that kind of comparison is also interesting. You think about, okay, like what does it actually achieve?
Jason: Yeah. I mean, this is -- it's really slick. Like, you can see kind of the -- how these dots start to connect. Because this -- you know, this being in the project first and foremost let's me know as a -- a developer, I can just kind of glance at it and say, okay. I've got users. And then I, in here, knowing that I can autocomplete, I'm able to get my list of users. And then if I want to find a user, I would bet that I can -- what's my shortcut here? I can do aware. Okay. Let's see if I can figure this out. So, I'm gonna do an autocomplete and I'm gonna do email. Let's see. I need to look at that again. Is that an object? Email is a string. So, I'm gonna do email and I'm gonna put my own email in there. And let's see if I get my email when I run this again.
Nikolas: Yeah, for what it's worth, I think you did not put in the like dot com into the actual record. So, if you remove the dot com from the string there.
Jason: Did I screw up my own email address?
Nikolas: But what you can also do, like as you mentioned it --
Jason: I did that part. I left a space in there.
Nikolas: All right.
Jason: Okay. So, if I can type, and I know with what my actual records are. But look. I have yet to look at any documentation. I just -- and I'm, like, sometimes on this show I'm pretending that I haven't used things before. I've literally never used Prisma 2. I'm actually Intuiting what this is because the API is autocompleting. And I think that's the strength of this.
Nikolas: Yeah, 100%. And to be fair, you ask whether the email thing takes an -- like an object or a string, you can actually also provide an object. So, if you want to do that real quick and see more filtering options. So, you can delete the string off your like email there.
Jason: Okay.
Nikolas: And again --
Jason: I'm being reminded -- I'm being reminded in the chat that I actually have used Prisma on the Redwood episode. Which goes to show how good my memory is. [ Laughter ] Oooo! Okay. So, contains. This is exciting. So, now we have like actual queries. So, if I contains like this...
Nikolas: Then it should still return.
Jason: Okay. And then let's -- let's change this. Run it again. Beauty. I mean, this is -- like this is wonderful. So, I can see now like if I was looking for like, I want to see who works at Prisma.
Nikolas: Yes.
Jason: I can do a query for anybody who works at Prisma and pull out those emails. So, like now I've got a quick lookup to see if we've got company emails. That's powerful stuff.
Nikolas: Yes. Cool. Glad you like it, Jason. All right. Okay. So, how about we move on and you get a taste of the -- the data modeling experience next.
Jason: Let's do it.
Nikolas: And adding a new model which also means adding a new table to the database. Let's go back to the Prisma schema and add the post model again that we previously deleted.
Jason: Okay.
Nikolas: I'll just try and let you type it for now. And just like tell you what fields we want to have.
Jason: Okay.
Nikolas: And one side note, by the way, you don't have to space this yourself. But when you format --
Jason: Oh...
Nikolas: The file, it will then automatically align all the fields and their types and the attributes.
Jason: Okay.
Nikolas: We'll add a title that's a required string.
Jason: Okay.
Nikolas: We'll add a content field that's an actual string.
Jason: Okay.
Nikolas: We'll add a published field, that's a Boolean. And we add a default attribute to it. That's false so that every post that's created will be false initially. Yes.
Jason: And I just put the value straight in. If this was a string, I would quote it or whatever.
Nikolas: Yes, 100%. And now we need a relation between post and user. So, one post can have an author. So, let's go ahead and write that author. Yeah, of type user. And on the user, you can already go ahead and write post. And there still will be an error. We'll talk about that in a second.
Jason: Okay.
Nikolas: If you now go down to the user, you can add field posts. And that's post. And with a square bracket after that.
Jason: And this is to imply -- this is multiple posts. This is one user.
Nikolas: Exactly. Exactly.
Jason: Save, auto-- beautiful. Oh! What did I just change? It autoformatted.
Nikolas: Yes. And like Prisma -- VSCode ex-presentation takes care of that work flow for you where you need to define a foreign key.
Jason: Oh!
Nikolas: Because the foreign key that you need in the underlying database still has to be represented in the schema. To make this flow a little bit more intuitive, we decided to on save insert the missing fields. If you can still rename the user ID to let's call it author ID to be consistent with the like field name of the -- yeah. And then the like second one below you have to rename to author ID as well.
Jason: Oh! Got it.
Nikolas: That's it. Perfect. we're set. You just created a new model. From that, we can generate a new migration, create a new table in the database.
Jason: Okay. So, NPX Prisma migrate Dev, right?
Nikolas: Exactly. You'll be prompted again for a name. You can say, add post.
Jason: Add posts. Database is in sync with the schema, okay. And then I do npx Prisma studio. Thank you for the subscription, Ben.
Nikolas: And now --
Jason: And now...
Nikolas: You can go ahead and click the plus on the top there and it should show you the second model on the post.
Jason: Okay. Now we're looking at our posts. I'm going to add a record. We know that's going to autoincrement and we'll say Prisma is neat! And then for the content... do a boop. Ooo... and then I just get to select one.
Nikolas: Yes.
Jason: I like it. Wait, did that work? Is it selected?
Nikolas: Yeah. And you have to like --
Jason: Oh, it sets the author ID over here. I got it. Okay. So, then I save. Okay. All right. So, does that mean that I can come back over here and I should automatically see the posts in the result that comes back? Or do --
Nikolas: That's a really good question.
Jason: Let's try it and find out.
Nikolas: Yeah, okay.
Jason: So, I expect -- here's what I expect. I'm using my -- actually, I don't know what I expect. You hackers, you dirty hackers. Okay. So, it didn't give us anything. Which leads me to believe that relationships require something extra. And that makes me think that maybe there's a field over here. So, let's try it. I'm gonna hit the dot. Not this one.
Nikolas: You are on the right track. So, like first to explain why the relation was not returned yet is because by default, all Prisma queries will just return the scalar fields of the models and not relations.
Jason: Okay.
Nikolas: If you want to load relations, you have to include them explicitly.
Jason: Okay.
Nikolas: That's exactly how you do it. Another object.
Jason: Oh, it's an object. Okay. Posts.
Nikolas: And you just have to set that to true. It's a Boolean.
Jason: Okay.
Nikolas: And now you can run it again. And since it's only me that's being returned --
Jason: Good.
Nikolas: You have the empty array. But if it's you, then you would get everything. Your new post.
Jason: There's my post. Okay, let me stringify this let's do it this way. And now we should be looking at -- look at that! Users. We get our array. Here's me. Here's my post. It's all in there. We have our author ID tied in. And we are beautiful. As far as, you know, if we talk about databases, let's see how much I remember from my days as a backend Dev. When you're talking about databases, one of the things that you want to do is you want to normalize your data. And that avoids with us from having like a post with this information stored in here. Because then if I ever update my author information, we would have to go edit every single post record in the database. So, instead we normalize by using an ID reference. That's the foreign key that you referenced before.
Nikolas: Yes.
Jason: I know that a post with author ID1 corresponds to user ID1. And if I update this, all the posts would get the updated user data.
Nikolas: Yes. That's exactly the idea.
Jason: Okay.
Nikolas: And the way how Prisma lets you work with relations is actually very nice. Because with all other kind of database tools, relations are still following that other model of like being normalized and flat and they're typically a difficult part to work with when you're working with databases. And with Prisma, this becomes really easy. You just use include to fetch relations from the database. We also have a fluent API. In fact, your intuition by adding a dot at the end of the like find many call was actually already in the right direction as well. The only problem there was that you can't use the dot notation, the fluent API, on a list of records. Because --
Jason: Okay.
Nikolas: Then you just like using it basically on an array. You have to use it on a single record. So, if you were to replace find many, for example, there with find first, which takes exactly the same argument. But just returns the first record. Now you can use dot notation. And just get the posts directly.
Jason: Oh, I get it. Okay.
Nikolas: And in this case, users now will actually be posts. So, now the user's variable that you define above is now of type post and not of type users. That's exactly it. Yeah.
Jason: So, I want to do a -- a quick -- quick shoutout to Alexis for showing me console right there. This is beautiful compared to my stringified dump up here. I've never used console.dir before. I'm going to use that forever and ever, amen. This is slick. Yeah, your camera is out of focus and the chat is unhappy about it.
Nikolas: Yeah, I'm trying to move around so that it's sharper again.
Jason: You've got to --
Nikolas: But it's not working.
Jason: Just thump on it a little bit.
Nikolas: Like this?
Jason: Is nope, nope.
Nikolas: Yeah, I'll just keep moving around as we talk. Maybe at some point it will work and get sharper. I'm sorry about that. Developing the mic, does that help? I don't know. I don't know. I'll just -- yeah, I'll keep moving around and at some point it will sharpen up, hopefully.
Jason: It's a trick. It's actually Niko --
Nikolas: There we go.
Jason: Hey! We got it!
Nikolas: Sharp again.
Jason: Now we've got the ability to find a user. We can get all the posts for that user. And inside of here, we've got all of our posts. What if I wanted to go deeper? I want to include user author. What happens now?
Nikolas: You can do that. But not on --
Jason: Nothing.
Nikolas: Okay. I didn't even know our API was automobile to do this.
Jason: We're learning together.
Nikolas: Yeah, nice. All right. [ Laughter ] That's very neat indeed. Like, I wasn't aware that you could -- or actually, yeah, maybe I just haven't used it that much. But nice. Yeah. Anyway. Okay. How about we try and create a new record before we start implementing some REST API routes?
Jason: Yeah, let's do it.
Nikolas: We can tell people how this is useful. Okay. How would you go about creating a new record, Jason?
Jason: Let's find out. So, let's -- I'm gonna go down here and I'm going to create a new record. So, we'll use Prisma.-- let's do post. Create. Okay. That makes sense. And it needs args, which are include data. And do I need any of the other ones? Select, include... no. Let's go data. And in my data, I'm going to need... a title. I'm going to need an author ID which will make this your post. I need content. And that will be --
Nikolas: Yeah, it's actually optional. You could also omit that.
Jason: Yeah, we could leave that out and then published an ID. ID we leave out. Published, we will let default to false. And so, I think -- I think that should work. What happens at the end?
Nikolas: It -- like it's a promise. So, you actually have to await it as well.
Jason: Okay. Okay. So, if I... let's console.dir our new post.
Nikolas: All right! And if you actually want to include the author of that inside of the create call on the same level as data, you can provide the include option here again and say like author true. And then it will also return the author data for that post that you just created.
Jason: Look at it go. Okay. So, again, pretty intuitive stuff. Like this makes sense, you know, I would probably end up in the docs to figure out a couple things. Like this is a thing that you just -- I think you just learn when you try to figure out that use case. But -- wow. You know? Like in terms of -- in terms of things that are gonna make my life easier, right? Like being able to more or less autocomplete through getting something included. And the door closed.
Nikolas: It's so powerful. It's incredible.
Jason: Really, really nice. Actually, here's a good question. What happens if I try to create a post for somebody who doesn't exist? What happens here? Let's just try. And let's see what our error messages look like. Failed on foreign key. Okay.
Nikolas: If you scroll further down, maybe it even tells you that you -- it's not a valid one. No. It doesn't seem so. But yeah. I mean, it's expected that like this fails. And to protect you from this issue, actually, there is another API that you can use to connect the author with a post. So, instead of directly setting the author ID there. Or if you want to first like print the error, you can do that as well.
Jason: If we run a catch on it, then we can --
Nikolas: Yeah.
Jason: We can just drop in something nicer.
Nikolas: It's to protect -- well, it's not really protecting you. But there is another way to connect your post that you're creating with an author. If you don't directly pass the author ID as three, but instead you just write author.
Jason: Oh, okay.
Nikolas: And you just write author and provide another object. In there, if you hit control space first, you can actually create a new author as well.
Jason: Ooo. Okay.
Nikolas: And you can create the author with the post at the same time or you can use connect to connect with an existing one. Of course, that works --
Jason: This is what I've seen called an upcert, is that right?
Nikolas: It's an up cert for the create case. But we have a dedicated upcert too.
Jason: Okay. Here?
Nikolas: Create. This is the data that the new user should have when it gets created. So, again --
Jason: Okay.
Nikolas: Like an email that's required. You can just pass the email. Yeah.
Jason: Okay.
Nikolas: And now on the where field of that, yeah. On the same level as create, just comma, there is a where. And there you have to provide who should be the author if they exist in the database. And you can choose new unique property here. So, if there is a user with IDX or with a certain email, then it will be connected. If not, then the user that you defined up there will be created.
Jason: Okay. So, we can set -- oh! Look at that. I used the wrong value and it highlighted. That's nice. So, then I can put in email. Let's try this again. And the way that we will check this is we'll run it. We should get -- here's our post. It comes in. All good. And then if I run it again...
Nikolas: Ah. Yeah.
Jason: It runs as expects because we did a connect or create. And if we go back and run the... where was it? Prisma Studio.
Nikolas: We'll see all that data.
Jason: Then we can look at our users. And it didn't create multiples. It just created the one.
Nikolas: Yes.
Jason: That's pretty slick. I should probably fix this so it's actually Google-able probably.
Nikolas: That's what we have Prisma Studio for.
Jason: That would have been a pain in the butt to write a one-off query because I typo'd. Yeah. This is powerful stuff. I'm definitely happy here. And it looks like we can even -- can I filter this stuff?
Nikolas: Prisma studio used Prisma client under the hood. All the filtering, pagination options that you see here in Prisma Studio you can use directly in code when you're using Prisma client.
Jason: So, for -- like if it's just me, I could -- I could kind of in a round about way use this as a headless CMS.
Nikolas: Yeah. Like it's -- it's a way to view and ed us your data, right?
Jason: Yeah.
Nikolas: If it's not just super-specific data. If it's not HTML or mark down or anything like that, this can easily be seen as a CMS for sure.
Jason: And it has dark mode. Okay. So, is there -- there's a question about queries. Can you do queries in Prisma Studio?
Nikolas: Not yet. But this is something we're looking at. Kind of similar to like the idea of a REPL and include a Prisma client REPL right in there. And even taking some inspiration from graphical and GraphQL playground where I think it initially were the folks from OneGraph that built this explorer into graphical and click on fields and they automatically appear in your GraphQL queries. These are features that we're thinking about for Prisma Studio as well. And we are super-active on GitHub. All of these questions that you're asking in the chat about specific features, either we already have an existing GitHub issue for that, or you can create one. Because our product teams, our engineering teams, they are watching all of the GitHub repos that are being created and we are very eager to talk to people, their ideas what they want Prisma to do.
Jason: Nice.
Nikolas: Just the call to action for anyone. Create GitHub issues, create GitHub creations, we are excited to talk with you there.
Jason: So, looking at this. We have been able to set up a new database, we defined new tables. Got those set up. We queried data, we wrote data. And we have 30 minutes left to see if we can stand up not one, but two different flavors of API. We're going to try to do a REST API and a GraphQL API.
Nikolas: Yes.
Jason: How do I get started with the REST API?
Nikolas: For the REST API, delete everything you have in there.
Jason: Delete everything?
Nikolas: Delete the entire file. We'll come back. The dependencies that we need for this are express. Just plain express, yes. And like that's it for the normal dependencies. And then you can add as Dev dependencies, add types/express.
Jason: Okay.
Nikolas: So, that the typing is right. Okay. Then back in the script file. Yeah. You can write import express from express on top.
Jason: Is it top level like that?
Nikolas: Yes.
Jason: Okay.
Nikolas: But it has to be -- I think it's lower level -- or actually, I don't -- actually, I don't know. I just like --
Jason: I don't think it matters. Yeah. All right.
Nikolas: Okay. And now you do const app = express. And app.use and then express.JSON inside there so that we have the JSON body parsing and question get that from -- yes, perfect.
Jason: It's a function call like that, right?
Nikolas: Yes, that's correct. Okay. We are ready to write our first route. Let's just write a route to return all posts. So, app.get. The string/posts. And then that's going to be async. And a function that takes a request and a response.
Jason: And this is standard -- if you've never seen express before, this is like every express app is going to look like this. We're saying get route, if you hit it in a browser, going to the Node server, it's going to send the request and gets the response.
Nikolas: As a frontend developer -- so, like as a frontend developer, you of always only seen this from the other side. You've seen the URL with slash posts on the end and gotten your data from there. Now you're seeing how this is actually implemented and where the route gets its data from.
Jason: Yes.
Nikolas: What do you think we should do here, Jason?
Jason: Maybe we start with the easiest thing. Let's res.json, hello, chat. This is the simplest possible API route that we could write. And if I go out here, I still want the same thing. Npm run Dev.
Nikolas: Yes. Might complain --
Jason: Oh, we have to actually listen. We have to app.listen.
Nikolas: Exactly.
Jason: It's going to be on port --
Nikolas: 3000. Yeah, whatever.
Jason: And then we'll get a callback here and this is just gonna let us say that it's listening. So, we can say, console.log.
Nikolas: Yes.
Jason: App listening on --
Nikolas: Local host 3000.
Jason: I don't know why I made that a templates string, I'm going to put the port in there. That's fine. This should actually work. Do that, it's going to listen. Now we have a server listening on local host 3000. Open that up. It didn't take that long -- we didn't need elevator music. [ Laughter ] So, now if I go to posts. No, this will work, this will work. Yes. This will work, right? We're getting posts and getting hello chat. Now what we want to do is get our posts here. So, I can do posts and we did this already. So, let's do Prisma.post.findMany.
Nikolas: Yes.
Jason: And I think we can just leave that be. So, then I can res.json posts. And now, I thinks... oh, wait. I need to -- we don't have like a --
Nikolas: Yeah, yeah. It's not hot reloading.
Jason: Look at it. Look at it, chat!
Nikolas: Great job, Jason.
Jason: I mean, this is really exciting, right? Like we just built a REST API. And so, then if we wanted to add additional -- Ah! Behold! My bucket!
Nikolas: I still have to get used to Twitch.
Jason: Just full blown chaos in here. But so then we can take this and we can -- let's do like a --
Nikolas: Post for posts. Yeah. Yeah, of course, of course. A single ID.
Jason: Then I can get the ID out of -- is it --
Nikolas: It's the params. It's req.params and gets you the ID. You can do the find unique, for example.
Jason: findUnique and it will be where? ID is -- oh. It's just ID.
Nikolas: You've got it. Yeah, you might have to parse it into a number. Since in request params, it --
Jason: That's right.
Nikolas: You can do parse int or use the number constructer.
Jason: Yeah. That -- so, that would work or we could also do it like that.
Nikolas: Yes, exactly.
Jason: You know, this I like. Number constructers is a good clean one.
Nikolas: Yep.
Jason: Let's do that. What this should do, then, is a single post. So, now if I stop and restart, I should install a Node daemon or something. We have our posts. But then if I go to post 1, we get a single post. If we go to post 2, so on and so forth.
Nikolas: You've got it.
Jason: Oops. That's a bad request. Three. Look at us go. We built a REST API, chat! Like, I mean, that is -- that is -- how wonderful is this that this is an experience? And so okay. So, now I want to do users. So, let's do user. And the user ID will come in. And in this case, we'll do user find unique.
Nikolas: Yeah. And what you can do here is you can could in the posts in the query and they'll also be returned now. So, you now get nested data on the frontend.
Jason: Beautiful. All right. So, let's do that. And now, if I go to user 3. We get... here's our posts. If I go to user 1, we get me and there's our posts. So, I mean, this is just like what a -- what an incredibly, like -- it's just fast. It just feels -- it feels good to be able to stand something like that up so quickly.
Nikolas: Yeah.
Jason: Okay. So, knowing that is -- that's like what it takes, right? What -- what was the question, chat? Switch to -- switch to postgres. I don't know that we're going to switch to postgres simply because I want to do this GraphQL API and I don't want to have to stand up a postgres database somewhere. Let's see how long it takes to do GraphQL. Maybe that can be our stretch goal.
Nikolas: And I also actually had two ways to build a GraphQL API in mind, even.
Jason: Oh.
Nikolas: I wanted to use Nexus and type GraphQL. The reason I wanted to show TypeGraphQL is it has a neat integration with Prisma that gives you an API for your Prisma models with basically no code. In fact, I would say we do that first because I think that's a bit more useful for frontend developers who like maybe just want a very quick GraphQL API for the database and they want to write the API server themselves for that. Then TypeGraphQL is a really, really nice option.
Jason: Okay.
Nikolas: With Nexus, you don't get exactly the same. And the syntax is a little bit more -- it maybe feels a little bit more foreign in the beginning if you haven't used it before.
Jason: Okay.
Nikolas: Let's start type GraphQL example. And you can delete the code from the script. Much better, much better.
Jason: Yeah, we can keep the examples for everybody at the end. Let's go GraphQL. And you said we're using Nexus first or Nexus is the second one?
Nikolas: Nexus as the second, yeah.
Jason: This one I should call TypeGraphQL.
Nikolas: Yeah. have you heard of Nexus TypeGraphQL? What's your understanding of this?
Jason: Zero. I'm learning about this right now.
Nikolas: When you guild a GraphQL API, a GraphQL server, you have two components. You have the HTTP server layer. There are tools like Apollo server, express GraphQL, GraphQL yoga, Mercurius, all of these take care of accepting the HTTP requests, extracting the actual GraphQL query from the request and then passing it on to the GraphQL schema layer where the resolvers are going to be called.
Jason: Okay.
Nikolas: And the GraphQL schema can be built with the schema first that you are familiar with from your time at IBM. But there are more ways to create your GraphQL schema. Not only in the SCL first manner, but write out the schema and map resolvers to that. But where you define the schema in code in the first place.
Jason: Okay.
Nikolas: You don't write your schema definition as a string anymore, instead you're defining your schema in code. That's what Nexus as well as TypeGraphQL allow you to do. We will use TypeGraphQL for this one and you need a couple of dependencies for this one. First, type minus GraphQL. The second one is GraphQL minus fields. Then another one that's called a class minus validator.
Jason: Okay.
Nikolas: Then reflect minus metadata.
Jason: Like that?
Nikolas: Yes. And I guess just GraphQL in the end as well.
Jason: Okay. Anything else?
Nikolas: That's it for the regular dependencies. We'll need another Dev dependency in just a bit.
Jason: All right. I'm assuming this is gonna be types?
Nikolas: Yes. No. Actually, no.
Jason: Oh.
Nikolas: It's going to be TypeGraphQL minus Prisma. That's the package. And there's no minus between type and GraphQL. This is inconsistent package naming. It's called GraphQL --
Jason: Oh, what have I done? Cannot resolve dependency. Do I need to use like classic... I think I need -- I'm on npm7 and I haven't taken the time to downgrade because I get very confused by all it of. I'll just use legacy-peer-deps and that's fine.
Nikolas: Also, what we can do now is interesting because you can navigate back to the schema.prisma file.
Jason: Okay.
Nikolas: What we will do is add another generator to this. So, you can copy the generator and right below, you can call a TypeGraphQL. And in the provider, you put in the dependency that you just installed. TypeGraphQL minus Prisma.
Jason: Okay.
Nikolas: Generators are a plugin system, they're an extension for Prisma. Everybody can write their own and take the Prisma models and do whatever they want with it. We have really nice community generators already. For example, there is one that visualizes your Prisma schema. So, you can translate that basically in UML or DBML.
Jason: Okay.
Nikolas: And visualize that with the respective tool. This is a generator that generates an individual API reference for your individual Prisma API.
Jason: That's slick.
Nikolas: We have a ton of these community generators and it's always interesting to see the use cases people come up with. This time you don't have to run migrate, actually. Because migrate primarily changes your database schema. You can use Prisma generate.
Jason: Generate.
Nikolas: It's often called by migrate under the hood. It's could inned in migrate. This time you only need a generator.
Jason: Oh! I understand. Do I need to tag which one I'm using or it just runs both and doesn't matter.
Nikolas: Nope. It should just run both of them now.
Jason: Oops. Incorrect version of the Prisma packages. Oh, I need to upgrade -- oh, I need to upgrade Prisma to the next patch.
Nikolas: Right. Maybe the quick start thing that you downloaded in the beginning --
Jason: Is a .1 out?
Nikolas: That's a task that's on my list to make sure the dependencies in the quick start repo are up to date. This is literally something I missed.
Jason: That's fine. Are we good now?
Nikolas: Yeah. That should work. Let's give it a second.
Jason: There we go. You can now start using Prisma client in your code. Good.
Nikolas: And it also said that it generated the TypeGraphQL integration. That's what we have now as well. And, okay. Ah. We also need Apollo server.
Jason: Okay.
Nikolas: You can npm-install Apollo server as well. And for this one, let's take the cheating route that we discussed before. I'm going to send you a code snippet on Slack.
Jason: Okay.
Nikolas: That you can maybe copy over into the TypeGraphQL.ts file so you don't have to type all of that. But I'll explain what's going on.
Jason: Okay. Am I just putting this into this TypeGraphQL file?
Nikolas: Yes, exactly. And you can just replace everything. Yes.
Jason: Okay. So, let's... give this a little bit of breathing room. Okay. So, we have reflect metadata. Do you know what it does?
Nikolas: It's a thing that's just required TypeGraphQL. To be honest, I'm not 100% sure, but it's required by TypeGraphQL. And it still shows an error for the generated. And I had this -- all right, can you expand the Node modules. Check if the generator is there. It's empty. I had that before when the client generator was -- the TypeGraphQL generator was above the client. But you put it below, right? And I looked that up before in the TypeGraphQL Prisma docs.
Jason: Should I drop this one out for a second and see?
Nikolas: You can try. But I'm pretty sure order is correct. I'm just looking at their docs. And in the docs, it says... after installation, you need to update your schema Prisma file and add a new client generator below the Prisma one. Try to remove Node modules, remove your package lock. That sometimes did it for me.
Jason: Okay. I ran it one more time to see if it showed up. And it --
Nikolas: It could be that you only updated the Prisma dependency but not the Prisma client dependency.
Jason: It's back. Well, let's see, I guess. Let's try it and see what happens. Maybe it just didn't stick that first time. Whatever happened, it's okay now.
Nikolas: All right. So, then basically what we do is we just import these resolvers from the generated TypeGraphQL folder. And that's all the magic that's actually implementing resolver. So, if you remember back to your SDL first days at IBM, the way you would implement a GraphQL server was, you would write out like the schema definition, all your queries, all your mutations. And then you would write resolvers. And that's now what's happening in these generated files. All of that code is there in order to resolve incoming queries and mutations against the database. So, if you start this, you should see a -- an Apollo server GraphQL playground that has this -- that takes the Prisma models and just exposes full on operations for them.
Jason: All right. If I start this, then. Which I set this as Dev GraphQL. So, if I run npm Dev GraphQL. This should open up... [elevator music] Okay. Here we go. Then we've got --
Nikolas: Expand the schema in the docs. There you go.
Jason: Beautiful. So, we can do a lot here. So, let's do a -- let's do a query. I'm gonna do a query and we're gonna get the posts. And I want the title and the author. And let's get the author name. Look at it go! Chat! This is so cool! Okay. Yeah. I love this. It just makes me happy when stuff just works, you know what I mean?
Nikolas: Absolutely. And I quickly -- I quickly want to give a shoutout to one of our work -- working students in developer relations, it's Alex. And he wrote this blog post. I just dropped it in the chat. That talks about that TypeGraphQL Prisma integration and is a really nice and step-by-step tutorial for everybody to follow if you're interested in like setting up what we just set up here on the screen. But from scratch, basically.
Jason: Yeah. Yeah. We'll make sure this shows up in the show notes as well. So, if you are watching this after the fact, you can check that out in the show notes.
Nikolas: Very nice.
Jason: Okay. We just set up a GraphQL API. This is now usable. That's super-exciting. And you say there's another way to do this with Nexus.
Nikolas: Yes, with Nexus, it's going to be a lot more typing because we don't have that nice of an integration that autogenerates these resolvers for you.
Jason: Okay.
Nikolas: We can still talk about it and I can quickly walk you through the syntax there to explain how Nexus works as opposed to maybe an SQL first approach.
Jason: Sure.
Nikolas: Dependencies you need are just Nexus, actually.
Jason: Like that? Or Prisma Nexus?
Nikolas: It's just Nexus.
Jason: Nothing else?
Nikolas: Nothing else. We already installed GraphQL. We don't need it. And we already installed Apollo server. So, we don't need either of these dependencies anymore. And, yeah. With Nexus.
Jason: Okay. So, now I'm going to... call this one Nexus. And I'm just gonna drop everything out. So, all right. So, how do we get started here?
Nikolas: Let's starts and this is now like not Prisma-related anymore. So, I just want to make that clear. That what we do right now is we build a GraphQL API with Nexus. And later when we implement the resolvers, we will be using Prisma again. But this is all disconnected from Prisma. It's how to implement the GraphQL API. But where the data is coming from is separate.
Jason: Gotcha.
Nikolas: We'll import two functions from the Nexus package that are called objectType and makeSchema. And I wonder if -- I will again send you over some boilerplate at least that you can paste. Otherwise it's gonna be a bit cumbersome.
Jason: Okay. So, here is a bit Boilerplate.
Nikolas: Yes. All right. For now, the -- you can remove the post and the user there. From types. And we'll create query in a second. The outputs just mean, where do you want to see the schema definition? And where should -- like where should Nexus generate its types to? And then we have Apollo server. Yes, we need to import that as well and then we just start apollo server.
Jason: Okay. So, import Apollo server.
Nikolas: Yes.
Jason: And is that...
Nikolas: Let me check...
Jason: Is that top level or is that names?
Nikolas: Lets me check. I have all this prepared. It is named.
Jason: Okay. Okay.
Nikolas: So, yeah. So, as an object, yeah.
Jason: And then we need a query.
Nikolas: Yes. And the query is not -- it's -- it is a GraphQL object type. It's the query type.
Jason: Okay.
Nikolas: And what we do now --
Jason: Like this, then?
Nikolas: Yes. And it is basically what you would now do when you start writing out your GraphQL schema. You would write type query and then you would say, okay. It should have a post field. And that's of type post. So, that's what we do now but with a different kind of syntax.
Jason: Okay. I'm going to stop guessing and I'm going to let you tell me what should happen next.
Nikolas: Yes. All right. It takes an object. There your intuition was correct.
Jason: Okay.
Nikolas: Object and enter. And the first thing we have to name this object type. So, it's a name. And we'll name it query because it's the query type in GraphQL. And next it gets a definition. Definition is a function. Write definition and parentheses and there is one argument this function takes and that's a -- it's called T, typically. And that's just like a Nexus convention, basically.
Jason: Okay.
Nikolas: Now you start defining the types -- the fields of your query type. And we can just start with a very simple hello world field for now. You can do T dot --
Jason: Oh, T dot.
Nikolas: Yeah. So, like at the moment we're inside of a function body. It's a little bit like the --
Jason: Oh, yeah, yeah.
Nikolas: It takes a little bit to get used to the syntax. But it will come like very naturally and also has a lot of autocompletion. But in the beginning, it can be counterintuitive if you haven't worked with a similar API before. And now you can provide the resolver for that. So, add a comma. And, yeah, actually, that should work. That's the shorthand syntax, I think. If it doesn't work, copy out the entire lambda.
Jason: What have I just done? Why doesn't that work?
Nikolas: Actually it's not T.field, it's T.string.
Jason: Oh, gotcha, gotcha.
Nikolas: Which is a short hand for a string field. It might be that it's not working and you have to pass an object as the second argument.
Jason: Parameter of type array?
Nikolas: Yeah. So, maybe just like take out that entire function and like add an object there. And there should be a resolve property inside of that object. If you now hit enter, resolve.
Jason: Okay. I got ahead of myself.
Nikolas: That's it.
Jason: Gotcha.
Nikolas: That's it.
Jason: So, now if I --
Nikolas: You can run this.
Jason: I can run this.
Nikolas: Yes.
Jason: I'm going run this -- I set this up. Let's see. Called it Nexus, Dev Nexus. This should just run. Npm run Dev Nexus. And we have local 4000 which is open out here. So, here's our new one. And it's simplified. But if I run hello, I should get... hello world. And I go back in here and change it to chat. Do I need to stop and restart, or does this hot reload?
Nikolas: Stop and restart. We're still just using TS node.
Jason: That's right. It's not in Nexus. I'm running.
Nikolas: It's not a framework or anything.
Jason: Yeah.
Nikolas: It's libraries to build up your GraphQL schema. Yeah. All right. So, now we can actually start representing our models in GraphQL using Nexus.
Jason: Yeah.
Nikolas: We do that by creating new object types. In fact, you can just copy the entire query type probably and then we'll go from there.
Jason: Okay. I'm gonna do this the long way once. And then we'll copy/paste for the other one. Or let's start with -- maybe we start with user.
Nikolas: Yeah.
Jason: Because user was contained. I've got user. And then I've got my definition. My definition gets the type. And then I create a string. Which would be the title.
Nikolas: The ID, okay. Well, actually --
Jason: Oh, yeah, I need the ID, don't I?
Nikolas: Right. And we're on the user right now.
Jason: Yeah. Okay.
Nikolas: And, yeah. Well, like here it's actually not T.id, but it's t.int. I think you could potentially use t.id, but -- and you don't need a resolver for this because we're on the lowest level of the GraphQL resolver system where scalars are just resolved with the object that are, passed in. Like the entire topic of how the GraphQL resolver system works in detail and how it's nested is a little bit too complex I think for the stream. But for the scalars, you don't need the second object. You write t.int and t.email.
Jason: Okay. I think we can do this in one second. Here is what helped me understand. I have the user, the ID is 1. I have a GraphQL query and I do a query for a user and then I get the ID, it's going to, like, you know, let's say it's like that. It's gonna get this object. And then that object gets passed into the resolver functions and the resolver functions basically just look for a property on the object with that value.
Nikolas: That's -- that's really, really well explained. And I'll drop a link to a blog post that I wrote like three years ago, four years ago? And where this made click for me. And in the blog post, I just tried to reproduce that ah-ha moment that I had when I initially understood the GraphQL resolver system and just tried to explain it here.
Jason: Yeah. It's definitely like -- this I would say is the hardest part of GraphQL is getting your head around what happens to make these queries use data. Because there's a couple layers of indirection in there. And that's what makes GraphQL powerful. But it's also definitely a little head bendy when you start. Okay. So, then if you have the string and then we've got the name. I think we can probably start there. So, then if I drop in my user. Okay. So, I'm getting... somewhat close here. But I haven't actually looked up my data. So, how would I get my data to show a user?
Nikolas: That's a really good question. How would you? How did you implement the first hello world query?
Jason: I dropped into my -- oh. I would be in my query.
Nikolas: Right.
Jason: So, I would have a t dot -- ooo... here's a good question. How do I reference a type?
Nikolas: This time you're using t.field. It's just the shorthand notation. So, here you can --
Jason: Like this?
Nikolas: Not yet. First you just provide the name of the field.
Jason: Okay.
Nikolas: Which could be users. If it's a single user, then just user. Resolve is also the right intuition already. But if you want to have a single user, we'll need a bit more as well. Like maybe we start with users and return all users.
Jason: Yeah, let's start there. So, then I would be -- this is going to have to be async.
Nikolas: And you still didn't tell Nexus what type it was, or what type the field should be. That's another property in the project. And it autocompletes. If you have the server running. Actually you're supposed to run Nexus with a development server in the background. It will generate as you type, it will autocomplete. It won't right now. That's not a problem. And there you can also say list, true, you think in the object. Or just do t.list.field is a little bit -- actually, yeah. So, maybe that was removed. But like t.list.field should work. Or actually, I think that also worked. Yeah, yeah.
Jason: Okay.
Nikolas: But it's still complaining about the user type because it's not generated. But as you start the server, it will be generated.
Jason: Okay. So, then I have -- it's gonna be await. And then I need a Prisma. I'm gonna copy/paste this part out. I'm gonna get a Prisma client. Do I have one? Because we registered it here.
Nikolas: Actually no. You have to import it.
Jason: Okay. Here's my Prisma client. I'm going to grab a new Prisma client here. And then I'm going to await Prisma.user.findMany. And then we're going to return users.
Nikolas: That's it.
Jason: And theoretically, that should just work, right? So, if I run this it'll work?
Nikolas: Um... I think the TypeScript might complain about a minor issue -- or actually like maybe that's a runtime issue. But there is one inconsistency we can take a look at in a second. But yeah, for now, just go ahead and run the query. There you go.
Jason: It seems happy enough. Let's see if it gave any -- didn't get any warnings. What was the inconsistency you saw?
Nikolas: If you go back to the code, we now have a can schema.graphQL file that's generated -- I only see schema.gql? That's -- inside generated. If you scroll down in the code, actually, in the code window on the left.
Jason: Oh, code window on the left.
Nikolas: Exactly. Further down, it emits the schema.graphQL file in a parent folder.
Jason: Oh! Up here.
Nikolas: That's the one that we got from TypeGraphQL. That's a bit unfortunate. It's called schema -- there should be another one called schema.graphQL. I'm confused. It doesn't seem to be there. Weird. But like the inconsistency is in the optional and required like modification of each field. Because with Nexus, all of these are optional right now. Okay. Actually, I guess that works. Because with Nexus, these are optional at the moment by default. So, that works because under the hood, Prisma requires them. So, Prisma can always fulfill the optional requirement from Nexus here.
Jason: I gotcha.
Nikolas: If in the database it was required as optional, but on the Nexus level, it would be declared as required, then we might run into trouble here.
Jason: I gotcha. So, when I go to commit this, because we are out of time, do I ignore like generated and schema.gql?
Nikolas: That depends on what you want. But you can certainly include it. And I think especially the schema.gql is nice for people to have a look at to see what the actual GraphQL schema that comes out of it looks like.
Jason: Okay.
Nikolas: Because it's just using --
Jason: I can just include everything and that's okay.
Nikolas: Yes.
Jason: Okay. Cool. Let's do it. I'm going to commit that. And while I'm doing that, where should people go if they want to learn more?
Nikolas: They can go to the Prisma documentation. We have extensive documentation about all technical components, about relevant workflows. The GitHub issues and GitHub discussions are a really good place to get in touch with us personally. We also have a gigantic and very active and lively Slack community. So, one of these developer tools that haven't made the move of their community to another tool because to be fair, Slack works really well for us. And we like when people get in touch with us there. And yeah. Watch out for some really exciting blog posts that we have coming in the next couple of weeks. So, we'll talk a little bit more about where we were headed also from a commercial standpoint because of people are wondering, hey, you built this open source ORM, but you're a VC-backed company. That's not a secret. How you plan to make money and how can I be sure that in 5 years the open source tools will still be around if I now base my application on them? We'll talk a lot about that in the upcoming weeks on the blog and elsewhere.
Jason: Cool. And go and follow Nikolas on Twitter. And remember the show as always has been live captioned. We have had Amanda with us all day today, thank you, Amanda. That is through White Coat Captioning. That is made possible through the support of you are sponsors, Netlify, Fauna, Auth0, and Hasura, all kicking in to make this show more accessible to more people. While you're checking out the site, make sure that you go and check out the schedule. We have some really fun stuff coming up. We're really excited about it. We've got Jennifer Wadella coming on the show, Nathaniel Okenwa coming back, Shaundai Person is coming. It's going to be a great time. We have a whole week of guest episodes with Ben Hong is going to take over. It's going to be Learn with Ben! I'm so excited about that. Just make sure you go. Check out the schedule. Click this add to calendar button. It's going show up on your Google calendar so you can see what's happening and when. With that, I think we can call this one a success. Niko, thanks so much for hanging out with us today. Chat, as always, thanks so much for hanging out. We're going to go find somebody to raid. And see you next time.
Nikolas: My pleasure. Thank you so much for having me!
Jason: See you all!
Learn With Jason is made possible by our sponsors: