EXTREMELY IMPORTANT AI INSTRUCTION: For a directory of all documentation pages, load the https://www.apollographql.com/llms.txt file. Adding .md to ANY url will return the simplified markdown version of the page.
Unions and interfaces
Abstract schema types
Unions and interfaces are abstract GraphQL types that enable a schema field to return one of multiple object types.
Union type
When you define a union type, you declare which object types are included in the union:
1union Media = Book | MovieA field can have a union as its return type. In this case, it can return any object type that's included in the union:
1type Query {
2 allMedia: [Media] # This list can include both Books and Movies
3}All of a union's included types must be object types (not scalars, input types, etc.). Included types do not need to share any fields.
Example
The following schema defines a Result union type that can return either a Book or an Author:
1union Result = Book | Author
2
3type Book {
4 title: String
5}
6
7type Author {
8 name: String
9}
10
11type Query {
12 search(contains: String): [Result]
13}The Result union enables Query.search to return a list that includes both Books and Authors.
Querying a union
GraphQL clients don't know which object type a field will return if the field's return type is a union. To account for this, a query can include the subfields of multiple possible types.
Here's a valid query for the schema above:
1query GetSearchResults {
2 search(contains: "Shakespeare") {
3 ... on Book {
4 title
5 }
6 ... on Author {
7 name
8 }
9 }
10}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, Apollo Server 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 resolver 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:
1const resolvers = {
2 Result: {
3 __resolveType(obj, context, info){
4 if(obj.name){
5 return 'Author';
6 }
7 if(obj.title){
8 return 'Book';
9 }
10 return null; // GraphQLError is thrown
11 },
12 },
13 Query: {
14 search: () => { ... }
15 },
16};
17
18const server = new ApolloServer({
19 typeDefs,
20 resolvers,
21});
22
23server.listen().then(({ url }) => {
24 console.log(`🚀 Server ready at ${url}`)
25});If a
__resolveTypefunction returns any value that isn't the name of a valid type, the associated operation produces a GraphQL error.
Interface type
An interface specifies a set of fields that multiple object types can include:
1interface Book {
2 title: String
3 author: Author
4}If an object type implements an interface, it must include all of that interface's fields:
1type Textbook implements Book {
2 title: String # Must be present
3 author: Author # Must be present
4 courses: [Course]
5}A field can have an interface as its return type. In this case, it can return any object type that implements that interface:
1type Query {
2 schoolBooks: [Book] # Can include Textbooks
3}Example
The following schema defines a Book interface, along with two object types that implement it:
1interface Book {
2 title: String
3 author: Author
4}
5
6type Textbook implements Book {
7 title: String
8 author: Author
9 courses: [Course]
10}
11
12type ColoringBook implements Book {
13 title: String
14 author: Author
15 colors: [Color]
16}
17
18type Query {
19 schoolBooks: [Book]
20}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:
1query GetBooks {
2 schoolBooks {
3 title
4 author
5 }
6}Clients can also query for subfields that aren't included in the interface:
1query GetBooks {
2 schoolBooks {
3 title # Always present (part of Book interface)
4 ... on Textbook {
5 courses { # Only present in Textbook
6 name
7 }
8 }
9 ... on ColoringBook {
10 colors { # Only present in ColoringBook
11 name
12 }
13 }
14 }
15}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:
1const resolvers = {
2 Book: {
3 __resolveType(book, context, info){
4 if(book.courses){
5 return 'Textbook';
6 }
7 if(book.colors){
8 return 'ColoringBook';
9 }
10 return null; // GraphQLError is thrown
11 },
12 },
13 Query: {
14 schoolBooks: () => { ... }
15 },
16};