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.