mirror of
https://github.com/nestjs/docs.nestjs.com.git
synced 2026-02-21 20:31:32 +00:00
Update resolvers-map.md
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
### Resolvers
|
||||
|
||||
Resolvers provide the instructions for turning a [GraphQL](https://graphql.org/) operation (a query, mutation, or subscription) into data. They return the same shape of data we specify in our schema -- either synchronously or as a promise that resolves to a result of that shape. Typically, you create a **resolver map** manually. The `@nestjs/graphql` package, on the other hand, generates a resolver map automatically using the metadata provided by decorators you use to annotate classes. To demonstrate the process of using the package features to create a GraphQL API, we'll create a simple authors API.
|
||||
Resolvers provide the instructions for turning a [GraphQL](https://graphql.org/) operation (a query, mutation, or subscription) into data. They return the same shape of data we specify in our schema -- either synchronously or as a promise that resolves to a result of that shape. Typically, you create a **resolver map** manually. The `@nestjs/graphql` package, on the other hand, generates a resolver map automatically using the metadata provided by the decorators you use to annotate classes. To demonstrate the process of using the package features to create a GraphQL API, we'll create a simple authors API.
|
||||
|
||||
#### Code first
|
||||
|
||||
In the code first approach, we don't follow the typical process of creating our GraphQL schema by writing GraphQL SDL by hand. Instead, we use TypeScript decorators to generate the SDL from TypeScript class definitions. The `@nestjs/graphql` package reads the metadata defined through the decorators and automatically generates the schema for you.
|
||||
In the code-first approach, we don't follow the typical process of creating our GraphQL schema by writing GraphQL SDL by hand. Instead, we use TypeScript decorators to generate the SDL from TypeScript class definitions. The `@nestjs/graphql` package reads the metadata defined through the decorators and automatically generates the schema for you.
|
||||
|
||||
#### Object types
|
||||
|
||||
Most of the definitions in a GraphQL schema are **object types**. Each object type you define should represent a domain object that an application client might need to interact with. For example, our sample API needs to be able to fetch a list of authors and their posts, so we should define the `Author` type and `Post` type to support this functionality.
|
||||
|
||||
If we were using the schema first approach, we'd define such a schema with SDL like this:
|
||||
If we were using the schema-first approach, we'd define such a schema with SDL like this:
|
||||
|
||||
```graphql
|
||||
type Author {
|
||||
@@ -159,15 +159,15 @@ You can define multiple resolver classes. Nest will combine these at run time. S
|
||||
|
||||
> warning **Note** The logic inside the `AuthorsService` and `PostsService` classes can be as simple or sophisticated as needed. The main point of this example is to show how to construct resolvers and how they can interact with other providers.
|
||||
|
||||
In the example above, we created the `AuthorsResolver` which defines one query resolver function and one field resolver function. To create a resolver, we create a class with resolver functions as methods, and annotate the class with the `@Resolver()` decorator.
|
||||
In the example above, we created the `AuthorsResolver`, which defines one query resolver function and one field resolver function. To create a resolver, we create a class with resolver functions as methods, and annotate the class with the `@Resolver()` decorator.
|
||||
|
||||
In this example, we defined a query handler to get the author object based on the `id` sent in the request. To specify that the method is a query handler, use the `@Query()` decorator.
|
||||
|
||||
The argument passed to the `@Resolver()` decorator is optional, but comes into play when our graph becomes non-trivial. It's used to supply a parent object used by field resolver functions as they traverse down through an object graph.
|
||||
|
||||
In our example, since the class includes a **field resolver** function (for the `posts` property of the `Author` object type), we **must** supply the `@Resolver()` decorator with a value to indicate which class is the parent type (i.e., the corresponding `ObjectType` class name) for all field resolvers defined within this class. As should be clear from the example, when writing a field resolver function, it's necessary to access the parent object (the object the field being resolved is a member of). In this example, we populate an author's posts array with a field resolver that calls a service which takes the author's `id` as an argument. Hence the need to identify the parent object in the `@Resolver()` decorator. Note the corresponding use of the `@Parent()` method parameter decorator to then extract a reference to that parent object in the field resolver.
|
||||
In our example, since the class includes a **field resolver** function (for the `posts` property of the `Author` object type), we **must** supply the `@Resolver()` decorator with a value to indicate which class is the parent type (i.e., the corresponding `ObjectType` class name) for all field resolvers defined within this class. As should be clear from the example, when writing a field resolver function, it's necessary to access the parent object (the object the field being resolved is a member of). In this example, we populate an author's posts array with a field resolver that calls a service that takes the author's `id` as an argument. Hence, the need to identify the parent object in the `@Resolver()` decorator. Note the corresponding use of the `@Parent()` method parameter decorator to then extract a reference to that parent object in the field resolver.
|
||||
|
||||
We can define multiple `@Query()` resolver functions (both within this class, and in any other resolver class), and they will be aggregated into a single **Query type** definition in the generated SDL along with the appropriate entries in the resolver map. This allows you to define queries close to the models and services that they use, and to keep them well organized in modules.
|
||||
We can define multiple `@Query()` resolver functions (both within this class and in any other resolver class), and they will be aggregated into a single **Query type** definition in the generated SDL along with the appropriate entries in the resolver map. This allows you to define queries close to the models and services that they use, and to keep them well organized in modules.
|
||||
|
||||
> info **Hint** Nest CLI provides a generator (schematic) that automatically generates **all the boilerplate code** to help us avoid doing all of this, and make the developer experience much simpler. Read more about this feature [here](/recipes/crud-generator).
|
||||
|
||||
@@ -237,13 +237,13 @@ The `@Query()` decorator's options object (where we pass `{{ '{' }}name: 'author
|
||||
|
||||
Use the `@Args()` decorator to extract arguments from a request for use in the method handler. This works in a very similar fashion to [REST route parameter argument extraction](/controllers#route-parameters).
|
||||
|
||||
Usually your `@Args()` decorator will be simple, and not require an object argument as seen with the `getAuthor()` method above. For example, if the type of an identifier is string, the following construction is sufficient, and simply plucks the named field from the inbound GraphQL request for use as a method argument.
|
||||
Usually, your `@Args()` decorator will be simple and not require an object argument, as seen with the `getAuthor()` method above. For example, if the type of an identifier is string, the following construction is sufficient, and simply plucks the named field from the inbound GraphQL request for use as a method argument.
|
||||
|
||||
```typescript
|
||||
@Args('id') id: string
|
||||
```
|
||||
|
||||
In the `getAuthor()` case, the `number` type is used, which presents a challenge. The `number` TypeScript type doesn't give us enough information about the expected GraphQL representation (e.g., `Int` vs. `Float`). Thus we have to **explicitly** pass the type reference. We do that by passing a second argument to the `Args()` decorator, containing argument options, as shown below:
|
||||
In the `getAuthor()` case, the `number` type is used, which presents a challenge. The `number` TypeScript type doesn't give us enough information about the expected GraphQL representation (e.g., `Int` vs. `Float`). Thus, we have to **explicitly** pass the type reference. We do that by passing a second argument to the `Args()` decorator, containing argument options, as shown below:
|
||||
|
||||
```typescript
|
||||
@Query(() => Author, { name: 'author' })
|
||||
@@ -252,12 +252,12 @@ async getAuthor(@Args('id', { type: () => Int }) id: number) {
|
||||
}
|
||||
```
|
||||
|
||||
The options object allows us to specify the following optional key value pairs:
|
||||
The options object allows us to specify the following optional key-value pairs:
|
||||
|
||||
- `type`: a function returning the GraphQL type
|
||||
- `defaultValue`: a default value; `any`
|
||||
- `description`: description metadata; `string`
|
||||
- `deprecationReason`: to deprecate a field and provide meta data describing why; `string`
|
||||
- `deprecationReason`: to deprecate a field and provide metadata describing why; `string`
|
||||
- `nullable`: whether the field is nullable
|
||||
|
||||
Query handler methods can take multiple arguments. Let's imagine that we want to fetch an author based on its `firstName` and `lastName`. In this case, we can call `@Args` twice:
|
||||
@@ -307,7 +307,7 @@ type Query {
|
||||
}
|
||||
```
|
||||
|
||||
> info **Hint** Note that arguments classes like `GetAuthorArgs` play very well with the `ValidationPipe` (read [more](/techniques/validation)).
|
||||
> info **Hint** Note that argument classes like `GetAuthorArgs` play very well with the `ValidationPipe` (read [more](/techniques/validation)).
|
||||
|
||||
#### Class inheritance
|
||||
|
||||
@@ -380,11 +380,11 @@ function BaseResolver<T extends Type<unknown>>(classRef: T): any {
|
||||
|
||||
Note the following:
|
||||
|
||||
- an explicit return type (`any` above) is required: otherwise TypeScript complains about the usage of a private class definition. Recommended: define an interface instead of using `any`.
|
||||
- An explicit return type (`any` above) is required; otherwise, TypeScript complains about the usage of a private class definition. Recommended: define an interface instead of using `any`.
|
||||
- `Type` is imported from the `@nestjs/common` package
|
||||
- The `isAbstract: true` property indicates that SDL (Schema Definition Language statements) shouldn't be generated for this class. Note, you can set this property for other types as well to suppress SDL generation.
|
||||
|
||||
Here's how you could generate a concrete sub-class of the `BaseResolver`:
|
||||
Here's how you could generate a concrete subclass of the `BaseResolver`:
|
||||
|
||||
```typescript
|
||||
@Resolver(() => Recipe)
|
||||
@@ -395,7 +395,7 @@ export class RecipesResolver extends BaseResolver(Recipe) {
|
||||
}
|
||||
```
|
||||
|
||||
This construct would generated the following SDL:
|
||||
This construct would generate the following SDL:
|
||||
|
||||
```graphql
|
||||
type Query {
|
||||
@@ -460,7 +460,7 @@ class PaginatedAuthor extends Paginated(Author) {}
|
||||
|
||||
#### Schema first
|
||||
|
||||
As mentioned in the [previous](/graphql/quick-start) chapter, in the schema first approach we start by manually defining schema types in SDL (read [more](https://graphql.org/learn/schema/#type-language)). Consider the following SDL type definitions.
|
||||
As mentioned in the [previous](/graphql/quick-start) chapter, in the schema-first approach, we start by manually defining schema types in SDL (read [more](https://graphql.org/learn/schema/#type-language)). Consider the following SDL type definitions.
|
||||
|
||||
> info **Hint** For convenience in this chapter, we've aggregated all of the SDL in one location (e.g., one `.graphql` file, as shown below). In practice, you may find it appropriate to organize your code in a modular fashion. For example, it can be helpful to create individual SDL files with type definitions representing each domain entity, along with related services, resolver code, and the Nest module definition class, in a dedicated directory for that entity. Nest will aggregate all the individual schema type definitions at run time.
|
||||
|
||||
@@ -579,7 +579,7 @@ export class AuthorsResolver {
|
||||
|
||||
#### Generating types
|
||||
|
||||
Assuming that we use the schema first approach and have enabled the typings generation feature (with `outputAs: 'class'` as shown in the [previous](/graphql/quick-start) chapter), once you run the application it will generate the following file (in the location you specified in the `GraphQLModule.forRoot()` method). For example, in `src/graphql.ts`:
|
||||
Assuming that we use the schema first approach and have enabled the typings generation feature (with `outputAs: 'class'` as shown in the [previous](/graphql/quick-start) chapter), once you run the application, it will generate the following file (in the location you specified in the `GraphQLModule.forRoot()` method). For example, in `src/graphql.ts`:
|
||||
|
||||
```typescript
|
||||
@@filename(graphql)
|
||||
|
||||
Reference in New Issue
Block a user