Implementing the createResolvers API

In the course of schema customization, sometimes type definitions are insufficient for requirements in Gatsby sites. For example, the GraphQL SDL and Gatsby Type Builders can handle the vast majority of use cases when it comes to adding type definitions, but more granularity is occasionally necessary in the form of custom resolvers, which allow us to specify how fields should be resolved in the GraphQL schema. This is done through implementations of the createResolvers Node API:

// gatsby-node.js
exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    Frontmatter: {
      author: {
        resolve(source, args, context, info) {
          return context.nodeModel.getNodeById({
            id: source.author,
            type: "AuthorJson",
          })
        },
      },
    },
  }
  createResolvers(resolvers)
}

Implementations of the createResolvers API enable Gatsby developers to extend types with new fields without overriding the field type. Since the createResolvers function is executed near the end of the schema generation process, modification of an existing field type would require the regeneration of input types (fieldsort, etc.), which would be an expensive operation. For this reason, specifying field types is best handled in implementations of the createTypes action, unless you have more advanced requirements.

While implementing the createResolvers API, Gatsby permits access to the internal data store and Gatsby’s own query capabilities through the context.nodeModel object that is made available in each resolver. In this manner, Gatsby developers can directly access nodes by their identifiers by invoking getNodeById and getNodesByIds, whereas all nodes can be retrieved through getAllNodes. You can also issue arbitrary queries from within resolver function logic through runQuery, which allows for filter and sort query arguments.

For example, the following createResolvers implementation extends the AuthorJson type with a field that lists all recent articles written by a particular author:

// gatsby-node.js
exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    AuthorJson: {
      recentPosts: {
        type: ["MarkdownRemark"],
        resolve(source, args, context, info) {
          return context.nodeModel.runQuery({
            query: {
              filter: {
                frontmatter: {
                  author: { eq: source.email },
                  date: { gt: "2019-01-01" },
                },
              },
            },
            type: "MarkdownRemark",
            firstOnly: false,
          })
        },
      },
    },
  }
  createResolvers(resolvers)
}

If invoking runQuery from within the API implementation to sort results of the query, note that sort.fields and sort.order are both GraphQLList fields. Meanwhile, nested fields within sort.fields are accessed through dot notation rather than triple underscores, as we’ve seen in previous examples:

// gatsby-node.js
// ...
return context.nodeModel.runQuery({
  query: {
    sort: {
      fields: ["frontmatter.date"],
      order: ["DESC"],
    },
  },
  type: "MarkdownRemark",
})
// ...
NOTE

A powerful feature available in the createResolvers API that is beyond the scope of this overview of schema customization is custom query fields. For more information about these, consult the Gatsby documentation.


Posted

in

,

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *