Previously, we covered how seemingly innocuous queries can prevent your themes from being composable when used with other themes and even sites you didn't plan for. In this post, we'll cover the core issue a bit more directly.
To refresh your memory, we explored a query for
and a similar query for
File nodes, shown here.
The core problem with both of these queries is that we have
a conceptual content type that these represent (
AuthorBio, etc) and we're querying a format
Mdx) or a source (
File) and not a content type
Mdx is how our files are written while
File is where our files come from. Neither accurately
represents a conceptual content type accurately, ie: what
the content means to us.
So to start, we need to create a new type in the GraphQL
BlogPost. To do this, we'll use the
sourceNodes lifecycle method and the
APIs. Specifically we're using
buildObjectType to create a
new type with a set of resolvers at the same time.
Most of our fields have no resolvers defined because they can be infered by Gatsby itself. There are roughly two types of fields here:
For the second type of field we need to pass through our
resolver to the source type's resolver to get the final
value (note: this resolver code will be simplified by
additional future Gatsby APIs). We take this approach for
So now we have our
BlogPost type, but we still need some
nodes using that type. To do this, we'll use some
createNode calls that translates fairly
directly from MDX frontmatter to
BlogPost fields. We only
want to create
BlogPost nodes from
Mdx nodes with
parents from the
posts filesystem source in this case. We
could, in the future, source
BlogPosts from different
places as well.
Once we've done this, the following query will always work
regardless of if we have any
BlogPosts in the node system.
Note that even though we haven't coded any explicit support
for filtering or sorting, we can still use them because
Gatsby handles that for us.
Note also that because we created a parent/child
relationship for the
BlogPost nodes, we can reach up into
any of the parents to access interesting information, so no
user of our theme will be overly restricted if they want to
do something outside of the 80% use case.
With no posts, the result is:
With results, we get the following instead (note: I've removed the body value for brevity as it can get quite long).
Now we've gotten ourselves to a point where we can use a
BlogPost type instead of
Mdx, simplifying our code base
and also ensuring that when users of our theme want to query
for blog posts on their pages, they don't have to worry
about filtering all of the other