Motivation
Swagger decorators are documentation. They have nothing to do with routing, validation, or business rules, yet they still end up mixed into the same file.
The problem
Swagger decorators are documentation. They have nothing to do with routing, validation, or business rules, but they end up mixed into the same file, doubling the controller's size and burying the code that actually matters.
Before and after
users.controller.ts with Swagger decorators scattered throughout:
users.controller.ts
// users.controller.ts
@ApiTags("users")
@Controller("users")
export class UsersController {
@Get()
@ApiOperation({ summary: "List all users" })
@ApiResponse({ status: 200, description: "OK", type: [UserEntity] })
findAll(): Promise<UserEntity[]> {
return this.usersService.findAll();
}
@Post()
@ApiOperation({ summary: "Create a user" })
@ApiBody({ type: CreateUserDto })
@ApiResponse({ status: 201, description: "Created", type: UserEntity })
@ApiResponse({ status: 400, description: "Bad Request" })
create(@Body() dto: CreateUserDto): Promise<UserEntity> {
return this.usersService.create(dto);
}
}The convention
nestjs-docfy enforces a clean boundary: controllers express behavior, docs files express documentation. The convention (*.controller.docs.ts) mirrors how NestJS already organizes specs (*.controller.spec.ts), so it feels natural from day one.