You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/openapi/operations.md
+44-56Lines changed: 44 additions & 56 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -153,26 +153,26 @@ To add an Extension to a request use the `@ApiExtension()` decorator. The extens
153
153
@ApiExtension('x-foo', { hello: 'world' })
154
154
```
155
155
156
-
#### Advanced: Generics ApiResponse
156
+
#### Advanced: Generic `ApiResponse`
157
157
158
-
With the ability to provide **Raw Definition**, we can provide **Generics** schema for SwaggerUI. Assume we have the following *generics DTO*
158
+
With the ability to provide [Raw Definitions](/openapi/types-and-parameters#raw-definitions), we can define Generic schema for Swagger UI. Assume we have the following DTO:
159
159
160
160
```ts
161
161
exportclassPaginatedDto<TData> {
162
162
@ApiProperty()
163
163
total:number;
164
-
164
+
165
165
@ApiProperty()
166
166
limit:number;
167
-
167
+
168
168
@ApiProperty()
169
169
offset:number;
170
-
170
+
171
171
results:TData[];
172
172
}
173
173
```
174
174
175
-
We skip decorating `results`because we will be providing **Raw Definition**for it later. Now, let's assume we have the following `CatDto`
175
+
We skip decorating `results`as we will be providing a raw definition for it later. Now, let's define another DTO and name it, for example, `CatDto`, as follows:
176
176
177
177
```ts
178
178
exportclassCatDto {
@@ -187,56 +187,44 @@ export class CatDto {
187
187
}
188
188
```
189
189
190
-
Now, we can start providing a `PaginatedDto<CatDto>`on `CatController`
190
+
With this in place, we can define a `PaginatedDto<CatDto>`response, as follows:
191
191
192
192
```ts
193
-
@Controller(...)
194
-
exportclassCatController {
195
-
196
-
@Get()
197
-
@ApiOkResponse({
198
-
schema: {
199
-
allOf: [
200
-
{ $ref: getSchemaPath(PaginatedDto) },
201
-
{
202
-
properties: {
203
-
results: {
204
-
type: 'array',
205
-
items: { $ref: getSchemaPath(CatDto) },
206
-
},
193
+
@ApiOkResponse({
194
+
schema: {
195
+
allOf: [
196
+
{ $ref: getSchemaPath(PaginatedDto) },
197
+
{
198
+
properties: {
199
+
results: {
200
+
type: 'array',
201
+
items: { $ref: getSchemaPath(CatDto) },
207
202
},
208
203
},
209
-
],
210
-
},
211
-
})
212
-
async get(...):Promise<PaginatedDto<CatDto>> {
213
-
...
214
-
}
215
-
}
204
+
},
205
+
],
206
+
},
207
+
})
208
+
asyncfindAll(): Promise<PaginatedDto<CatDto>> {}
216
209
```
217
210
218
-
We are not done. `PaginatedDto` isn't part of any controller by itself so `SwaggerModule` won't be able to scan it
219
-
during initialization. But, `nestjs/swagger` provides an `ApiExtraModels()` decorator for such cases.
211
+
In this example, we specify that the response will have allOf `PaginatedDto` and the `results` property will be of type `Array<CatDto>`.
212
+
213
+
-`getSchemaPath()` function that returns the OpenAPI Schema path from within the OpenAPI Spec File for a given model.
214
+
-`allOf` is a concept that OAS 3 provides to cover various Inheritance related use-cases.
215
+
216
+
Lastly, since `PaginatedDto` is not directly referenced by any controller, the `SwaggerModule` will not be able to generate a corresponding model definition just yet. In this case, we must add it as an [Extra Model](/openapi/types-and-parameters#extra-models). For example, we can use the `@ApiExtraModels()` decorator on the controller level, as follows:
220
217
221
218
```ts
222
-
@Controller(...)
219
+
@Controller('cats')
223
220
@ApiExtraModels(PaginatedDto)
224
-
exportclassCatController {
225
-
...
226
-
}
221
+
exportclassCatsController {}
227
222
```
228
223
229
-
> info **Hint** You only need to use `ApiExtraModels` for a specific `Dto` once so find a place where it makes sense for you to do so.
230
-
231
-
-`getSchemaPath()` returns the OpenAPI Schema path from within the OpenAPI Spec File that `ApiExtraModels` helps `nestjs/swagger` generates,
232
-
or `nestjs/swagger` is able to scan automatically.
233
-
-`allOf` is a concept that OpenAPI 3 has to cover Inheritance use-cases.
234
-
235
-
In this case, we tell SwaggerUI that this response will have **allOf**`PaginatedDto` and the `results` property will be of type array and each item will be of type `CatDto`.
236
-
If you run the SwaggerUI now, you'd see the generated `swagger.json` for this specific endpoint like the following:
224
+
If you run Swagger now, the generated `swagger.json` for this specific endpoint should have the followng response defined:
237
225
238
226
```json
239
-
responses": {
227
+
"responses": {
240
228
"200": {
241
229
"description": "",
242
230
"content": {
@@ -261,10 +249,12 @@ responses": {
261
249
}
262
250
```
263
251
264
-
Now that we know it works, we can create a custom decorator for `PaginatedDto` as follow:
252
+
To make it reusable, we can create a custom decorator for `PaginatedDto`, as follows:
then we can use `ApiPaginatedResponse` on our endpoint:
278
+
> info **Hint**`Type<any>` interface and `applyDecorators` function are imported from the `@nestjs/common` package.
279
+
280
+
With this in place, we can use the custom `@ApiPaginatedResponse()` decorator on our endpoint:
289
281
290
282
```ts
291
-
@Get()
292
283
@ApiPaginatedResponse(CatDto)
293
-
asyncget(): Promise<PaginatedDto<CatDto>> {}
284
+
asyncfindAll(): Promise<PaginatedDto<CatDto>> {}
294
285
```
295
286
296
-
You can modify `ApiPaginatedResponse` as you see fit, maybe make it more generics to handle non-array `results` or maybe different property name than `results`.
297
-
Knowing the capabilities of `nestjs/swagger` APIs, you can totally go wild with it and make sure your OpenAPI Spec is correct and covered.
287
+
For client generation tools, this approach poses an ambiguity in how the `PaginatedResponse<TModel>` is being generated for the client. The following snippet is an example of a client generator result for the above `GET /` endpoint.
298
288
299
-
For client generation tools, this approach poses an ambiguity in how this `PaginatedResponse<TModel>` is being generated for the client. The following snippet is an example of a client generator result of the above **GET** request:
As you can see, the **Return Type** here is ambiguous. To workaround this issue, you can add a `title` property to the `schema` for `ApiPaginatedResponse`:
To define additional models that should be inspected by the Swagger module, use the `@ApiExtraModels()` decorator:
242
+
To define additional models that are not directly referenced in your controllers but should be inspected by the Swagger module, use the `@ApiExtraModels()` decorator:
243
243
244
244
```typescript
245
245
@ApiExtraModels(ExtraModel)
246
246
export class CreateCatDto {}
247
247
```
248
248
249
-
Then, you can get the reference (`$ref`) to your model using `getSchemaPath(ExtraModel)`:
249
+
> info **Hint** You only need to use `@ApiExtraModels()` once for a specific model class.
250
+
251
+
Alternatively, you can pass an options object with the `extraModels` property specified to the `SwaggerModule#createDocument()` method, as follows:
0 commit comments