Model Unions as a single type in GraphQL
Problem
The GraphQL API does not support Union types, yet you need query results that are comparable to using Unions.
This recipe is one solution to the problem outlined in Composable Types without Unions.
Solution
If the number of types is obvious, small, and not likely to change, then one option to model Union types is to be explicit about each relationship.
While this method can lead to some verbose queries, you are able to satisfy the objectives.
Setup
-
Update your GraphQL schema to include:
type User { name: String! favoriteMovies: [Movie]! @relation favoriteShows: [Show]! @relation favoriteBooks: [Book]! @relation # ... } type Movie { title: String! newRelease: Boolean # ...movie fields favoritedBy: [User]! @relation } type Show { title: String! newRelease: Boolean # ...TV show fields favoritedBy: [User]! @relation } type Book { title: String! newRelease: Boolean # ...book fields favoritedBy: [User]! @relation } type Query { allMovies: [Movie]! allShows: [Show]! allBooks: [Book]! moviesByNewRelease(newRelease: Boolean!): [Movie]! showsByNewRelease(newRelease: Boolean!): [Show]! booksByNewRelease(newRelease: Boolean!): [Book]! }
This involves editing the GraphQL schema definition, wherever you have stored it, and then uploading the new schema in the Fauna Dashboard.
-
Run GraphQL queries to create a
User
and some media items (Book
,Movie
, orShow
):mutation { createUser( data: { name: "Alice" favoriteMovies: { create: [ { title: "Black Widow", newRelease: true } { title: "Psycho" } ] } favoriteShows: { create: [ { title: "The Expanse", newRelease: true } ] } favoriteBooks: { create: [ { title: "Fellowship of the Ring" } ] } } ) { name _id favoriteMovies { data { title, newRelease, _id } } favoriteShows { data { title, newRelease, _id } } favoriteBooks { data { title, newRelease, _id } } } }
The result should be similar to:
{ "data": { "createUser": { "name": "Alice", "_id": "332112150594060834", "favoriteMovies": { "data": [ { "title": "Black Widow", "newRelease": true, "_id": "332112150596157986" }, { "title": "Psycho", "newRelease": null, "_id": "332112150607692322" } ] }, "favoriteShows": { "data": [ { "title": "The Expanse", "newRelease": true, "_id": "332112150611886626" } ] }, "favoriteBooks": { "data": [ { "title": "Fellowship of the Ring", "newRelease": null, "_id": "332112150615032354" } ] } } } }
The document IDs presented in the _id
fields are different for every new document created in Fauna. The Objective 3 query requires two of the document IDs present in this result.
Objective 1: Query for all entities of a given type
Each entity has its own type, so they can be queried separately.
{
allMovies {
data { title, newRelease }
}
allShows {
data { title, newRelease }
}
allBooks {
data { title, newRelease }
}
}
The result should be:
{
"data": {
"allMovies": {
"data": [
{
"title": "Black Widow",
"newRelease": true
},
{
"title": "Psycho",
"newRelease": null
}
]
},
"allShows": {
"data": [
{
"title": "The Expanse",
"newRelease": true
}
]
},
"allBooks": {
"data": [
{
"title": "Fellowship of the Ring",
"newRelease": null
}
]
}
}
}
Objective 2: Query for all entities with certain properties
You can make multiple queries to get all of the results. Indexes are
automatically added by the GraphQL API using the fields specified on
the Query type to support search-by-field, such as the newRelease
field:
{
moviesByNewRelease(newRelease: true) {
data { title, newRelease }
}
showsByNewRelease(newRelease: true) {
data { title, newRelease }
}
booksByNewRelease(newRelease: true) {
data { title, newRelease }
}
}
The result should be:
{
"data": {
"moviesByNewRelease": {
"data": [
{
"title": "Black Widow",
"newRelease": true
}
]
},
"showsByNewRelease": {
"data": [
{
"title": "The Expanse",
"newRelease": true
}
]
},
"booksByNewRelease": {
"data": []
}
}
}
Objective 3: Query for all relationships of an entity, regardless of which type it points to
-
You can search for all user favorites by selecting each relationship field.
-
You can search for all users that have the media item marked as a favorite, since each type has that field.
To make the following query work:
-
replace
<USERID>
with the document ID for the user created in the setup’s step 2 (just below thename
field in the result). -
replace
<MOVIEID>
with the document ID for the "Black Widow" movie created in the setup’s step 2.
{
findUserByID(id: "<USERID>") {
name
favoriteMovies {
data { title, newRelease }
}
favoriteShows {
data { title, newRelease }
}
favoriteBooks {
data { title, newRelease }
}
}
findMovieByID(id: "<MOVIEID>") {
title
newRelease
favoritedBy {
data { name }
}
}
}
The result should be:
{
"data": {
"findUserByID": {
"name": "Alice",
"favoriteMovies": {
"data": [
{
"title": "Black Widow",
"newRelease": true
},
{
"title": "Psycho",
"newRelease": null
}
]
},
"favoriteShows": {
"data": [
{
"title": "The Expanse",
"newRelease": true
}
]
},
"favoriteBooks": {
"data": [
{
"title": "Fellowship of the Ring",
"newRelease": null
}
]
}
},
"findMovieByID": {
"title": "Black Widow",
"newRelease": true,
"favoritedBy": {
"data": [
{
"name": "Alice"
}
]
}
}
}
}
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!