Gatsby: [Discussion] Allow substitution in graphql string templates

Created on 12 Dec 2017  路  8Comments  路  Source: gatsbyjs/gatsby

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:

  • Is this something other people are interested in? (Maybe even people who know how to fix the issue?)
  • Is there a way to get around the problem? My best idea so far is to do more of my queries in gatsby-node and send the results to my templates using templateContext, but that feels wrong 馃槙

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!

All 8 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

totsteps picture totsteps  路  3Comments

3CordGuy picture 3CordGuy  路  3Comments

benstr picture benstr  路  3Comments

dustinhorton picture dustinhorton  路  3Comments

dustinhorton picture dustinhorton  路  3Comments