Blog

Componentize data with GraphQL Fragments

GraphQL offers fragments - reusable units of logic that can be shared between multiple queries and mutations. By separating GraphQL fragments into separate files you can fully componentize your data and bundle them with your React or Vue (or any other flavour) components.

GraphQL fragments: reusable units

The easiest way to explain GraphQL fragments is with a quick example. When you have repeating logic, like the image in this query:

query {
  posts {
    title
    image {
      alt, src, width, height, filetype, base64
    }
    authors {
      name
      image {
        alt, src, width, height, filetype, base64
      }
    }
  }
}

You can turn that repeating image logic into a fragment:

query Blog {
  posts {
    title
    image { ...imageFragment }
    authors {
      name
      image { ...imageFragment }
    }
  }
}

fragment imageFragment on Image {
  alt
  src
  width
  height
  filetype
  base64
}

This makes the image logic more reusable within this file. But what if we want to use this fragment in other files? And how can you bundle fragments with other component files?

Fragment files for component data

We can move our GraphQL fragments to their own files and (with the help of a bit of tooling) import them where we need. As a convention we use a .fragment.graphql extension for our fragments and .query.graphql for files containing our GraphQL queries. This allows us to bundle our GraphQL fragments with components and put queries along our pages (or routes). In a typical React or Vue flavoured project our file structure looks something like this:

components/
  Image.(jsx|vue)
  Image.fragment.graphql

pages/
  Blog.(jsx|vue)
  Blog.query.graphql

Where Image.fragment.graphql:

fragment imageFragment on Image {
  alt
  src
  width
  height
  filetype
  base64
}

And Blog.query.graphql:

#import '../components/Image.fragment.graphql'

query Blog($locale: SiteLocale) {
  posts {
    title
    image { ...imageFragment }
    authors {
      name
      image { ...imageFragment }
    }
  }
}

The result is a clear and maintainable setup using GraphQL in our project.

Importing GraphQL files

As noted earlier, being able to import our GraphQL fragments into other GraphQL files does require a bit of tooling. The #import '…/Image.fragment.graphql' syntax above is not built-in GraphQL syntax. The GraphQL specification does not provide anything to declare or resolve such dependencies. So instead we use tooling for this. In our example we’re relying on the webpack-graphql-loader which enables the import syntax in GraphQL files (graphql-tag is a good alternative). We configure the loader for our .grapqhl files in our Webpack setup:

webpackConfig.module.rules.push({
  test: /\.graphql?$/,
  loader: 'webpack-graphql-loader'
})

The loader also allows us to directly load GraphQL files in JavaScript files, so we can use the queries to fetch data. For example in a Next.js app:

// pages/Blog.jsx
import { graphqlRequest } from '../lib/our-graphql-request-helper'
import query from './Blog.query.graphql'

export async function getStaticProps({ locale }) {
  const { posts } = await graphqlRequest({
    query,
    variables: { locale },
  })
  return { props: { posts } }
}

That’s it. Have fun componentizing your GraphQL.

← Alle blogposts