Skillshub nestjs-controllers-services
Controller/Service separation and Custom Decorators. Use when defining NestJS controllers, services, or custom parameter decorators. (triggers: **/*.controller.ts, **/*.service.ts, Controller, Injectable, ExecutionContext, createParamDecorator)
install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/HoangNguyen0403/agent-skills-standard/nestjs-controllers-services" ~/.claude/skills/comeonoliver-skillshub-nestjs-controllers-services && rm -rf "$T"
manifest:
skills/HoangNguyen0403/agent-skills-standard/nestjs-controllers-services/SKILL.mdsource content
NestJS Controllers & Services Standards
Priority: P0 (FOUNDATIONAL)
Layer separation standards and dependency injection patterns for NestJS applications.
Controllers
-
Role: Handler only. Delegate all logic to Services.
-
Context: Use
helpers (ExecutionContext
) for platform-agnostic code.switchToHttp() -
Custom Decorators:
- Avoid:
->@Request() req
(Not type-safe).req.user - Pattern: Create typed decorators like
,@CurrentUser()
.@DeviceIp()
import { RequestWithUser } from 'src/common/interfaces/request.interface'; export const CurrentUser = createParamDecorator( (data: unknown, ctx: ExecutionContext): User => { const request = ctx.switchToHttp().getRequest<RequestWithUser>(); return request.user; }, ); - Avoid:
DTOs & Validation
- Strictness:
: Strip properties without decorators.whitelist: true- Critical:
: Throw error if unknown properties exist.forbidNonWhitelisted: true
- Transformation:
: Auto-convert primitives (String '1' -> Number 1) and instantiate DTO classes.transform: true
- Documentation:
- Automation: Use the
CLI plugin (@nestjs/swagger
) to auto-detect DTO properties without manualnest-cli.json
tags.@ApiProperty()
- Automation: Use the
Interceptors (Response Mapping)
- Standardization: specific responses should be mapped in Interceptors, not Controllers.
- Use
to wrap success responses (e.g.map()
).{ data: T } - Refer to API Standards for
andPageDto
.ApiResponse - Use
to map low-level errors (DB constraints) tocatchError()
(e.g.HttpException
) before they hit the global filter.ConflictException
- Use
Services & Business Logic
- Singleton: Default.
- Stateless: Do not store request-specific state in class properties unless identifying as
.Scope.REQUEST
Pipes & Validation
- Global: Register
globally.ValidationPipe - Route Params: Fail fast. Always use
,ParseIntPipe
on all ID parameters.ParseUUIDPipe
@Get(':id') findOne(@Param('id', ParseIntPipe) id: number) { ... }
Lifecycle Events
- Init: Use
for connection setup.OnModuleInit - Destroy: Use
for cleanup. (RequiresOnApplicationShutdown
).enableShutdownHooks()
Anti-Patterns
- No business logic in controllers: Delegate everything to Services; controllers only parse and respond.
- No req.user access: Create typed
decorator instead of accessing raw@CurrentUser()
.req - No REQUEST scope by default: Use SINGLETON; it makes the entire injection chain request-scoped.