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