I'm new to graphql, but I find a lot of my queries are very long and repetitive, and being able to interpolate repeated sections would make my code a lot easier to read and update.
Here's one section of graphql I have on one of my templates:
# SUBNAV PROPERTIES - CATEGORY
overviewNavTitle
categorySlug: slug
subcategories {
description: navDescription
id
slug
title: navTitle
}
# SUBNAV PROPERTIES - NESTED ARTICLE
parentCategory: contentpage {
categoryTitle: navTitle
categoryDescription: navDescription
overviewNavTitle
categorySlug: slug
subcategories {
description: navDescription
id
slug
title: navTitle
}
}
I wish I could write it like this:
# SUBNAV PROPERTIES - CATEGORY
${commonNavProps}
# SUBNAV PROPERTIES - NESTED ARTICLE
parentCategory: contentpage {
categoryTitle: navTitle
categoryDescription: navDescription
${commonNavProps}
}
But I get an error triggered by this code: https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/babel-plugin-extract-graphql.js#L10
This code does _not_ run on queries in my gatsby-node file, so I've been taking advantage of interpolation there and it's made things a lot easier.
I tried to look into a solution for this myself, but I'm a bit out of my element dealing with babel ASTs, so I thought I'd pause and see:
gatsby-node and send the results to my templates using templateContext, but that feels wrong 馃槙 It sounds like you're looking for the GraphQL concept of fragments: http://graphql.org/learn/queries/#fragments. Gatsby doesn't support variable names in GraphQL queries as explained here: https://github.com/gatsbyjs/gatsby/issues/2293
Thanks @calcsam. I had tried those before (and I'm using inline fragments elsewhere) but I guess I had the formatting wrong because I couldn't get them to work. Your comment inspired me to try them again and now I have it working. Fragments are more flexible than I thought. I guess that solves the issue!
@sarahatwork how did you get them to work? Do you add them to an external graphql file and import them or so? Any hints would be appreciated ;)
Put them wherever it makes sense e.g. in the same page or in a component. Fragments are in a global namespace so you don't have to import them explicitly.
They do need to be in a js file though. We don't support .graphql files atm.
Yeah in my case it wound up being:
export const pageQuery = graphql`
fragment commonNavProps on ContentfulContentPage {
overviewNavTitle
categorySlug: slug
subcategories {
description: navDescription
id
slug
title: navTitle
}
}
query contentPageQuery($id: String!) {
contentfulContentPage(id: { eq: $id }) {
# SUBNAV PROPERTIES - CATEGORY
...commonNavProps
# SUBNAV PROPERTIES - NESTED ARTICLE
parentCategory: contentpage {
categoryTitle: navTitle
categoryDescription: navDescription
...commonNavProps
}
}
`;
Still can't do everything I want, like a fragment containing inline fragments, but still reducing some repetition.
Ah thank you both! I was confused by the syntax, I tried to declare them without template strings so no wonder it didn't work. Graphql was already nice but this is wonderful!
I'm looking for a more general use case: interpolating the same query in different places. For example, the Sourcing from Ghost example could be fleshed out to output a list of posts with the title linking to the slug. That needs a page with another allGhostPost GraphQL query for the set of posts, repeating the query from gatsby-node.js and only adding the title field.
If interpolation in the graphql tag worked, one could write a single query for both, returning the slug and title. In gatsby-node.js, the title would be ignored, but it would be used when creating the lists of posts.
Most helpful comment
Thanks @calcsam. I had tried those before (and I'm using inline fragments elsewhere) but I guess I had the formatting wrong because I couldn't get them to work. Your comment inspired me to try them again and now I have it working. Fragments are more flexible than I thought. I guess that solves the issue!