GraphQL with Mercurius and Prisma, love at first sight


In this speech, I'll talk about the benefit of using GraphQL and show a small demo of an endpoint created with Fastify Mercurius and Prisma.


Okay, today I want to speak about... and prisma with Mercurius. So first of all, who I am. I'm Luca Del Pupo and I'm an Italian guy. I'm a full stack developer and I love javascript and also typescript. In my free time I create some content in my YouTube channel and I love to write something for the other to show my experience and to share my experience. And I love running and hiking. But now it's time to go to the topic. So why I'm here? First because the committee decided to vote my talk, so thank you. And then because in the last period I tried to help a customer move from REST api to graphql. So I want to share with you our experience and how we decided to move in this way. So in the last 10 years, typically I work only with the REST api. When I start to work, the api typically serve only browser or maybe some desktop application. And REST api works very well in this way, in this case, and you can use it without any problem. I don't have any mistake or problem against REST api because they work very well and I use it in my daily in this moment. But in some scenario, we have to improve the flexibility of the api. Typically in the last period, we start to use other device that use our api, for instance, a smartphone and also a smartphone and a smart TV. So we start to learn the potential of graphql because we need to give more powerful, more power to the client, unfortunately. And so we start to learn and try graphql. Before move to the decision, I want to show you also the need for the customer in this case. Typically I work with a small and medium company and they have a lot of junior and middle developer and some senior developer. The need for this customer are these typically. They want a framework or a code base easy to maintain. Then the framework or the architecture need to help in the day by day. The developer need to help the junior typically because they want to put the value and increase the skill and also help the senior to not spend time to resolve a framework problem. Then we need, it's a must, have a typescript in our application and the developer must be focused on business and not to resolve framework problem. So with this need, we decided to move in this way with Merkur in the graphql part and prisma to call the database and the part of the data access. The developers stay in the middle, so I have to create the graphql signature and create the code to access to the database using prisma. Why we decided to move in this way? First, the graphql implementation. We already know fastify and Mercurius is built on top of fastify. So for the developer, it's easy to learn Mercurius because it's easy to use if you already know fastify. Then Mercurius is easy to use. It's not rocket science. If you know graphql, you can create a graphql server in a very easy way. The documentation is awesome in my opinion, and you can open the website and you can find everything. And if you don't find your info, you can open an issue, ask to the community and they answer as soon as possible. Last, in order, typescript is support out of the box, so you don't have to spend too much time to use typescript. Yes, you have to create the TS configure and so on, but it's very easy. And last, there is a small MPM package called Mercurius CodeGen that help you to convert your JQL file with all the signature of your JQL server in typescript definition. So you can guarantee the definition of your graphql with the typescript. And also you can, if you want to create operation to build your test for test your graphql server in this case. And for instance, if you change the graphql schema and you broke the operation during the code generation, the Mercurius library raise an error and you have to fix it. So you can prevent the problem before arriving in production in this case. Then for the database implementation, for the data access implementation, we decide to move to prisma. Typically, I don't love ORM, but prisma is a bit different in this case. Help us to improve the developer experience of the developer. And also it's easy to use and easy to maintain. And if you are familiar with typescript, the syntax for creating a database and data access layer with prisma, it's pretty simple. Then prisma have a good data modeling. So it's very easy to create your entity using prisma. You can create type safe query, so you can guarantee your query during the build time of your application, if you use typescript. And you can also use the migration to keep up to date your database in production or in stage and so on. Last but not the least, you can integrate prisma in your fastify application by a simple plugin. So it's very easy to integrate in a fastify environment. And last, both Mercurius and prisma love typescript. So I speak too much. So I want to show you the demo so you can see the code to understand the benefit of the solution. So first of all, I run the server so you can see the demo in this case. I show you the demo there before in the... It's okay. Bigger to not bigger. Okay. Better? Perfect. Okay. This is graphql. graphql is a UI interface to test or to show or to see the documentation of your graphql server. You can use the docs if you want, and you can check which are the query in this case. You can check which are the mutation or which are the subscription. So if you want, you can see all the documentation of your graphql server. Then you can also test your application. For instance, I already create a query for a welcome. So this is a Tonino pizza menu. So sorry, I'm Italian and the pizza is in my blood. The first query is the welcome. So it's simple. You call the query welcome and the server responds with welcome to Tonino pizza. You can also create query with a parameter if you want. Pretty simple. You can call in this case, hi Pupo. I pass the name, my name in this case. Hi Pupo, welcome to Tonino pizza. To see a more complex example, we can do in the pizza. I already created a pizza. This is the pizza for the Ninja Turtle. So you can see the list of the pizza. In this case, the pizza are only one, the pepperoni pizza. And as you can see, you can see all the implement, you can see the list of the pizza in the menu in this case. You can also, for instance, create a new pizza, the pizza margherita and so on. Pretty simple. I don't want to spend too much time in the graphql because it's not the real focus of the topic. You can create pizza and then you can see in the pizza list your pizza. Pretty simple in this case. Okay, now I want to move in the code to show how we can implement this graphql server. So this is my application. I want to start from the prisma side. So if you want to work with prisma, typically you have to work in a single folder called prisma. And there is only one file. It's okay, the code is visible. Okay, perfect. The schema prisma is the only file to work with prisma. So in this case, the schema prisma is the single source of your database. The schema prisma is pretty simple. There is the first part where you can see the generator. The generator is the provider used to build your node client to call your database. The data source is the info to understand which is the provider. In this case, the provider is the Postgres SQL, but you can use MySQL, SQL Server and other provider. The URL is used for the connection string. And then the other part important is the model. The model is the entity, the models are the entity of your database in this case. The syntax, as you can notice, is similar to typescript. The model indicates that this model, the topic is a simple entity for the database. And then you can describe your column or your property. So in this case, the ID, the name and the creator and so on. You can indicate the type of the column, in this case, string, date time and so on. And you can decorate each property with a specific decoration. For instance, the ID for the primary key, the default for if you wanted to put a default UID in your entity and so on. You can also create a relation, so the foreign key, using a simple syntax with the relation. Pretty simple. And if you want to improve your developer experience, you can install the prisma extension in VS Code to get some intelligence. For instance, you can get the help for creating the column and so on. If you start to work with prisma, you have to know four commands for the CLI. Typically, you have to start from the MPX prisma. prisma is the CLI. And the init is the first command. Init is used to initialize your project, in this case. And I already created it, so I don't run it. Then the second is the generate. Generate is used to convert the schema in your prisma client to call the database from your codebase. So if you run it, prisma starts to read your schema and create the prisma client as an object. There is the prisma client used to call the database and make the query and so on. The last, but not the least, the prisma CLI permit to create the migration. There are two commands for the migration, the dev and the deploy. The dev is used during the development mode. So if you change the schema, for instance, and you add a new column or a new table, you have to call the dev command to create the new migration. The migration are inside of the prisma folder, inside of the migration folder. This migration is inside of a single folder with the timestamp and a simple description that you can put. And the migration is a simple file. In this case, there is only one migration to create the topping table, the pizza table and so on. You can use the dev, but you can also use the deploy. In my case, if I run the deploy, I try to apply the migration, but the migration are already applied and in this case, nothing happened. It's common to use the deploy in your CI or in the deploy script, depending on how you implement this stuff. Now it's time to move to the graphql part. So in this case, there are two important folders for this implementation. The first is the graphql folder, where you can find all the JQL files. There is the schema that contains all the description for your JQL server. In this case, mutation contains all the mutation. Close this. Okay. Mutation contains the mutation, query contains all the query and subscription, all the subscription. You can also create one file with all the code inside. I prefer to split because it's a clear than only one file. And then you can also create a folder with, I don't know, the input for the pizza, the pizza type and so on. Pretty simple if you already know graphql and I hope you already know it. The operation is used by Mercurius to create our test case. For instance, you can create the query for the welcome and the Mercurius code gen convert this operation in an object that you can use to test your server during the development stage. Now it's time to see the code. So in the source code, typically there is the server. As you can notice, the server is a simple fastify server. So you have to initialize a simple fastify instance and then you can register something. In this case, the port is the 3000 and in the app folder, in the app file, you can find the real application. The real application has two main points. First, try to load the plugins and the plugins in this case are two. The configuration, so it's pretty simple in this case. I use a type box to check if the process environment contains the node and also the database URL. So in this case, I'm sure that the process and contain these two properties and this two environment. And then the important part is the db context. Db context is a simple fastify plugin that is used to initialize the prisma client. In this case, fp is the fastify plugin function and you can create the prisma client in this way. So you can use the new prisma client and you can pass the URL in this case. The URL is used as connection string. Then you have to create the connection in this way and then you can decorate your server using the decorate property function. And in this case, the db context contain our prisma client instance. So in this way, you can use the app.db context to have access to the prisma's implementation. Last but not least, there is a hook on the onClose to disconnect the connection if the server shuts down. Pretty simple. Now it's time to see the important part for the graphql. graphql is registered as another plugin in this case and in the graphql file you can find all the implementation. As you can notice, Mercurius is a simple plugin registered in fastify and you have to pass some configuration. The first is the schema. So using the load schema function, I used the Mercurius code gen library to convert the JQL folder in real code for Mercurius. The first thing is the load schema file. Using this syntax, you can say to Mercurius code gen where it can find the JQL file and the library check. Okay. It's not a good day probably for my Mac. Okay. And convert all the file in a schema for Mercurius. And also if you want, you can enable the watch mode to change in real time your server. In this case, for me, it's only in developer mode. And in this case, when something changes, I refresh the graphql part for add a new feature or something like this. Okay. The last before going to the real code is the code gen Mercurius function that used the idea of the JQL file to convert the JQL file to typescript. So in the target path as a source resolver generated TS, you can find all the definition of your server. So you can find, for instance, the mutation, the query and the mutation. This type is used by the developer to be sure the server respect the JQL definition. Now, if I go back to the graphql part, when you set up this, you have only to pay attention or take care about to create the code for your business. So for creating the loader and the resolver. So today I speak only about the resolver because I have only 20 minutes, but it's similar for the loader. Inside of the resolver folder, you can find the index. The resolver is a simple object with a three property, the query, the mutation and the subscription. And in my case, I create a simple folder for each of one of these. So inside of the query, the mutation, you can find all the mutation for the pizza, for the topping and so on. Inside of the query, you can find all the query for the pizza and the topping and so on. And pretty simple in this case. I want to show you, for instance, the mutation for the create pizza. In this case, the implementation is pretty simple. So using this syntax, the typically typescript syntax, I create a new function called createPizza. And using the type of the mutation, I say to this function that must respect the signature of the createPizza in the mutation types. In this way, I'm sure that the code must respect the jql file described before. So the function is pretty simple. So there is the parent. In this case, you don't have to pay much attention to the parent. That is the first parameter. The second parameter is the data arrived from the client, in this case, the pizza. So the name and the list of the topping. The third parameter contains the graphql context, if you want, the instance of the fastify application and also the pub sub object in this case. So using the app, you can get, for instance, the logger, in this case, Pino, or the db context. The db context, as you can see, is the prisma client registered before with the plugin. And in this way, you can call, for instance, the db to insert the pizza in your database. The db context is pretty simple to use. So you can use db context and you can have the pizza, in our case, the topping, and the recipe, if you want. Each model creates an object with all the possibility method for insert, select, update, and delete. Pretty simple. Then you can put together the stuff and you can create your business logic, in this case. Pub sub. What is pub sub? If you have some subscription, you can use the pub sub object to notify that something happened. In this case, I created the pizza created event, in this case, and this notified the subscription. And if something is subscribed, it received the notification. Pretty simple. The query is very similar. So I show you, for instance, the topping. In this case, I use the query object and using the get topping. In this case, you have different objects because in this case, the query wants the pagination. You can get the limit and the offset. And you can use the find method to find many toppings in this case. Or you can also use the get topping to get the topping by an ID, for instance. I know the example is pretty simple, but probably you have understood the benefit of using this architecture. From the demo, I think that's all. So I want to go to the slide again to close the talk. So, perfect. Okay. Conclusion. I'm not a salesman, so I'm not here to sell this solution. But it's a possible solution if you want to work with graphql. Why we decide to move in this way? First, fastify and Mercuro is a good option to create graphql server. fastify is very, very fast if you want, and Mercurio is also. And the combination helps you to create a very performance server. Yes, if you know graphql, you can create a very bad mistake if you want. But in this case, it's not in Mercurio's side, but in the developer's side, probably the problem. Using prisma, you can create a layer between your application and the database. You can have a good developer experience. Yes, you have to have a tradeoff because go direct to the database or using NRM in this case. But with prisma, typically you can improve the velocity of your team. And if you have some problem with the query, it's very easy to customize the query and create your own query if you want. Last but not least, developers are focused on creating features for your business and not waste time to resolve a framework problem or because there is a patch, a monkey patch that broke your server. And they both love TyScript. So I think that's all. If you want, here you can find the slide and also the demo. I share all in my social then. If you want to go dive to prisma, I wrote a prisma series and you can find it in DevTO or in this QR code. And that's all. Thank you very much to everyone. These are my contact. So LinkedIn and Twitter are open. So you're welcome if you want to chat with me. If you want to subscribe to my YouTube channel, this is the name. And if you want to read something, DevTO or my blog post are in my blog. And that's all. Thank you. I hope you enjoy this content and thank you to everyone and to Node Congress. Thank you, Luca. Awesome. And we have quite a few questions already. Well, first one I think might be partially answered already. Not the one that I right now selected. One second. Is a code for a demo available somewhere? Is it on the same QR codes? Yes. We can go back to the code. You have to go to this QR code. It's the GitHub code, the GitHub link. You have to fork or clone it and run the server. It's not available in a link, but you can download, clone the project and run it. So I hope it's okay. Yeah. Thanks. Thanks for that. Yeah. Next one. Would you recommend using Mercurius for graphql subscriptions, WebSocket connection? How would you compare it to graphql apollo? Okay. In reality, graphql subscription, I don't which you're using. In reality, graphql subscription use a WebSocket by default. So if you want to build another WebSocket to handle it, you can do this without any problem, but by default, you can use graphql subscription with a WebSocket. Very simple. How to compare it to graphql apollo? Okay. In the last period, I lose the control of apollo probably. I tried it two year ago. Two year ago. Yes. And the problem with apollo is based on Express. I know now they created their own server. Probably it's better in this moment, but if you want, you can also integrate apollo in fastify without any problem. There is a plugin, right? Thank you, Matteo. And so in reality, I hate to compare to Staffer. There is pros and cons in the solution. Typically, you have to find your best way for your solution probably. All right. Thank you. Yeah. Any thoughts on a POTS graphql, which flips the schema generation to be typescript first? I don't know what is POTS graphql in reality, so I don't have the answer probably in this case. Please give us more information. Yeah. Another one. Why Mercurius? Okay. This is a good question. In reality, as I said before, we already know fastify. And Mercurius in this case, it's built on top of fastify. The other motivation is the team love of fastify. And we moved from Express to fastify. And the way to create a node before node REST api with fastify, it's similar to Express, but you have a good performance, a good maintainer. Thank you, guys. And also, you can have a new release if you check the Express release. It's stopped to the version 4.3. I don't remember. 4.3 or 4.8. So, yes, the community behind Poi is better in this moment than other framework for the node environment. Okay. Quick reminder for everyone. Oh, yes. Yeah. A quick reminder to... And also pay attention to create a lot of loader that create a lot of query that create a lot of wait in time for your user probably. Nice. Yeah, I think I just have one maybe question. It can be a very quick one. So, if you could choose like your ideal stack for, let's say, database plus api on... Yeah, let's limit it to node.js. What would you choose? Probably limited to node.js. Probably for the REST api and the Kafka fastify. And for the database, if you have to choose NRM, choose prisma. If you know very well, if you have time and you know very well the provider, use the default provider for your provider. Also use the mongodb provider and so on. Typically, if you want to... If you want control of your database, use direct the provider exposed by the database in this case, because give you more control of the stuff. Thank you, Luca. Thank you. Yeah. Thank you, Luca.
34 min
14 Apr, 2023

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Workshops on related topic