DRY Up Your Code with GraphQL Fragments

Sarah Sweat
Level Up Coding
Published in
4 min readJun 11, 2019

--

Photo by Katy Cao on Unsplash

I have been learning about using GraphQL and Apollo in my React applications. This blog post is going to assume you have a basic understanding of both technologies and will specifically address using GraphQL fragments in queries defined using Apollo. If you want to learn more about using Apollo and GraphQL with React, I have links to documentation at the end of the article.

My problem

For my app, I was want to allow users to find recipes in two ways. 1) Supplying a search term and showing a limit of 50 results that were related to the term, and also allow for paging through results if necessary. 2) Allow users to search for a specific recipe by a unique ID and only return the single result. I no longer needed to account for limiting, paging, etc.

In both cases I wanted to receive the same type of result per recipe. A recipe object returned from both queries should have the same attributes, such as id, title, image, bylines, etc.

Check out the code below and see the two queries I was using to accomplish this:

Use case 1:

Use case 2:

As I am sure you noticed, there are several repeated lines here. All of the attributes on a Recipe have been repeated between the two queries. If only there were a way to clean this up and reduce the amount of code I needed to write………..

My Solution

In order to write the query attributes once, we can use an Apollo/GraphQL Fragment which can be reused in multiple queries.

At its most simple definition:

“A GraphQL fragment is a shared piece of query logic.” — Apollo documentation (referencing the base GraphQL concept. )

Also according to the Apollo documentation, there are two principal uses for fragments in Apollo:

  • Sharing fields between multiple queries, mutations, or subscriptions.
  • Breaking your queries up to allow you to co-locate field access with the places they are used.

In my case, I am more concerned with the first point, and that’s what I will address here to clean up these two recipe queries.

First, lets define our fragment.

You can see on line 1 that I am importing the gql tag from apollo-boost so that I can write my query in React more easily. Then I define a constant in which I am defining the fragment. The name RECIPE_ATTRIBUTES is referring to this segment of gql code so that we can bring it into our other queries later. This is not the fragment itself, just the container for some gql code.

The snippet of code within our tag is using the fragment key word to define the actual section of code we want to reuse. In this case I have named my fragment recipeAttributes. I put on Recipe after this declaration because that is the type to which these attributes belong.

Now that I have my fragment defined, I need to add it to my queries and replace the duplicate code:

That just got so much shorter! I brought in my RECIPE_ATTRIBUTES constant which I had previously defined and interpolated it after the query but still within the gql tag. I then was able to reference the fragment that I had defined as recipeAttributes within my existing query.

This leaves me with my final code:

To recap, we just wrote a GraphQL fragment in our Apollo gql tag in order to encapsulate and reuse the definition of how we want our recipes to be returned to us. This helps us to enforce the Single Responsibility Principe(SRP). Quick recap on SRP:

“The Single Responsibility Principle (SRP) is one of the five so-called SOLID principles, developed and promoted by Robert C. Martin to help developers produce flexible and maintainable code. In short, the SRP says that a given module or class should have responsible for a single element of a program’s functionality, and thus have just a single reason to change.” — Severin Perez

This also helped us to have a single source of truth for recipes returned to our front end through GraphQL. We have defined the expected recipe attributes in one place.

Not only do we have a separate variable to hold our query vs our recipe definition and have the structure of recipe result defined in a single place, but also we have reduced the quantity and complexity of our code! Win win!

Hope this helps you as much as it did me!

--

--