- Introduced `@Pagination()` decorator to mark list endpoints for pagination.
- Added `TransformInterceptor` to wrap responses in a standardized format `{ data, meta }`.
- Created pagination-related utility functions and constants for managing pagination logic.
- Defined `PaginationQueryDto` for handling pagination query parameters.
- Established `PaginationMetaDto` for OpenAPI documentation of pagination metadata.
- Updated existing controller and service structures to support pagination in responses.
- Added unit tests for pagination utilities and interceptor to ensure correct functionality.
80 lines
2.7 KiB
Plaintext
80 lines
2.7 KiB
Plaintext
---
|
||
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<PaginationResponse<ShipmentDto>> {
|
||
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"]`)
|