Join us from October 8-10 in New York City to learn the latest tips, trends, and news about GraphQL Federation and API platform engineering.Join us for GraphQL Summit 2024 in NYC
Docs
Start for Free
Apollo Server 2 is officially end-of-life as of 22 October 2023. Learn more about upgrading.

Unions and interfaces

Abstract schema types


Unions and interfaces are abstract types that enable a schema to return one of multiple .

Union type

When you define a union type, you declare which object types are included in the union:

union Media = Book | Movie

A field can have a union as its return type. In this case, it can return any that's included in the union:

type Query {
allMedia: [Media] # This list can include both Books and Movies
}

All of a union's included types must be object types (not , input types, etc.). Included types do not need to share any .

Example

The following schema defines a Result union type that can return either a Book or an Author:

union Result = Book | Author
type Book {
title: String
}
type Author {
name: String
}
type Query {
search(contains: String): [Result]
}

The Result union enables Query.search to return a list that includes both Books and Authors.

Querying a union

don't know which object type a field will return if the field's return type is a union. To account for this, a can include the subfields of multiple possible types.

Here's a valid query for the schema above:

query GetSearchResults {
search(contains: "Shakespeare") {
... on Book {
title
}
... on Author {
name
}
}
}

This query uses inline fragments to fetch a Result's title (if it's a Book) or its name (if it's an Author).

For more information, see Using fragments with unions and interfaces.

Resolving a union

To fully resolve a union, needs to specify which of the union's types is being returned. To achieve this, you define a __resolveType function for the union in your map.

The __resolveType function uses a returned object's fields to determine its type. It then returns the name of that type as a string.

Here's an example __resolveType function for the Result union defined above:

const resolvers = {
Result: {
__resolveType(obj, context, info){
if(obj.name){
return 'Author';
}
if(obj.title){
return 'Book';
}
return null; // GraphQLError is thrown
},
},
Query: {
search: () => { ... }
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
});

If a __resolveType function returns any value that isn't the name of a valid type, the associated produces a GraphQL error.

Interface type

An interface specifies a set of fields that multiple object types can include:

interface Book {
title: String
author: Author
}

If an object type implements an interface, it must include all of that interface's fields:

type Textbook implements Book {
title: String # Must be present
author: Author # Must be present
courses: [Course]
}

A field can have an interface as its return type. In this case, it can return any object type that implements that interface:

type Query {
schoolBooks: [Book] # Can include Textbooks
}

Example

The following schema defines a Book interface, along with two object types that implement it:

interface Book {
title: String
author: Author
}
type Textbook implements Book {
title: String
author: Author
courses: [Course]
}
type ColoringBook implements Book {
title: String
author: Author
colors: [Color]
}
type Query {
schoolBooks: [Book]
}

In this schema, Query.schoolBooks returns a list that can include both Textbooks and ColoringBooks.

Querying an interface

If a field's return type is an interface, clients can query that field for any subfields included in the interface:

query GetBooks {
schoolBooks {
title
author
}
}

Clients can also query for subfields that aren't included in the interface:

query GetBooks {
schoolBooks {
title # Always present (part of Book interface)
... on Textbook {
courses { # Only present in Textbook
name
}
}
... on ColoringBook {
colors { # Only present in ColoringBook
name
}
}
}
}

This query uses inline fragments to fetch a Book's courses (if it's a Textbook) or its colors (if it's a ColoringBook).

For more information, see Using fragments with unions and interfaces.

Resolving an interface

As with union types, Apollo Server requires interfaces to define a __resolveType function to determine which implementing object type is being returned.

Here's an example __resolveType function for the Book interface defined above:

const resolvers = {
Book: {
__resolveType(book, context, info){
if(book.courses){
return 'Textbook';
}
if(book.colors){
return 'ColoringBook';
}
return null; // GraphQLError is thrown
},
},
Query: {
schoolBooks: () => { ... }
},
};
Previous
Schema basics
Next
Custom scalars
Rate articleRateEdit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc., d/b/a Apollo GraphQL.

Privacy Policy

Company