< Home

How to get more from your GraphQL data in Gatsby

A guide for Gatsby on how to get more out of your GraphQL data.

December 06, 2021 (Updated on January 10, 2022)

Introduction

Recently, I decided to add reading times to the blog, and while that in itself wasn't a huge challenge, doing it in an SSG-friendly way was. In previous iterations of blogs and websites, I've done this calculation on the page itself, although this introduces a problem. The reading-time calculation would be ran every time the page is opened, which for a small slice of text is quite unnecessary and resource-intensive.

Thankfully, since the data for the blogs is coming from an external source (Contentful in my case), we can make use of Gatsby's GraphQL layer to serve the reading time information on build time, rather than run-time.

Introducing the Field Extension 🚀

Within Gatsby's GraphQL pipeline, we can modify the data belonging to an existing node, and add additional data alongside it. This could be anything, such as combining names or calculating word counts, in my case it was getting the reading times of blog posts.

First, we use the createSchemaCustomization function to indicate we want to add additional information to the GraphQL schema:

exports.createSchemaCustomization = ({ actions, schema }) => {

}

Next, we'll need to extend the GraphQL node of our choice with some data by using the createFieldExtension function. I used the marked NPM package to parse the markdown coming from the CMS, and the reading-time NPM package to estimate the length of the content.

exports.createSchemaCustomization = ({ actions, schema }) => {
    const { createFieldExtension } = actions;

    createFieldExtension({
        name: 'readingTime',
        extend() {
            return {
                resolve(source) {
                    return readingTime(marked(source.copy)).text;
                },
            };
        },
    });
};

The blog content is coming from the source vaiable in the resolve function. This will vary depending on the node you're extending, in my case all of the markdown content was in a field called copy.

Next we need to assign this extended data to a node, so Gatsby knows where in the GraphQL tree to place it. To do this, we use the createTypes function, and pass it the GraphQL node type we want to extend, with the new field assigned to it. For me, the node was called contentfulPageBlogPostCopyTextNode, which I found in the GraphQL explorer.

exports.createSchemaCustomization = ({ actions, schema }) => {
    const { createFieldExtension, createTypes } = actions;

    createFieldExtension({
        name: 'readingTime',
        extend() {
            return {
                resolve(source) {
                    return readingTime(marked(source.copy)).text;
                },
            };
        },
    });

    createTypes(`
        type contentfulPageBlogPostCopyTextNode implements Node {
            readingTime: String @readingTime   
        }
    `);
};

Finally, we can query for the new field on the node it's been assigned to.

{
  contentfulPageBlogPost {
    copy {
      readingTime
    }
  }
}

Conclusion

And that's it! You can do this with nearly all queryable data, and all of the data processing happens during build time, rather than on load 🎉 .

Related Posts

Hello World!

Hello World!

Hello World! A brief introduction to the blog, what I'm planning, and more.

Building a Design System; 👍's & 👎's

Building a Design System; 👍's & 👎's

What you should and shouldn't do when building a design system, from theming, to styling, to component structure and testing.

Code Snippets - React Hooks

Code Snippets - React Hooks

A selection of React utility hooks I've put together over the years.