Building GraphQL Resolvers

Figuring out how to make GraphQL resolvers is tricky when you get past the basic static routes. Here's a straight forward tutorial that goes over creating resolvers.

Prerequisite

The previous tutorials cover what GraphQL is and how to implement it in an express server. In this tutorial, we will try to establish how GrpahQL uses resolvers to fill data in a request and how to write the resolvers.

Setting up the Schema

Building a modular schema is fundamental to building a good API. The first step in building a good schema is knowing what the data you want to get out looks like. Here we will want to be able to make three types of queries, the first being pulling information about a book. The second and third are filtering books by authors and getting all of the books we have in the database. We will be using the following JSON object as our "database".

 1// Some dummy data
 2const books = [
 3  {
 4    id: 1,
 5    title: 'The Great Gatsby',
 6    author: 'F. Scott Fitzgerald',
 7  },
 8  {
 9    id: 2,
10    title: 'To Kill a Mockingbird',
11    author: 'Harper Lee',
12  },
13  {
14    id: 3,
15    title: '1984',
16    author: 'George Orwell',
17  },
18];

Before building the Query object let's define what a book looks like so we are able to return the books as a result. Our book object Book will match the shape of the array items in the database, having an id, title, and author like below.

1type Book {
2    id: Int
3    title: String
4    author: String
5 }

For the Query object we will define which routes we want to make available and what data the resolvers will need to function. The book route is the route that can get a book by its id. The exclamation point after the Int for the id argument tells GraphQL that a parameter is required. The book route then returns a Book object which is the same object defined above. The next route is the books route, which takes the author of the book and filters out any non-matching books. As you can see this parameter is required also. The last route we will have is the all route which can return our entire database to the client. The brackets around Book tells GraphQL that the response should be an array of Book objects.

1type Query {
2    book(id: Int!): Book
3    books(author: String!): [Book]
4    all: [Book]
5  }

Where to put this at?

Up to this point, the code examples have not been "full" code examples. When it comes to building the schema for your API you need to put these objects inside of the buildSchema function.

 1// Construct a schema using GraphQL schema language
 2const schema = buildSchema(`
 3type Query {
 4  book(id: Int!): Book
 5  books(author: String!): [Book]
 6  all: [Book]
 7}
 8
 9type Book {
10  id: Int
11  title: String
12  author: String
13}
14`);

Building the Resolvers

Resolvers act as the keys in the query, to better understand this here is a GraphQL query.

1{
2  book(id: 3) {
3    title
4  }
5}

This query is asking to get data from the book function and passes id as a parameter with a value of one to it. Then it takes the response of the book function and extracts the title parameter from it then returns the data.

To build a resolver start with an new object, typically this is called root, and add the functions you laid out in the previous steps like below.

1// Define the resolvers
2const root = {
3  book: ({ id }) => books.find((book) => book.id === id),
4  books: ({ author }) => books.filter((book) => book.author === author),
5  all: () => books
6};

The root object contains the book function that takes the book id as a parameter and then finds the correct book entree to send back. To extract data from the returned object in a resolver you don't have to add a thing. GraphQL automatically handles the extraction of data. For example, now that we have resolvers defined, we can pass the query above and it would return then following:

1{
2  "data": {
3    "book": {
4      "title": "1984"
5    }
6  }
7}

Full Code Example

 1import express from "express";
 2import { graphqlHTTP } from 'express-graphql';
 3import { buildSchema } from 'graphql';
 4
 5// Construct a schema using GraphQL schema language
 6const schema = buildSchema(`
 7  type Query {
 8    book(id: Int!): Book
 9    books(author: String!): [Book]
10    all: [Book]
11  }
12
13  type Book {
14    id: Int
15    title: String
16    author: String
17  }
18`);
19
20// Some dummy data
21const books = [
22  {
23    id: 1,
24    title: 'The Great Gatsby',
25    author: 'F. Scott Fitzgerald',
26  },
27  {
28    id: 2,
29    title: 'To Kill a Mockingbird',
30    author: 'Harper Lee',
31  },
32  {
33    id: 3,
34    title: '1984',
35    author: 'George Orwell',
36  },
37];
38
39// Define the resolvers
40const root = {
41  book: ({ id }) => books.find((book) => book.id === id),
42  books: ({ author }) => books.filter((book) => book.author === author),
43  all: () => books
44};
45
46// Create an express server and a GraphQL endpoint
47const app = express();
48app.use(
49  '/graphql',
50  graphqlHTTP({
51    schema: schema,
52    rootValue: root,
53    graphiql: true,
54  })
55);
56
57// Start the server
58app.listen(4000, () => console.log('Express GraphQL Server Now Running On localhost:4000/graphql'));