Connecting The Server and Database with Prisma Client

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.

Wiring up your GraphQL schema with 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.

The GraphQL context resolver argument

Remember 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!

Updating the resolver functions to use Prisma Client

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!

Understanding the feed resolver

The 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.

Understanding the post resolver

The 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.

Testing the new implementation

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.

Exploring your data in Prisma Studio

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:

see a tab for your Link model

hovering on the far left menu

Unlock the next chapter
What is the purpose of the context argument in GraphQL resolvers?
It always provides access to a database
It carries the query arguments
It is used for authentication
It lets resolvers communicate with each other