Custom GraphQL Schemata for Gatsby and Date Formatting
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: Stringauthor: Stringslug: Stringdate: 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 {titleauthorslugdatedraft}}
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: Datedraft: 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 {titleauthorslugdate(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 @dateformatdraft: 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.