--- description: NestJS OpenAPI/Swagger conventions for controllers and DTOs globs: "src/**/*.controller.ts,src/**/dto/**/*.ts,src/common/swagger/**/*.ts,src/main.ts,nest-cli.json" alwaysApply: false --- # NestJS Swagger Best Practices ## Controllers Document every HTTP handler: ```typescript @ApiTags('auth') @Controller('auth') export class AuthController { @Post('login') @ApiOperation({ summary: 'Log in' }) @ApiOkResponse({ type: TokenPairDto }) login(@Body() dto: LoginDto) { /* ... */ } @Get('me') @ApiBearerAuth('access-token') @ApiOkResponse({ type: MeResponseDto }) me(@CurrentUser() user: AuthUser) { /* ... */ } } ``` - Use `@ApiTags`, `@ApiOperation`, and typed `@ApiOkResponse` / `@ApiCreatedResponse` / `@ApiNoContentResponse` - Response types must be DTO **classes**, not interfaces or domain entities - Add `@ApiBearerAuth('access-token')` only on JWT-protected routes - Public (`@Public()`) routes must omit bearer auth - Document expected errors (`@ApiBadRequestResponse`, `@ApiUnauthorizedResponse`, etc.) when meaningful ### Paginated list endpoints - Mark with `@Pagination()`; document the **public** envelope `{ data, meta }`, not the handler’s `{ data, total }` - Use a response DTO class for list items plus `PaginationMetaDto` from `src/common/http/response/` - Detail / create / update / delete stay typed to the resource DTO (unwrapped) ```typescript @Get() @Pagination() @ApiOperation({ summary: 'List shipments' }) @ApiOkResponse({ schema: { properties: { data: { type: 'array', items: { $ref: '#/components/schemas/ShipmentDto' } }, meta: { $ref: '#/components/schemas/PaginationMetaDto' }, }, }, }) list(@Query() query: ListShipmentsQueryDto): Promise> { return this.service.list(query) } ``` ## DTOs - Request and response DTOs live under `dto/` - Never expose domain entities or sensitive fields (`passwordHash`, secrets) in OpenAPI - Nest CLI Swagger plugin is enabled — use `@ApiProperty` for examples, `format: 'password'`, `writeOnly`, not to restate every class-validator rule - Examples must be fake; never real tokens or secrets ```typescript // BAD — documents entity / real secret @ApiOkResponse({ type: User }) @ApiProperty({ example: process.env.JWT_ACCESS_SECRET }) // GOOD — response DTO + fake example @ApiOkResponse({ type: MeResponseDto }) @ApiProperty({ example: 'alice', format: 'password', writeOnly: true }) ``` ## Bootstrap - Mount UI at `/docs` and JSON at `/docs-json` only (via `setupSwagger` / `configureApp`) - Swagger is off when `NODE_ENV=production` unless `SWAGGER_ENABLED=true` - Keep the `@nestjs/swagger` plugin in `nest-cli.json` (`classValidatorShim`, `introspectComments`, `dtoFileNameSuffix: [".dto.ts"]`)