with one click
building-nestjs-controllers
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.
Menu
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.
Defines the rule base every skill in this pack obeys: file layout, frontmatter, vocabulary, OOP/typing/decoupling axioms, and anti-patterns. Load FIRST before authoring or applying any other skill in this pack.
Designs NestJS feature modules with clean dependency boundaries, provider scopes, and dynamic modules. Use when adding a new feature module, splitting a monolithic AppModule, or fixing tangled imports between modules.
Prepares a NestJS service for production: graceful shutdown, health/readiness, structured logs, config, Dockerfile, CI gates, and rollout safety. Use when promoting a service to staging/production or auditing readiness.
Designs NestJS application services as use-case classes that orchestrate domain logic and ports without leaking the framework. Use when creating new use cases, refactoring services that mix HTTP/DB/domain, or moving from anemic services to OOP.
Maps internal AppError hierarchy to HTTP responses through a single global exception filter and a Result-to-HttpException helper. Use when adding new error types, fixing inconsistent error responses, or removing scattered try/catch in controllers.
Implements the Repository pattern with TypeORM in NestJS so domain entities stay framework-free, ORM models live in infrastructure, and transactions are explicit. Use when adding persistence, refactoring leaky ORM usage, or handling transactions across aggregates.
| 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 |
@Body() DTO validation with ValidationPipeResult<T,E> to ApiResponse<T> via helper@ApiTags(), @ApiOperation() for Swagger@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 } };
}
}
// Controller delegates to use-case
@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: ... };
}
// ❌ Business logic in controller
@Post('order')
createOrder(@Body() body: any) {
if (body.items.length === 0) return { error: 'Empty' }; // No!
return this.db.save(body);
}
See reference/controller-patterns.md for full patterns.