@@ -5,7 +5,7 @@ title: Abstract types in GraphQL.js
5
5
GraphQL includes two kinds of abstract types: interfaces and unions. These types let a single
6
6
field return values of different object types, while keeping your schema type-safe.
7
7
8
- This guide covers how to define and resolve abstract types using GraphQL.js. It focuses on
8
+ This guide covers how to define and resolve abstract types using GraphQL.js. It focuses on
9
9
constructing types in JavaScript using the GraphQL.js type system, not the schema definition
10
10
language (SDL).
11
11
@@ -22,20 +22,20 @@ flexibility while preserving validation, introspection, and tool support.
22
22
GraphQL provides two kinds of abstract types:
23
23
24
24
- Interfaces define a set of fields that multiple object types must implement.
25
- - Use case: A ` ContentItem ` interface with fields like ` id ` , ` title ` , and ` publishedAt ` ,
25
+ - Use case: A ` ContentItem ` interface with fields like ` id ` , ` title ` , and ` publishedAt ` ,
26
26
implemented by types such as ` Article ` and ` PodcastEpisode ` .
27
27
- Unions group together unrelated types that don't share any fields.
28
- - Use case: A ` SearchResult ` union that includes ` Book ` , ` Author ` , and ` Publisher ` types.
28
+ - Use case: A ` SearchResult ` union that includes ` Book ` , ` Author ` , and ` Publisher ` types.
29
29
30
30
## Defining interfaces
31
31
32
32
To define an interface in GraphQL.js, use the ` GraphQLInterfaceType ` constructor. An interface
33
- must include a ` name ` , a ` fields ` function , and a ` resolveType ` function, which tells GraphQL which
34
- concrete type a given value corresponds to.
33
+ must include a ` name ` , definition of the shared ` fields ` , and should include a ` resolveType `
34
+ function telling GraphQL which concrete type a given value corresponds to.
35
35
36
36
The following example defines a ` ContentItem ` interface for a publishing platform:
37
37
38
- ``` js
38
+ ``` js filename="ContentItemInterface.js"
39
39
import { GraphQLInterfaceType , GraphQLString , GraphQLNonNull } from ' graphql' ;
40
40
41
41
const ContentItemInterface = new GraphQLInterfaceType ({
@@ -55,10 +55,13 @@ const ContentItemInterface = new GraphQLInterfaceType({
55
55
return null ;
56
56
},
57
57
});
58
+
59
+ exports .ContentItemInterface = ContentItemInterface;
58
60
```
59
61
60
- You can return either the type name as a string or the corresponding ` GraphQLObjectType ` instance.
61
- Returning the instance is recommended when possible for better type safety and tooling support.
62
+ The ` resolveType ` function must return either the string type name corresponding
63
+ to the ` GraphQLObjectType ` of the given ` value ` , or ` null ` if the type could not
64
+ be determined.
62
65
63
66
## Implementing interfaces with object types
64
67
@@ -70,6 +73,7 @@ conform to the `ContentItem` interface:
70
73
71
74
``` js
72
75
import { GraphQLObjectType , GraphQLString , GraphQLNonNull } from ' graphql' ;
76
+ import { ContentItemInterface } from ' ./ContentItemInterface.js' ;
73
77
74
78
const ArticleType = new GraphQLObjectType ({
75
79
name: ' Article' ,
@@ -105,11 +109,8 @@ GraphQL uses `resolveType`.
105
109
Use the ` GraphQLUnionType ` constructor to define a union. A union allows a field to return one
106
110
of several object types that don't need to share fields.
107
111
108
- A union requires:
109
-
110
- - A ` name `
111
- - A list of object types (` types ` )
112
- - A ` resolveType ` function
112
+ A union requires a name and a list of object types (` types ` ). It should also be
113
+ provided a ` resolveType ` function the same as explained for interfaces above.
113
114
114
115
The following example defines a ` SearchResult ` union:
115
116
@@ -134,39 +135,42 @@ const SearchResultType = new GraphQLUnionType({
134
135
});
135
136
```
136
137
137
- Unlike interfaces, unions don't declare any fields of their own. Clients use inline fragments
138
- to query fields from the concrete types .
138
+ Unlike interfaces, unions don't declare any fields their members must implement.
139
+ Clients use a fragment with a type condition to query fields from a concrete type .
139
140
140
141
## Resolving abstract types at runtime
141
142
142
- GraphQL resolves abstract types dynamically during execution using the ` resolveType ` function.
143
+ GraphQL resolves abstract types dynamically during execution using the ` resolveType ` function, if
144
+ present.
143
145
144
146
This function receives the following arguments:
145
147
148
+ { /* prettier-ignore */ }
146
149
``` js
147
150
resolveType (value, context, info)
148
151
```
149
152
150
153
It can return:
151
154
152
- - A ` GraphQLObjectType ` instance (recommended)
153
155
- The name of a type as a string
156
+ - ` null ` if the type could not be determined
154
157
- A ` Promise ` resolving to either of the above
155
158
156
- If ` resolveType ` isn't defined, GraphQL falls back to checking each possible type's ` isTypeOf `
159
+ If ` resolveType ` isn't defined, GraphQL falls back to checking each possible type's ` isTypeOf `
157
160
function. This fallback is less efficient and makes type resolution harder to debug. For most cases,
158
161
explicitly defining ` resolveType ` is recommended.
159
162
160
163
## Querying abstract types
161
164
162
- To query a field that returns an abstract type, use inline fragments to select fields from the
163
- possible concrete types. GraphQL evaluates each fragment based on the runtime type of the result.
165
+ To query a field that returns an abstract type, use fragments to select fields from the possible
166
+ concrete types. GraphQL evaluates each fragment based on the runtime type of the result.
164
167
165
168
For example:
166
169
167
170
``` graphql
168
- {
169
- search (term : " deep learning" ) {
171
+ query Search ($term : String ! = " deep learning" ) {
172
+ search (term : $term ) {
173
+ # Inline fragments with type condition:
170
174
... on Book {
171
175
title
172
176
isbn
@@ -175,30 +179,34 @@ For example:
175
179
name
176
180
bio
177
181
}
178
- ... on Publisher {
179
- name
180
- catalogSize
181
- }
182
+ # Named fragment:
183
+ ... publisherFrag
182
184
}
183
185
}
186
+
187
+ fragment publisherFrag on Publisher {
188
+ name
189
+ catalogSize
190
+ }
184
191
```
185
192
186
193
GraphQL's introspection system lists all possible types for each interface and union, which
187
- enables code generation and editor tooling to provide type-aware completions.
194
+ enables code generation and editor tooling to provide type-aware completions; however you should
195
+ keep in mind the possibility that more types will implement the interface or be included in the
196
+ union in future, and thus ensure that you have a default case to handle additional types.
188
197
189
198
## Best practices
190
199
191
200
- Always implement ` resolveType ` for interfaces and unions to handle runtime type resolution.
192
- - Return the ` GraphQLObjectType ` instance when possible for better clarity and static analysis.
193
201
- Keep ` resolveType ` logic simple, using consistent field shapes or tags to distinguish
194
- types.
195
- - Test ` resolveType ` logic carefully. Errors in ` resolveType ` can cause runtime errors that can
196
- be hard to trace.
202
+ types.
203
+ - Test ` resolveType ` logic carefully. Errors in ` resolveType ` can cause runtime errors that can
204
+ be hard to trace.
197
205
- Use interfaces when types share fields and unions when types are structurally unrelated.
198
206
199
207
## Additional resources
200
208
201
209
- [ Constructing Types] ( https://www.graphql-js.org/docs/constructing-types/ )
202
- - GraphQL Specification:
203
- - [ Interfaces] ( https://spec.graphql.org/October2021/#sec-Interfaces )
204
- - [ Unions] ( https://spec.graphql.org/October2021/#sec-Unions )
210
+ - GraphQL Specification:
211
+ - [ Interfaces] ( https://spec.graphql.org/October2021/#sec-Interfaces )
212
+ - [ Unions] ( https://spec.graphql.org/October2021/#sec-Unions )
0 commit comments