site logo
LIAM AXON

Custom GraphQL Schemata for Gatsby and Date Formatting

Nov 8, 2021
tags: coding, gatsbyjs, graphql

I love how Gatsby integrates GraphQL in ways that make it easier for developers to develop. One of these great features is how Gatsby and Gatsby plugins automatically detect data fields and data types for your GraphQL queries. This allows you, the developer, to not worry about how data is processed by your GraphQL queries. For example, when including frontmatter from a Markdown or MDX page, Gatsby will automatically generate a schema for your frontmatter that may look something like this.

type {
title: String
author: String
slug: String
date: Date
}

This implicit type creation works great most of the time, but it can lead to problems. For example, my frontmatter also includes an optional draft parameter to specify that a MDX file should not be made into a page. This means that sometimes I have blog posts with a draft parameter, and sometimes I don't. My GraphQL queries to my MDX pages look something like the following:

... {
frontmatter {
title
author
slug
date
draft
}
}

When I don't have any drafts, this query causes GraphQL to raise an error since the (automatically generated) data type for frontmatter doesn't include a draft parameter.

Luckily, Gatsby provides a way for developers to specify their own data types with the createSchemaCustomization function. To specify the data type for MDX frontmatter processed by gatsby-plugin-mdx, include the following code in your gatsby-node.js file.

// create GraphQL schema, to be used within the website:
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
createTypes(`
type MdxFrontmatter {
title: String!
author: String!
slug: String!
date: Date
draft: Boolean
}
`);
};

Let's break this down a bit. The above code runs before any GraphQL queries are made (and before plugins like gatsby-plugin-mdx automatically generate data types). The createTypes function takes here a string parameter which is written in the GraphQL Schema Language, but it can take other inputs as well. It modifies one type, MdxFrontmatter. This type is used by gatsby-plugin-mdx when it processes the frontmatter of MDX files. Here, we define the page's frontmatter type. By adding an exclamation mark to a property, as in title: String!, we are telling GraphQL that this property can not be null. This is handy, for example, for fields that must be included in frontmatter.

There is one last problem that we need to deal with. Gatsby includes nice formatting functions for dates that can be called within a GraphQL query. I use the formatString function to receive dates in nice format, as in the following partial query. I could also process the date directly in Javascript, but this way everything is processed in build-time, which I like.

... {
frontmatter {
title
author
slug
date(formatString: "D MMMM, YYYY")
draft
}
}

When I defined the fields of MdxFrontmatter, this code broke! It turns out that when I defined the type of the date field in MdxFrontmatter, it lost all of its nice functions. That is, GraphQL no longer knows how to process functions like formatString. To fix this, we need to add an interface to the date field. These kinds of interfaces are called resolvers.

// create GraphQL schema, to be used within the website:
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
createTypes(`
type MdxFrontmatter {
title: String!
author: String!
slug: String!
date: Date @dateformat
draft: Boolean
}
`);
};

Note the @dateformat after date: Date, informing GraphQL how to respond to functions like formatString. Now, finally, everything works! I found this solution to date formatting in this Gatsby blog post, which is also a neat resource for learning more about cool features of GraphQL and Gatsby.