Write your graph's resolvers

So far, we can say our API is useful yet. Though we can inspect our graph's schema, but we can't still run queries on it. Since our schema and data sources are complete, it's time to take on our resolvers to trigger business logic and/or to fetch and/or update data.

But what is a resolver?

Resolvers provide the instructions for turning a GraphQL operation (a query, mutation, or subscription) into data. They either return the same type of data we specify in our schema or a promise for that data.

To be write resolvers, we need to learn more about what a resolver function looks like, and the arguments they accept.

A typical resolver looks like this:

fieldName: (parent, args, context, info) => data;
  • parent: An object that contains the result returned from the resolver on the parent type
  • args: An object that contains the arguments passed to the field
  • context: An object shared by all resolvers in a GraphQL operation. We use the context to contain per-request state such as authentication information and access our data sources.
  • info: Information about the execution state of the operation which should only be used in advanced cases

Remember the LaunchAPI and UserAPI data sources we created in the previous section and passed to the context property of ApolloServer? We're going to call them in our resolvers by accessing the context argument.

No doubt, it will absolutely sound crazy at first, but a little patience as we go on, it will start making sense. Let's get started

Connecting resolvers to Apollo Server

First, we connect our resolver map to Apollo Server. Right now, it's just an empty object, but we will still add it to our ApolloServer instance, so we don't have to do it later. To do this Navigate to src/index.js and add the following code to the file:

// src/index.js
const {ApolloServer} = require('apollo-server');
const typeDefs = require('./schema');
const {createStore} = require('./utils');
const resolvers = require('./resolvers');
const LaunchAPI = require('./datasources/launch');
const UserAPI = require('./datasources/user');
const store = createStore();
const server = new ApolloServer({
    typeDefs, resolvers,  dataSources: () => ({
    launchAPI: new LaunchAPI(),
    userAPI: new UserAPI({ store })

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);

Automatically, Apollo Server will add the launchAPI and userAPI to our resolvers' context so we can easily call them.

Write Query resolvers

First, let's start by writing our resolvers for the launches, launch, and me fields on our Query type. We structure our resolvers into a map where the keys correspond to the types and fields in our schema. If you ever get stuck remembering which fields are on a type, you can always check your graph API's schema.

Navigate to src/resolvers.js and paste the code below into the file:

module.exports = {
  Query: {
    launches: (_, __, {dataSources}) =>
    launch: (_, {id}, {dataSources}) =>
      dataSources.launchAPI.getLaunchById({ launchId: id }),
    me: (_, __, {dataSources}) => dataSources.userAPI.findOrCreateUser()

The code above shows the resolver functions for the Query type fields: launches, launch, and me. The first argument to our top-level resolvers, parent, is always blank because it refers to the root of our graph. The second argument refers to any arguments passed into our query, which we use in our launch query to fetch a launch by its id. Finally, we destructure our data sources from the third argument, context, in order to call them in our resolvers.

The resolvers we just wrote follows the resolver pattern we described in the introduction of resolvers in the early part of this tutorial.

Our resolvers are simple and concise because the logic is embedded in the LaunchAPI and UserAPI data sources. We recommend keeping your resolvers thin as a best practice, which allows you to safely refactor without worrying about breaking your API.

Our resolvers are ready and queries can now be ran. These queries will return all the records in the db, which will make application slow.

In the next tutorial we will write paginated queries and update our resolvers to return these paginated values.

Previous: Connect a database
Next: Paginated queries