What's not to love about GraphQL? It's got your back when it comes to returning predictable results - the data you get is exactly what you need, nothing more and nothing less.
If you’ve worked with GraphQL, then you’re probably familiar with query and mutation types — so what exactly is a GraphQL union? 🤔
Unions are abstract GraphQL types that enable a schema field to return one of multiple object types.
Not really sure what that means? Don't worry! I got you. In this tutorial, I will be walking you through the concept of GraphQL unions by addressing the two important questions below:
- Why do I need GraphQL unions?
- How do I implement GraphQL unions?
Why do I need GraphQL unions?
Let's consider a simple scenario: You own a small candy shop and the website is using GraphQL APIs. Each candy is associated with a unique identifier, it's name and price.
Now, let's have a basic query in place to retrieve the details of the candy when passed the unique identifier. Here's how that's gonna look:
Building on this scenario, let's assume that it's also possible for a queried candy to either be out of stock or unavailable for shipping in the region. We can visualize this as three three states of a candy:
We will consider all three states as valid responses and hence, instead of throwing an error when a candy is out of stock or unavailable for shipping, we provide the user with additional information like when a candy would be restocked if out of stock and an array of regions where it is available if unavailable for shipping.
Now, if we add all these new fields on our existing type: Candy, then we would have to over-fetch data to determine the state of a candy. And if we create separate queries for the different states, we would be under-fetching data.
In essence, what we're itching for is a way to somehow define 'out of stock' and 'region unavailability' as separate types (say, OutOfStock
and RegionUnavailability
) along with the existing type: Candy
under the same query to ensure we're only getting the data we need.
How do we do this? That's right, this is where GraphQL unions steps in. We model the identified "states" as separate types and use unions to enable a query to return one of the multiple types defined.
How do I implement GraphQL unions?
Now that we have our states as object types. Let's understand unions: Unions are abstract schema types. To define a union type, we declare which object types are included in the union.
union CandyResult = Candy | OutOfStock | RegionUnavailability
It's important to understand here that all of a union's included types must be object types (not scalars, input types, etc.) and that the included types do not need to share any fields.
Resolving a GraphQL union (server-side):
After adding the union type to our schema file, it's going to be looking something like this:
To resolve a union, we are required to specify which of the union’s type is being returned. To achieve this, we define a __resolveType
function for the union.
The __resolveType
function uses a returned object's unique field to determine its type. It then returns the name of that type as a string.
Here’s how we would use the __resolveType
function for the CandyResult union we’ve defined in the schema:
Querying for a GraphQL union (client-side):
When the return type of a query is a union, the GraphQL client doesn’t know which object type a field will return. To account for this, a query can include the subfields of multiple possible types.
Here’s how our query going to be looking:
query {
candy(id: $id) {
... on Candy {
name
price
}
... on OutOfStock {
restockDate
}
... on RegionUnavailability {
availableRegions
}
}
}
Let’s add a candy to our data dump that’s out of stock with a restockDate
key. When we use the query above to retrieve data for the candy, we can now expect to see the results tailored to exactly what we need.
And that’s it! — we’ve made a query that supports multiple object types with the help of unions.
You can find the entire code as a Github repository here 🚀
Share if you found this useful 😄
Top comments (1)
Hi, I use typescript in my codebase, and when use union in my queries and mutations I received this error:
"Abstract type \"BO\" must resolve to an Object type at runtime for field \"Query.all\". Either the \"BO\" type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function.".
I don't know how to resolve it, can you help me?