| name | building-nestjs-controllers |
| description | Builds thin NestJS controllers that parse input, invoke a single use case, and map the Result to ApiResponse<T>. Use when adding HTTP endpoints, refactoring fat controllers, or applying API versioning. |
| license | MIT |
Building NestJS Controllers
When to use
- Adding HTTP endpoints
- Refactoring fat controllers
- Applying API versioning
Core rules
- Controllers are thin: only parse input, call one use-case, map Result to response
- No business logic in controllers
- Use
@Body() DTO validation with ValidationPipe
- Map
Result<T,E> to ApiResponse<T> via helper
- Use
@ApiTags(), @ApiOperation() for Swagger
Reference shape (TypeScript)
Thin Controller
@Controller('users')
@ApiTags('users')
export class UserController {
constructor(private readonly createUserUseCase: CreateUserUseCase) {}
@Post()
@ApiOperation({ summary: 'Create user' })
async create(@Body() dto: CreateUserDto): Promise<ApiResponse<User>> {
const result = await this.createUserUseCase.execute(dto);
return result.success
? { success: true, data: result.value }
: { success: false, error: { code: result.error.code, message: result.error.message } };
}
}
Examples — Do
@Get(':id')
async findOne(@Param('id') id: string): Promise<ApiResponse<User>> {
const result = await this.useCase.execute(id);
return result.success ? { success: true, data: result.value } : { success: false, error: ... };
}
Examples — Don't
@Post('order')
createOrder(@Body() body: any) {
if (body.items.length === 0) return { error: 'Empty' };
return this.db.save(body);
}
Checklist
See reference/controller-patterns.md for full patterns.