GraphQL Recursive Query with Fragments

July 28th 2020

We recently ran into a scenario where we wanted to create a GraphQL query that could recursively call children of a definition type. The use case was for a hierarchy of product categories on our site rustic.com where a category can be a parent and have children, and the children could have children etc. We discovered that GraphQL does not allow for recursive calls as per the specs.

It’s not possible to write a recursive query of unlimited depth. 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.

https://spec.graphql.org/

So how does one recursively call a GraphQL query if the query object is hierarchal and contains children? We do have to “plan” how deep our query will go but we can save ourselves a lot of time by using GraphQL Fragments. Fragments allow you to construct sets of repeatable fields, and then include them in queries where you need to.

GraphQL Fragments for Recursive Query

As per our example we have a GraphQL object definition called Category and our category object can have children categories and those children could have children. As an example we could have:

Furniture
|__ Dining Room
|  |__ Dining Tables
|__ Living Room
   |__ Coffee Tables

As you can see our Furniture category is the parent and has children (Dining Room and Living Room) and those each have children. Here is the GraphQL type definition for our Category object:

type Category {
  id: ID!
  _id: ID!
  createdAt: DateTime!
  updatedAt: DateTime!
  name: String
  slug: String
  parent: Category
  products(sort: String, limit: Int, start: Int, where: JSON): [Product]
  subcategories(sort: String, limit: Int, start: Int, where: JSON): [Category]
}

You can see that our relationship to our children is in a field called subcategories and this will be important later when creating our recursive fragment. You will need to make sure that your child field name is replaced by subcategories.

First, we will define the fields that we want each category (and subcategories) to return. We’ll create a Fragment called SubcategoryFields:

fragment SubcategoryFields on Category {
  id
  name
  slug
  products {
    id
    slug
    name
  }
}

In this fragment we’re getting our fields needed for each category. You can call this fragment whatever name makes sense for your type definitions. For example, if you are trying to get hierarchal comments you could name this CommentFields. Now with the Fields fragment in place we can turn our attention to the recursive fragment definition. In our example we know that we need to go at least three levels deep with a recursive call (Furniture > Dining Room > Dining Tables) so we’re going to create another fragment to handle this query definition:

fragment CategoriesRecursive on Category {
  subcategories {
    ...SubcategoryFields
    subcategories {
      ...SubcategoryFields
      subcategories {
        ...SubcategoryFields
      }
    }
  }
}

As you can see we’re spreading our SubcategoryFields fragment so we don’t have to redundantly keep typing in the subcategory fields. This saves a lot of time and code space and if you want to add (or remove) a field you only have to do it in the SubcategoryFields fragment. Finally, we want to make our query definition to get our categories:

query ALL_CATEGORIES {
  categories {
    ...SubcategoryFields
    ...CategoriesRecursive 
  }
}

Since our SubcategoryFields are the same as our Category fields we can use our fragment again to spread all of the fields we need. Then we are going to spread the CategoriesRecursive field which includes all of our SubcategoryFields definitions. Now if you need to add another level deep all you would need to do is modify your CategoriesRecursive fragment to include another SubcategoryFields fragment.

Hopefully this helps solve your Recursive GraphQL Query needs and you can implement these fragments into your next project!