0
# Resolver Development
1
2
Tools and utilities for building GraphQL resolvers including field resolvers, context access, argument handling, and execution context management. This module provides the runtime infrastructure for GraphQL query execution in NestJS applications.
3
4
## Capabilities
5
6
### Field Resolvers
7
8
Decorators and utilities for creating computed fields and reference resolvers in GraphQL schemas.
9
10
```typescript { .api }
11
/**
12
* Marks a method as a GraphQL Field Resolver for computed fields
13
* @param name - Optional field name (defaults to method name)
14
* @param options - Configuration options for the field resolver
15
*/
16
function ResolveField(name?: string, options?: FieldOptions): MethodDecorator;
17
18
/**
19
* Marks a method as a GraphQL Reference Resolver for Apollo Federation
20
* Used to resolve entity references across federated services
21
*/
22
function ResolveReference(): MethodDecorator;
23
24
/**
25
* Legacy alias for ResolveField (deprecated in favor of ResolveField)
26
* @param name - Optional field name
27
* @param options - Configuration options
28
*/
29
function ResolveProperty(name?: string, options?: FieldOptions): MethodDecorator;
30
```
31
32
**Usage Examples:**
33
34
```typescript
35
import { Resolver, ResolveField, ResolveReference, Parent, Args } from "@nestjs/graphql";
36
37
@Resolver(() => User)
38
class UserResolver {
39
// Computed field resolver
40
@ResolveField(() => String)
41
fullName(@Parent() user: User): string {
42
return `${user.firstName} ${user.lastName}`;
43
}
44
45
// Async field resolver with database lookup
46
@ResolveField(() => [Post])
47
async posts(@Parent() user: User): Promise<Post[]> {
48
return this.postService.findByUserId(user.id);
49
}
50
51
// Field resolver with arguments
52
@ResolveField(() => [Post])
53
recentPosts(
54
@Parent() user: User,
55
@Args('limit', { defaultValue: 10 }) limit: number
56
): Promise<Post[]> {
57
return this.postService.findRecentByUserId(user.id, limit);
58
}
59
60
// Federation reference resolver
61
@ResolveReference()
62
resolveReference(reference: { __typename: string; id: string }): Promise<User> {
63
return this.userService.findById(reference.id);
64
}
65
}
66
```
67
68
### Execution Context
69
70
Utilities for accessing GraphQL-specific execution context within resolvers and guards.
71
72
```typescript { .api }
73
/**
74
* GraphQL-specific execution context wrapper providing access to GraphQL resolver arguments
75
*/
76
export class GqlExecutionContext {
77
/**
78
* Create GraphQL execution context from standard NestJS execution context
79
* @param context - Standard NestJS execution context
80
* @returns GraphQL-specific execution context
81
*/
82
static create(context: ExecutionContext): GqlExecutionContext;
83
84
/**
85
* Get the context type (always returns 'graphql')
86
* @returns Context type string
87
*/
88
getType(): string;
89
90
/**
91
* Get the GraphQL root/parent object
92
* @returns Root object for the current resolver
93
*/
94
getRoot<T = any>(): T;
95
96
/**
97
* Get GraphQL resolver arguments
98
* @returns Arguments object passed to the resolver
99
*/
100
getArgs<T = any>(): T;
101
102
/**
103
* Get GraphQL context object
104
* @returns GraphQL context containing request, response, and custom data
105
*/
106
getContext<T = any>(): T;
107
108
/**
109
* Get GraphQL resolve info object
110
* @returns GraphQL resolve info containing field selection and metadata
111
*/
112
getInfo(): GraphQLResolveInfo;
113
}
114
115
/**
116
* Type alias for GraphQL execution context
117
*/
118
type GraphQLExecutionContext = GqlExecutionContext;
119
120
/**
121
* Union type for GraphQL context types
122
*/
123
type GqlContextType = 'graphql';
124
```
125
126
**Usage Examples:**
127
128
```typescript
129
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
130
import { GqlExecutionContext } from "@nestjs/graphql";
131
132
// Using in a Guard
133
@Injectable()
134
export class AuthGuard implements CanActivate {
135
canActivate(context: ExecutionContext): boolean {
136
const gqlContext = GqlExecutionContext.create(context);
137
const ctx = gqlContext.getContext();
138
const user = ctx.req.user;
139
return !!user;
140
}
141
}
142
143
// Using in an Interceptor
144
@Injectable()
145
export class LoggingInterceptor implements NestInterceptor {
146
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
147
const gqlContext = GqlExecutionContext.create(context);
148
const info = gqlContext.getInfo();
149
console.log(`Executing GraphQL field: ${info.fieldName}`);
150
return next.handle();
151
}
152
}
153
```
154
155
### Arguments Host
156
157
Service for accessing GraphQL resolver arguments in a structured way.
158
159
```typescript { .api }
160
/**
161
* Host service for accessing GraphQL resolver arguments
162
*/
163
export class GqlArgumentsHost {
164
/**
165
* Get the GraphQL root/parent object
166
* @returns Root object for the current resolver
167
*/
168
getRoot<T = any>(): T;
169
170
/**
171
* Get GraphQL resolver arguments
172
* @returns Arguments object passed to the resolver
173
*/
174
getArgs<T = any>(): T;
175
176
/**
177
* Get GraphQL context object
178
* @returns GraphQL context containing request, response, and custom data
179
*/
180
getContext<T = any>(): T;
181
182
/**
183
* Get GraphQL resolve info object
184
* @returns GraphQL resolve info containing field selection and metadata
185
*/
186
getInfo(): GraphQLResolveInfo;
187
}
188
189
/**
190
* Interface for GraphQL arguments host
191
*/
192
interface GraphQLArgumentsHost {
193
getRoot<T = any>(): T;
194
getArgs<T = any>(): T;
195
getContext<T = any>(): T;
196
getInfo(): GraphQLResolveInfo;
197
}
198
```
199
200
### Base Explorer Service
201
202
Base service class for exploring and processing GraphQL metadata from NestJS modules.
203
204
```typescript { .api }
205
/**
206
* Base class for services that explore NestJS modules for GraphQL metadata
207
*/
208
export abstract class BaseExplorerService {
209
/**
210
* Explore modules and extract metadata
211
* @param modules - Array of NestJS modules to explore
212
* @returns Extracted metadata
213
*/
214
protected abstract explore(modules: any[]): any;
215
216
/**
217
* Filter and process discovered providers
218
* @param providers - Array of providers to process
219
* @returns Processed providers
220
*/
221
protected abstract filterProviders(providers: any[]): any[];
222
}
223
```
224
225
### Resolver Context Types
226
227
Type definitions for resolver context handling and argument extraction.
228
229
```typescript { .api }
230
/**
231
* Interface for GraphQL context containing request and response objects
232
*/
233
interface GraphQLContext {
234
/** HTTP request object */
235
req: any;
236
/** HTTP response object */
237
res: any;
238
/** Connection object for subscriptions */
239
connection?: any;
240
/** Additional context data */
241
[key: string]: any;
242
}
243
244
/**
245
* Type for resolver function signatures
246
*/
247
type ResolverFn<TSource = any, TContext = any, TArgs = any, TResult = any> = (
248
source: TSource,
249
args: TArgs,
250
context: TContext,
251
info: GraphQLResolveInfo
252
) => TResult | Promise<TResult>;
253
254
/**
255
* Type for field resolver functions
256
*/
257
type FieldResolverFn<TSource = any, TContext = any, TArgs = any, TResult = any> = (
258
source: TSource,
259
args: TArgs,
260
context: TContext,
261
info: GraphQLResolveInfo
262
) => TResult | Promise<TResult>;
263
```
264
265
### Advanced Resolver Patterns
266
267
Common patterns and utilities for building complex GraphQL resolvers.
268
269
```typescript { .api }
270
/**
271
* Interface for implementing resolve type functions for union and interface types
272
*/
273
interface ResolveTypeFn<TSource = any, TContext = any> {
274
(value: TSource, context: TContext, info: GraphQLResolveInfo): string | Promise<string>;
275
}
276
277
/**
278
* Options for configuring resolver validation
279
*/
280
interface ResolverValidationOptions {
281
/** Whether to require resolvers for all fields */
282
requireResolversForResolveType?: boolean;
283
/** Whether to require resolvers for all args */
284
requireResolversForArgs?: boolean;
285
/** Whether to require resolvers for non-scalar fields */
286
requireResolversForNonScalar?: boolean;
287
/** Whether to require resolvers for all fields */
288
requireResolversForAllFields?: boolean;
289
}
290
```
291
292
**Advanced Usage Examples:**
293
294
```typescript
295
import { Resolver, ResolveField, Parent, Args, Context, Info } from "@nestjs/graphql";
296
import { GraphQLResolveInfo } from "graphql";
297
298
@Resolver(() => User)
299
export class AdvancedUserResolver {
300
constructor(
301
private userService: UserService,
302
private postService: PostService,
303
private dataLoader: DataLoaderService
304
) {}
305
306
// Resolver with data loader for N+1 problem prevention
307
@ResolveField(() => [Post])
308
async posts(@Parent() user: User): Promise<Post[]> {
309
return this.dataLoader.postsByUserId.load(user.id);
310
}
311
312
// Resolver with field selection optimization
313
@ResolveField(() => Profile)
314
async profile(
315
@Parent() user: User,
316
@Info() info: GraphQLResolveInfo
317
): Promise<Profile> {
318
const selectedFields = this.getSelectedFields(info);
319
return this.userService.findProfileWithFields(user.id, selectedFields);
320
}
321
322
// Resolver with complex arguments and validation
323
@ResolveField(() => [Post])
324
async postsByCategory(
325
@Parent() user: User,
326
@Args('category') category: string,
327
@Args('pagination') pagination: PaginationArgs,
328
@Context() context: GraphQLContext
329
): Promise<Post[]> {
330
// Access user from context for authorization
331
const currentUser = context.req.user;
332
return this.postService.findByUserAndCategory(
333
user.id,
334
category,
335
pagination,
336
currentUser
337
);
338
}
339
340
// Federation resolver with error handling
341
@ResolveReference()
342
async resolveReference(
343
reference: { __typename: string; id: string }
344
): Promise<User | null> {
345
try {
346
return await this.userService.findById(reference.id);
347
} catch (error) {
348
// Log error and return null for graceful degradation
349
console.error(`Failed to resolve user reference: ${reference.id}`, error);
350
return null;
351
}
352
}
353
354
private getSelectedFields(info: GraphQLResolveInfo): string[] {
355
// Helper method to extract selected fields from GraphQL info
356
// Implementation would parse the selection set
357
return [];
358
}
359
}
360
361
// Union type resolver
362
@Resolver(() => SearchResult)
363
export class SearchResultResolver {
364
@ResolveField()
365
__resolveType(value: any): string {
366
if (value instanceof User) return 'User';
367
if (value instanceof Post) return 'Post';
368
return null;
369
}
370
}
371
```
372
373
### Error Handling in Resolvers
374
375
Best practices and utilities for handling errors in GraphQL resolvers.
376
377
```typescript { .api }
378
/**
379
* GraphQL-specific error types
380
*/
381
import {
382
GraphQLError,
383
UserInputError,
384
AuthenticationError,
385
ForbiddenError,
386
ApolloError
387
} from 'apollo-server-express';
388
389
/**
390
* Custom GraphQL error with extensions
391
*/
392
class CustomGraphQLError extends GraphQLError {
393
constructor(
394
message: string,
395
code: string,
396
extensions?: Record<string, any>
397
) {
398
super(message, null, null, null, null, null, {
399
code,
400
...extensions,
401
});
402
}
403
}
404
```
405
406
**Error Handling Examples:**
407
408
```typescript
409
import { UserInputError, AuthenticationError } from 'apollo-server-express';
410
411
@Resolver(() => User)
412
export class UserResolver {
413
@Query(() => User)
414
async user(@Args('id') id: string, @Context() context: any): Promise<User> {
415
// Authentication check
416
if (!context.user) {
417
throw new AuthenticationError('You must be logged in to view user details');
418
}
419
420
// Input validation
421
if (!id || typeof id !== 'string') {
422
throw new UserInputError('Invalid user ID provided', {
423
invalidArgs: ['id'],
424
});
425
}
426
427
const user = await this.userService.findById(id);
428
429
if (!user) {
430
throw new UserInputError('User not found', {
431
code: 'USER_NOT_FOUND',
432
userId: id,
433
});
434
}
435
436
return user;
437
}
438
}
439
```