Skip to content

Commit 6feb438

Browse files
Merge pull request #1309 from nestjs/feat/new-openapi-category
feat(): extract openapi to its own category
2 parents a37129b + 5848feb commit 6feb438

25 files changed

+1177
-989
lines changed

content/cli/overview.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Read the sections on [Workspaces](/cli/monorepo) and [Libraries](/cli/libraries)
5858

5959
<app-banner-courses></app-banner-courses>
6060

61-
### CLI command syntax
61+
#### CLI command syntax
6262

6363
All `nest` commands follow the same format:
6464

@@ -80,7 +80,7 @@ $ nest n my-nest-project -d
8080

8181
Most commands, and some options, have aliases. Try running `nest new --help` to see these options and aliases, and to confirm your understanding of the above constructs.
8282

83-
### Command overview
83+
#### Command overview
8484

8585
Run `nest <command> --help` for any of the following commands to see command-specific options.
8686

content/openapi/cli-plugin.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
### Plugin
2+
3+
TypeScript's metadata reflection system has several limitations which make it impossible to, for instance, determine what properties a class consists of or recognize whether a given property is optional or required. However, some of these constraints can be addressed at compilation time. Nest provides a plugin that enhances the TypeScript compilation process to reduce the amount of boilerplate code required.
4+
5+
> warning **Hint** This plugin is **opt-in**. If you prefer, you can declare all decorators manually, or only specific decorators where you need them.
6+
7+
#### Overview
8+
9+
The Swagger plugin will automatically:
10+
11+
- annotate all DTO properties with `@ApiProperty` unless `@ApiHideProperty` is used
12+
- set the `required` property depending on the question mark (e.g. `name?: string` will set `required: false`)
13+
- set the `type` or `enum` property depending on the type (supports arrays as well)
14+
- set the `default` property based on the assigned default value
15+
- set several validation rules based on `class-validator` decorators (if `classValidatorShim` set to `true`)
16+
- add a response decorator to every endpoint with a proper status and `type` (response model)
17+
18+
Please, note that your filenames **must have** one of the following suffixes: `['.dto.ts', '.entity.ts']` (e.g., `create-user.dto.ts`) in order to be analysed by the plugin.
19+
20+
If you are using a different suffix, you can adjust the plugin's behavior by specifying the `dtoFileNameSuffix` option (see below).
21+
22+
Previously, if you wanted to provide an interactive experience with the Swagger UI,
23+
you had to duplicate a lot of code to let the package know how your models/components should be declared in the specification. For example, you could define a simple `CreateUserDto` class as follows:
24+
25+
```typescript
26+
export class CreateUserDto {
27+
@ApiProperty()
28+
email: string;
29+
30+
@ApiProperty()
31+
password: string;
32+
33+
@ApiProperty({ enum: RoleEnum, default: [], isArray: true })
34+
roles: RoleEnum[] = [];
35+
36+
@ApiProperty({ required: false, default: true })
37+
isEnabled?: boolean = true;
38+
}
39+
```
40+
41+
While not a significant issue with medium-sized projects, it becomes verbose & hard to maintain once you have a large set of classes.
42+
43+
By enabling the Swagger plugin, the above class definition can be declared simply:
44+
45+
```typescript
46+
export class CreateUserDto {
47+
email: string;
48+
password: string;
49+
roles: RoleEnum[] = [];
50+
isEnabled?: boolean = true;
51+
}
52+
```
53+
54+
The plugin adds appropriate decorators on the fly based on the **Abstract Syntax Tree**. Thus you won't have to struggle with `@ApiProperty` decorators scattered throughout the code.
55+
56+
> warning **Hint** The plugin will automatically generate any missing swagger properties, but if you need to override them, you simply set them explicitly via `@ApiProperty()`.
57+
58+
#### Using the CLI plugin
59+
60+
To enable the plugin, open `nest-cli.json` (if you use [Nest CLI](/cli/overview)) and add the following `plugins` configuration:
61+
62+
```javascript
63+
{
64+
"collection": "@nestjs/schematics",
65+
"sourceRoot": "src",
66+
"compilerOptions": {
67+
"plugins": ["@nestjs/swagger/plugin"]
68+
}
69+
}
70+
```
71+
72+
You can use the `options` property to customize the behavior of the plugin.
73+
74+
```javascript
75+
"plugins": [
76+
{
77+
"name": "@nestjs/swagger/plugin",
78+
"options": {
79+
"classValidatorShim": false
80+
}
81+
}
82+
]
83+
```
84+
85+
The `options` property has to fulfill the following interface:
86+
87+
```typescript
88+
export interface PluginOptions {
89+
dtoFileNameSuffix?: string[];
90+
controllerFileNameSuffix?: string[];
91+
classValidatorShim?: boolean;
92+
}
93+
```
94+
95+
<table>
96+
<tr>
97+
<th>Option</th>
98+
<th>Default</th>
99+
<th>Description</th>
100+
</tr>
101+
<tr>
102+
<td><code>dtoFileNameSuffix</code></td>
103+
<td><code>['.dto.ts', '.entity.ts']</code></td>
104+
<td>DTO (Data Transfer Object) files suffix</td>
105+
</tr>
106+
<tr>
107+
<td><code>controllerFileNameSuffix</code></td>
108+
<td><code>.controller.ts</code></td>
109+
<td>Controller files suffix</td>
110+
</tr>
111+
<tr>
112+
<td><code>classValidatorShim</code></td>
113+
<td><code>true</code></td>
114+
<td>If set to true, the module will reuse <code>class-validator</code> validation decorators (e.g. <code>@Max(10)</code> will add <code>max: 10</code> to schema definition) </td>
115+
</tr>
116+
</table>
117+
118+
If you don't use the CLI but instead have a custom `webpack` configuration, you can use this plugin in combination with `ts-loader`:
119+
120+
```javascript
121+
getCustomTransformers: (program: any) => ({
122+
before: [require('@nestjs/swagger/plugin').before({}, program)]
123+
}),
124+
```

content/openapi/decorators.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
### Decorators
2+
3+
All of the available OpenAPI decorators have an `Api` prefix to distinguish them from the core decorators. Below is a full list of the exported decorators along with a designation of the level at which the decorator may be applied.
4+
5+
| | |
6+
| ------------------------ | ------------------- |
7+
| `@ApiOperation()` | Method |
8+
| `@ApiResponse()` | Method / Controller |
9+
| `@ApiProduces()` | Method / Controller |
10+
| `@ApiConsumes()` | Method / Controller |
11+
| `@ApiBearerAuth()` | Method / Controller |
12+
| `@ApiOAuth2()` | Method / Controller |
13+
| `@ApiBasicAuth()` | Method / Controller |
14+
| `@ApiSecurity()` | Method / Controller |
15+
| `@ApiExtraModels()` | Method / Controller |
16+
| `@ApiBody()` | Method |
17+
| `@ApiParam()` | Method |
18+
| `@ApiQuery()` | Method |
19+
| `@ApiHeader()` | Method / Controller |
20+
| `@ApiExcludeEndpoint()` | Method |
21+
| `@ApiTags()` | Method / Controller |
22+
| `@ApiProperty()` | Model |
23+
| `@ApiPropertyOptional()` | Model |
24+
| `@ApiHideProperty()` | Model |
25+
| `@ApiExtension()` | Method |

content/openapi/introduction.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
### Introduction
2+
3+
The [OpenAPI](https://swagger.io/specification/) specification is a language-agnostic definition format used to describe RESTful APIs. Nest provides a dedicated [module](https://github.com/nestjs/swagger) which allows generating such a specification by leveraging decorators.
4+
5+
#### Installation
6+
7+
To begin using it, we first install the required dependencies.
8+
9+
```bash
10+
$ npm install --save @nestjs/swagger swagger-ui-express
11+
```
12+
13+
If you use fastify, install `fastify-swagger` instead of `swagger-ui-express`:
14+
15+
```bash
16+
$ npm install --save @nestjs/swagger fastify-swagger
17+
```
18+
19+
#### Bootstrap
20+
21+
Once the installation process is complete, open the `main.ts` file and initialize Swagger using the `SwaggerModule` class:
22+
23+
```typescript
24+
import { NestFactory } from '@nestjs/core';
25+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
26+
import { AppModule } from './app.module';
27+
28+
async function bootstrap() {
29+
const app = await NestFactory.create(AppModule);
30+
31+
const options = new DocumentBuilder()
32+
.setTitle('Cats example')
33+
.setDescription('The cats API description')
34+
.setVersion('1.0')
35+
.addTag('cats')
36+
.build();
37+
const document = SwaggerModule.createDocument(app, options);
38+
SwaggerModule.setup('api', app, document);
39+
40+
await app.listen(3000);
41+
}
42+
bootstrap();
43+
```
44+
45+
The `DocumentBuilder` helps to structure a base document that conforms to the OpenAPI Specification. It provides several methods that allow setting such properties as title, description, version, etc. In order to create a full document (with all HTTP routes defined) we use the `createDocument()` method of the `SwaggerModule` class. This method takes two arguments, an application instance and a Swagger options object.
46+
47+
Once we create a document, we can call the `setup()` method. It accepts:
48+
49+
1. the path to mount the Swagger UI
50+
2. an application instance
51+
3. the document object instantiated above
52+
53+
Now you can run the following command to start the HTTP server:
54+
55+
```bash
56+
$ npm run start
57+
```
58+
59+
While the application is running, open your browser and navigate to `http://localhost:3000/api`. You should see the Swagger UI.
60+
61+
<figure><img src="/assets/swagger1.png" /></figure>
62+
63+
The `SwaggerModule` automatically reflects all of your endpoints. Note that the Swagger UI is created using either `swagger-ui-express` or `fastify-swagger`, depending on the platform.
64+
65+
> info **Hint** To generate and download a Swagger JSON file, navigate to `http://localhost:3000/api-json` in your browser (assuming that your Swagger documentation is available under `http://localhost:3000/api`).
66+
67+
#### Example
68+
69+
A working example is available [here](https://github.com/nestjs/nest/tree/master/sample/11-swagger).

content/openapi/mapped-types.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
### Mapped types
2+
3+
As you build out features like **CRUD** (Create/Read/Update/Delete) it's often useful to construct variants on a base entity type. Nest provides several utility functions that perform type transformations to make this task more convenient.
4+
5+
#### Partial
6+
7+
When building input validation types (also called DTOs), it's often useful to build **create** and **update** variations on the same type. For example, the **create** variant may require all fields, while the **update** variant may make all fields optional.
8+
9+
Nest provides the `PartialType()` utility function to make this task easier and minimize boilerplate.
10+
11+
The `PartialType()` function returns a type (class) with all the properties of the input type set to optional. For example, suppose we have a **create** type as follows:
12+
13+
```typescript
14+
import { ApiProperty } from '@nestjs/swagger';
15+
16+
export class CreateCatDto {
17+
@ApiProperty()
18+
name: string;
19+
20+
@ApiProperty()
21+
age: number;
22+
23+
@ApiProperty()
24+
breed: string;
25+
}
26+
```
27+
28+
By default, all of these fields are required. To create a type with the same fields, but with each one optional, use `PartialType()` passing the class reference (`CreateCatDto`) as an argument:
29+
30+
```typescript
31+
export class UpdateCatDto extends PartialType(CreateCatDto) {}
32+
```
33+
34+
> info **Hint** The `PartialType()` function is imported from the `@nestjs/swagger` package.
35+
36+
#### Pick
37+
38+
The `PickType()` function constructs a new type (class) by picking a set of properties from an input type. For example, suppose we start with a type like:
39+
40+
```typescript
41+
import { ApiProperty } from '@nestjs/swagger';
42+
43+
export class CreateCatDto {
44+
@ApiProperty()
45+
name: string;
46+
47+
@ApiProperty()
48+
age: number;
49+
50+
@ApiProperty()
51+
breed: string;
52+
}
53+
```
54+
55+
We can pick a set of properties from this class using the `PickType()` utility function:
56+
57+
```typescript
58+
export class UpdateCatAgeDto extends PickType(CreateCatDto, ['age'] as const) {}
59+
```
60+
61+
> info **Hint** The `PickType()` function is imported from the `@nestjs/swagger` package.
62+
63+
#### Omit
64+
65+
The `OmitType()` function constructs a type by picking all properties from an input type and then removing a particular set of keys. For example, suppose we start with a type like:
66+
67+
```typescript
68+
import { ApiProperty } from '@nestjs/swagger';
69+
70+
export class CreateCatDto {
71+
@ApiProperty()
72+
name: string;
73+
74+
@ApiProperty()
75+
age: number;
76+
77+
@ApiProperty()
78+
breed: string;
79+
}
80+
```
81+
82+
We can generate a derived type that has every property **except** `name` as shown below. In this construct, the second argument to `OmitType` is an array of property names.
83+
84+
```typescript
85+
export class UpdateCatDto extends OmitType(CreateCatDto, ['name'] as const) {}
86+
```
87+
88+
> info **Hint** The `OmitType()` function is imported from the `@nestjs/swagger` package.
89+
90+
#### Intersection
91+
92+
The `IntersectionType()` function combines two types into one new type (class). For example, suppose we start with two types like:
93+
94+
```typescript
95+
import { ApiProperty } from '@nestjs/swagger';
96+
97+
export class CreateCatDto {
98+
@ApiProperty()
99+
name: string;
100+
101+
@ApiProperty()
102+
breed: string;
103+
}
104+
105+
export class AdditionalCatInfo {
106+
@ApiProperty()
107+
color: string;
108+
}
109+
```
110+
111+
We can generate a new type that combines all properties in both types.
112+
113+
```typescript
114+
export class UpdateCatDto extends IntersectionType(
115+
CreateCatDto,
116+
AdditionalCatInfo,
117+
) {}
118+
```
119+
120+
> info **Hint** The `IntersectionType()` function is imported from the `@nestjs/swagger` package.
121+
122+
#### Composition
123+
124+
The type mapping utility functions are composable. For example, the following will produce a type (class) that has all of the properties of the `CreateCatDto` type except for `name`, and those properties will be set to optional:
125+
126+
```typescript
127+
export class UpdateCatDto extends PartialType(
128+
OmitType(CreateCatDto, ['name'] as const),
129+
) {}
130+
```

0 commit comments

Comments
 (0)