Get Started

Build GraphQL Servers with Prisma

Goals

On this page, you will learn how to:

  • Define the GraphQL schema for a domain-specific GraphQL API
  • Implement resolver functions that are delegating requests to Prisma using Prisma bindings

Add graphql-yoga server library to Node.JS project

grahpql-yoga is a GraphQL server library based on Express.js. Add it to your project with the following command:

yarn add graphql-yoga
Copy

Create and define the application schema

When building GraphQL servers with Prisma, you're working with two GraphQL APIs:

  • The database layer exposing generic CRUD operations (configured with Prisma)
  • The application layer exposing a domain-specific API tailored to the needs of your client applications

While the auto-generated GraphQL schema in prisma.graphql defines the API of your Prisma service, the GraphQL schema of your application layer (also called application schema) still needs to be defined.

Create application schema: schema.graphql

Create a new file called schema.graphql which you will use to store the application schema:

touch schema.graphql
Copy

Define API operations for application layer

To define the API operations for your client applications, you need to specify the Query and Mutation types in your application schema - the following operations are examples for a simple blogging application:

# import User, Post from "prisma.graphql"

type Query {
  publishedPosts: [Post!]!
  post(postId: ID!): Post
  postsByUser(userId: ID!): [Post!]!
}

type Mutation {
  createUser(name: String!): User
  createDraft(title: String!, userId: ID!): Post
  publish(postId: ID!): Post
}
Copy

What looks like a comment in the first line of the application schema is not a comment but a required import statement from the graphql-import library. If it was removed, the application schema would not be valid any more as the Post and User types were both undefined.

Implement resolver functions

Each API operation is backed by exactly one resolver function that's invoked when the operation is requested by a client. Here is how you implement the resolver functions for the six API operations you defined in the application schema. Replace the current contents of index.js entirely with the following code snippet:

const { GraphQLServer } = require('graphql-yoga')
const { Prisma } = require('prisma-binding')

const resolvers = {
  Query: {
    publishedPosts(parent, args, context, info) {
      return context.db.query.posts({ where: { published: true } }, info)
    },
    post(parent, args, context, info) {
      return context.db.query.post({ where: { id: args.postId } }, info)
    },
    postsByUser(parent, args, context, info) {
      return context.db.query.posts(
        {
          where: {
            author: { id: args.userId },
          },
        },
        info,
      )
    },
  },
  Mutation: {
    createDraft(parent, args, context, info) {
      return context.db.mutation.createPost(
        {
          data: {
            title: args.title,
            author: {
              connect: { id: args.userId },
            },
          },
        },
        info,
      )
    },
    publish(parent, args, context, info) {
      return context.db.mutation.updatePost(
        {
          where: { id: args.postId },
          data: { published: true },
        },
        info,
      )
    },
    createUser(parent, args, context, info) {
      return context.db.mutation.createUser(
        {
          data: { name: args.name },
        },
        info,
      )
    },
  },
}
Copy

Each resolver simply delegates incoming requests to the Prisma binding object which is called db and attached to the resolvers' context.

Configure your GraphQL server

Now you need to instantiate the GraphQLServer from the graphql-yoga library and pass the application schema along with its resolver functions. You're also instantiating the Prisma binding object and attach it to the context so that the resolvers can access it; again the __YOUR__PRISMA_ENDPOINT__-placeholder needs to be replaced with your acual endpoint:

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  context: req => ({
    ...req,
    db: new Prisma({
      typeDefs: ‘prisma.graphql’,
      endpoint: '__YOUR__PRISMA_ENDPOINT__',
    }),
  }),
})
server.start(() => console.log('Server is running on http://localhost:4000'))
Copy

Launch the GraphQL server

To start the GraphQL server (of the application layer) run the following command:

node index.js
Copy

Explore the GraphQL API of the application layer in a Playground

The GraphQL API of your application layer now exposes the six operations defined in schema.graphql. To test these operations, navigate your browser to http://localhost:4000 where the GraphQL server is running.

Here are a few sample queries and mutations you can send to explore the API.

Create a new User
Create new draft
Publish a Post
Fetch published Posts
mutation {
  createUser(name: "Jenny") {
    id
  }
}
Copy

Best practices for your GraphQL server

Here are some hints for structuring your project:

  • Include the directory that contains the service configuration files for your Prisma service (in your case that's the hello-world directory) inside the project directory of the GraphQL server.
  • The GraphQL schema of your Prisma API (called prisma.graphql) should be available in the directory where the source code for your GraphQL server is located. As it's auto-generated, it is helpful to put it into a dedicated directory, e.g. called generated.
  • Use graphql-config to enable the GraphQL Playground to show the two GraphQL APIs (Prisma and application server) side-by-side.

Here's how your project structure will look like if you follow above:

.
├── .graphqlconfig
# defines the Prisma service (database layer)
├── hello-world
│   ├── datamodel.graphql
│   └── prisma.yml
# implementation of the GraphQL server (application layer)
├── src
│   ├── generated
│   │   └── prisma.graphql
│   ├── index.js
│   └── schema.graphql
├── package.json
└── yarn.lock

Your .graphqlconfig.yml file needs to define both GraphQL projects you're working with:

projects:
  app:
    schemaPath: src/schema.graphql
    extensions:
      endpoints:
        default: http://localhost:4000
  hello-world:
    schemaPath: src/generated/prisma.graphql
    extensions:
      prisma: hello-world/prisma.yml

This allows to quickly switch between the two GraphQL APIs using the sidenav inside the GraphQL Playground. Note that for this to work you need to open the Playground using the graphql playground command (from the GraphQL CLI) inside the same directory where your .graphqlconfig is located.

Prisma's auto-generated GraphQL schema changes whenever you deploy changes to the service's data model. To ensure your local prisma.graphql stays up-to-date you can configure a post-deployment hook which updates it after every deploy.

You can configure the hook in prisma.yml:

datamodel: datamodel.graphql
endpoint: http://localhost:4466 # or some other endpoint

hooks:
  post-deploy:
    - graphql get-schema --endpoint ${self:endpoint} --output src/generated/prisma.graphql --no-all

This assumes that the GraphQL CLI is installed globally on your machine.

Congratulations! 🚀 You made it through the quickstart tutorial and learned how to use Prisma and Prisma bindings to build a GraphQL server.
Next Step