In this section, you’re going to learn how to connect your GraphQL server to your database using Prisma, which provides the interface to your database. This connection is implemented via Prisma Client.
The first thing you need to do is import your generated Prisma Client library and wire up the GraphQL server so that you can access the database queries that your new Prisma Client exposes.
context
resolver argumentRemember how we said earlier that all GraphQL resolver functions always receive four arguments? To accomplish this step, you’ll need to get to know another one – the context
argument!
The context
argument is a plain JavaScript object that every resolver in the resolver chain can read from and write to. Thus, it is basically a means for resolvers to communicate. A really helpful
feature is that you can already write to the context
at the moment when the GraphQL server itself is being initialized.
This means that you can attach an instance of Prisma Client to the context
when initializing the server and then access it from inside our resolvers via the context
argument!
That’s all a bit theoretical, so let’s see how it looks in action 💻
You’ll start by creating a new file called src/context.ts
to handle our GraphQL context
creation.
In the next step, you’ll connect the Prisma client and your GraphQL server!
Awesome! This will make the prisma
object available for us during the execution of our resolvers
.
Now, the context
object that’s passed into all your GraphQL resolvers is being initialized right here and because you’re attaching an instance of PrismaClient
(as prisma
) to it when the GraphQL server is instantiated, you’ll now be able to access context.prisma
in all of your resolvers.
To get the most out of the TypeScript language, you also created a GraphQLContext
type to have strict validation, and to make it easier to type the resolvers later.
This TypeScript type GraphQLContext
will represent the structure of the GraphQL context
, and will help us to get better type-safety and auto-complete for the Prisma SDK.
Finally, it’s time to refactor the GraphQL resolvers. Again, we encourage you to type these changes yourself so that you can get used to Prisma’s autocompletion and how to leverage that to intuitively figure out what resolvers should be on your own.
Next, you need to update the implementation of the resolver functions because they’re still accessing the variables that were just deleted. Plus, you now want to return actual data from the database instead of local dummy data.
Now let’s understand how these new resolvers are working!
feed
resolverThe feed
resolver is implemented as follows:
const resolvers = {
Query: {
// ...
feed: async (parent: unknown, args: {}, context: GraphQLContext) => {
return context.prisma.link.findMany();
},
},
// ...
}
It accesses the prisma
object via the context
argument we discussed a moment ago. As a reminder, this is actually an entire PrismaClient
instance that’s imported from the generated @prisma/client
library, effectively allowing you to access your database through the Prisma Client API you set up in chapter 4.
Now, you should be able to imagine the complete system and workflow of a Prisma/GraphQL project, where our Prisma Client API exposes a number of database queries that let you read and write data in the database.
post
resolverThe post
resolver now looks like this:
const resolvers = {
Mutation: {
post: async (
parent: unknown,
args: { description: string; url: string },
context: GraphQLContext
) => {
const newLink = await context.prisma.link.create({
data: {
url: args.url,
description: args.description,
},
});
return newLink;
},
},
};
Similar to the feed
resolver, you’re simply invoking a function on the PrismaClient
instance which is attached to the context
.
You’re calling the create
method on a link
from your Prisma Client API. As arguments, you’re passing the data that the resolvers receive via the args
parameter.
So, to summarize, Prisma Client exposes a CRUD API for the models in your datamodel for you to read and write in your database. These methods are auto-generated based on your model definitions in
schema.prisma
.
You may also have noticed that newLink
is an object of type Promise
. This is because all Prisma CRUD operations are asynchronous. This is not a problem as Fastify Server is capable of detecting, and automatically resolving any Promise
object that is returned from resolver functions.
With these code changes, you can now go ahead and test if the new implementation with a database works as expected. As usual, run the following command in your terminal to start the GraphQL server (npm run dev
, or npm start
)
Then, open GraphiQL at http://localhost:3000/playground
. You can send the same feed
query and post
mutation as before. However, the difference is that this time the submitted links will be
persisted in your SQLite database. Therefore, if you restart the server, the feed
query will keep returning the same links.
Prisma ships with a powerful database GUI where you can interact with your data: Prisma Studio.
Prisma Studio is different from a typical database GUI (such as TablePlus) in that it provides a layer of abstraction which allows you to see your data represented as it is in your Prisma data model.
This is one of the several ways that Prisma bridges the gap between how you structure and interact with your data in your application and how it is actually structured and represented in the underlying database. One major benefit of this is that it helps you to build intuition and understanding of these two linked but separate layers over time.
Let’s run Prisma Studio and see it in action!
Running the command should open a tab in your browser automatically (running on http://localhost:5555
) where you will see the following interface. Notice that you see a tab for your Link
model and can also explore all models by hovering on the far left menu: