Gatsby: GraphQL doesn't support recursive data

Created on 12 Jun 2018  Â·  9Comments  Â·  Source: gatsbyjs/gatsby

Summary

GraphQL being the method for data hydration in Gatsby can cause issues for recursive data. GraphQL explicitly does not support recursive data:

The graph of fragment spreads must not form any cycles including spreading itself. Otherwise an operation could infinitely spread or infinitely execute on cycles in the underlying data.

Some CMSs, such as Contentful, allow arbitrarily deep data structures that can nest the same content types within themselves:

{
  "contentType": "Container",
  "heading": "Example",
  "references": [
    {
      "contentType": "Container",
      "heading": "Example 1",
      "references": []
    },
    {
      "contentType": "Container",
      "heading": "Example 2",
      "references": []
    }
  ]
}

This depends on your components being intelligent enough to decide how to handle generating children. While this is doable from a React perspective via dynamically generated components, it isn't currently possible with GraphQL.

Questions/Proposed Solutions

  • Is it a viable solution to make GraphQL an optional part of Gatsby, allowing hydration of data to occur separately?
stale? question or discussion

Most helpful comment

I have the same needs.
I want to generate pages with Gatsby by fetching page data from Contentful.
This data contains references to other pages, thus creating potentially infinite links. Emphasis on "potentially" here. In practical terms, I only go 6 or 7 level deep.

I would love to be able to use GraphQL for this without having a nested query of hell.

All 9 comments

I have the same needs.
I want to generate pages with Gatsby by fetching page data from Contentful.
This data contains references to other pages, thus creating potentially infinite links. Emphasis on "potentially" here. In practical terms, I only go 6 or 7 level deep.

I would love to be able to use GraphQL for this without having a nested query of hell.

Is it possible to restrict recursion in Contentful? It sounds like that could cause plenty of problems just in general site building even beyond making things work in GraphQL. /cc @Khaledgarbaya

GraphQL doesn't allow you to query things that aren't known at query time.

I'd suggest discussing with content folks about what a reasonable limit for recursion is. You can then query up to that limit with GraphQL just fine.

@KyleAMathews you can restrict the Content Models to only accept certain data, etc., but I'm not sure you can restrict the levels of recursion.

I think for the most most of my use case a refactor of the models themselves could make it work, by flattening them out or simply predicting inside the query itself how many levels deep you need to pull from. However, as @dotlouis mentions, even with guessing the depth, you still get into nested query hell pretty quickly.

Personally, I'd prefer to have direct access to the data coming into each page, rather than having to query for it. It'd be nice for GraphQL to be opt-in. How challenging do you think this is?

Personally, I'd prefer to have direct access to the data coming into each page

Gatsby doesn't believe there's any inherent connection between data and pages — that's the point of the query — to decide what data comes onto the page. E.g. how would you know that object x is connected to y and z? Which relations to follow? Which ones you shouldn't? Without some sort of query, you'd either underfetch (meaning you'd have to introspect on data and then query for more data) or overfetch getting way more data than you want.

It'd be nice for GraphQL to be opt-in.

GraphQL is an integral part of Gatsby so it won't be opt-in — at least for the server side rendering bit. You can fetch whatever you'd like client-side of course.

Hey @jreidgreer @KyleAMathews, the nature of Contentful allows you to make circular references.
But I personally don't recommend that and most of the time you can refactor your content model to have a simpler structure.
~@jreidgreer can you share more details about your content model?~

@jreidgreer An alternative content modeling can be

// Container Entry
{
  "contentType": "Container",
  "heading": "Example"
}
// ContainerReferences Entry
{
   slug: 'container1'
   container: {
       "contentType": "Container"
        "heading": "Example 1"
   },
  references: [
     {
      "contentType": "Container",
      "heading": "Example 2",
      "references": []
    }
  ]
}

and in your Gatsby page you run 2 queries (This is not tested by you can get the idea)

export const pageQuery = graphql`
   query containerQuery($slug: String!) {
    contentfulContainer(slug: { eq: $slug }) {
      edges {
        node {
          heading
        }
      }
    }
   allContentfulContainer(slug: { eq: $slug }) {
      edges {
        node {
          container { 
            heading
          }
          references {
             ... on Container {
                   heading
             }
          }
        }
      }
    }
  }
`;

What I ultimately settled to do was to query the array of all my pages (flat) and then constructed the tree myself in Javascript using Id references and recursion.

Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!

This issue is being closed due to inactivity. Is this a mistake? Please re-open this issue or create a new issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andykais picture andykais  Â·  3Comments

ferMartz picture ferMartz  Â·  3Comments

theduke picture theduke  Â·  3Comments

KyleAMathews picture KyleAMathews  Â·  3Comments

dustinhorton picture dustinhorton  Â·  3Comments