Using GraphQL Fragments for Unions and Interfaces


Fragments are one of the most underrated features in GraphQL. A fragment is a reusable unit in GraphQL that allows developers to construct sets of fields that you can include in multiple operations. Fragments are helpful when constructing queries that require repetitive fields or complex data structures that need to be broken down into smaller chunks. Some GraphQL clients even allow you to use fragments to colocate fragments across pages and components.
In this blog post, you'll learn how to use GraphQL fragments and how to use them to construct operations that return data from GraphQL unions and interfaces.
When to use GraphQL fragments?
Using fragments, we can keep our queries concise and avoid repeating the same fields multiple times. Additionally, if we need to add or remove fields from our query, we only need to update the fragment instead of modifying every instance of the fields in the query.
Let's have a look at the following GraphQL schema:
type Employee {
name: String
age: Int
salary: Float
terminationDate: String
}
type Query {
employees: [Employee]
}
In this schema, the response type for employees
is Employee
, which returns the employee's name, age, salary, and termination date. The terminationDate
field is only returned for employees that have left the company.
Assume you have a page that displays a list of employees with their names, ages, and salaries. You can create a fragment that includes those fields and use it like this:
fragment employeeFields on Employee {
name
age
salary
}
query {
employees {
...employeeFields
}
}
This makes constructing operations that return data from multiple types easier. For example, when adding a new field selection that returns the same fields, you can simplify using a fragment:
fragment employeeFields on Employee {
name
age
salary
}
query employees {
employees {
...employeeFields
}
allEmployees: employees {
...employeeFields
terminationDate
}
}
In the above example, we request the same fields for employees
and allEmployees
. The field allEmployees
is an alias for employees
and returns the same data. The only difference is that allEmployees
returns the terminationDate
field. Instead of repeating the same fields in both queries, we can use the employeeFields
fragment to keep our operations concise and avoid repeating the same fields multiple times.
To read more about basic GraphQL fragments, check out this previous blog post.
In the next section, you'll learn how to use GraphQL fragments based on interfaces.
Fragments for interfaces
You've just learned how to use GraphQL fragments to share fields between field selections, but you can also use fragments on fields defined through an interface. If we'd create an Employee
interface, we could create a fragment based on that interface instead of the return type for an operation. This is useful when you have multiple types implementing the same interface.
For example, in the following GraphQL schema we have changed the type Employee
to an interface that is implemented by two new types: CurrentEmployee
and FormerEmployee
.
interface Employee {
name: String
age: Int
salary: Float
}
type CurrentEmployee implements Employee {
name: String
age: Int
salary: Float
}
type FormerEmployee implements Employee {
name: String
age: Int
salary: Float
terminationDate: String
}
type Query {
formerEmployees: [FormerEmployee]
currentEmployees: [CurrentEmployee]
}
In this schema, the Employee
interface is implemented by CurrentEmployee
and FormerEmployee
. The formerEmployees
and currentEmployees
fields return a list of former and current employees, respectively. Let's say we want to get current and former employees and display their names, ages, and salaries. We can use a fragment to share the fields between formerEmployees
and currentEmployees
:
fragment employeeFields on Employee {
name
age
salary
}
query {
formerEmployees {
...employeeFields
terminationDate
}
currentEmployees {
...employeeFields
}
}
That's not all; you can also use fragments to distinguish between possible return types for an operation that returns a union (or interface) type , as you'll learn in the next section.
Fragments for unions
What if we'd want to get both the former and current employees in one field selection and want to distinguish between the fields? In GraphQL, you can do this by using inline fragments. Have a look at the following GraphQL schema that contains a union type:
interface Employee {
name: String
age: Int
salary: Float
}
type CurrentEmployee implements Employee {
name: String
age: Int
salary: Float
}
type FormerEmployee implements Employee {
name: String
age: Int
salary: Float
terminationDate: String
}
union AnyEmployee = CurrentEmployee | FormerEmployee
type Query {
employees: [AnyEmployee]
}
The above schema shows that the AnyEmployee
union type contains two possible types: CurrentEmployee
and FormerEmployee
. Let's say we want to query the employees' field and display different information depending on whether an employee is employed or a former employee. We can use an inline fragment to specify the fields unique to each subtype of the AnyEmployee
union.
query {
employees {
... on Employee {
name
age
salary
}
... on FormerEmployee {
terminationDate
}
}
}
In this example, we're requesting the employees
field and requesting the name
, age
, and salary
fields for all employees. Additionally, we're using an inline fragment with the on keyword to specify that if an employee is a FormerEmployee
, we also want to include the terminationDate
field in the response. Three or four fields will be returned based on whether or not an employee is currently working for the company.
Using an inline fragment, we can conditionally include fields based on the type of object you're querying, making it easier to work with union types and polymorphic interfaces.
Running the example
You should install the StepZen CLI on your local machine to run the example in this blog post. If you still need to install StepZen, you can follow the instructions in the Getting Started guide.
To run the example, you'll need to define a schema for the GraphQL API in a new file called api.graphql
. Create this file in a new directory, copy the schema from the example above, and paste it into the api.graphql
file. Add the @rest
custom directive to mock data. The complete schema, including the mocking capability, looks like this:
## api.graphql
## ...
type Query {
employees: [AnyEmployee]
@rest(
endpoint: "stepzen:empty"
ecmascript: """
function transformREST(s) {
return ([
{
__typename: "FormerEmployee",
name: "John Doe",
age: 30,
salary: 100000,
terminationDate: "2021-01-01"
},
{
__typename: "CurrentEmployee",
name: "Jane Doe",
age: 25,
salary: 80000
},
{
__typename: "CurrentEmployee",
name: "John Smith",
age: 40,
salary: 120000
},
{
__typename: "FormerEmployee",
name: "Jane Smith",
age: 35,
salary: 100000,
terminationDate: "2021-01-01"
}
])
}
"""
)
}
Next, you'll need to create a new file called index.graphql
and add the following query to it:
## index.graphql
schema @sdl(files: ["api.graphql"]) {
query: Query
}
Now you can run the following command to start and deploy the StepZen GraphQL API:
stepzen start
If you'd like to implement the example for interfaces, you should create the
formerEmployees
andcurrentEmployees
operation fields using the logic for theemployees
operation field.
The StepZen CLI will ask how you like to name your endpoint, after which it will be deployed. Your new GraphQL API is now running, and you can open GraphQL Explorer to test the queries from this blog post on the endpoint displayed in the terminal.
Conclusion
In this blog post, you've learned to use GraphQL fragments to share fields between fields selection. You've also learned to use fragments to construct queries that return data from GraphQL unions and interfaces. Questions? You can ask for help on our Discord channel.