Loading...
Loading...
Provides comprehensive code review capability for NestJS applications, analyzing controllers, services, modules, guards, interceptors, pipes, dependency injection, and database integration patterns. Use when reviewing NestJS code changes, before merging pull requests, after implementing new features, or for architecture validation. Triggers on "review NestJS code", "NestJS code review", "check my NestJS controller/service".
npx skill4agent add giuseppe-trisciuoglio/developer-kit nestjs-code-reviewnestjs-code-review-expert@Controller@Injectable@Moduleglobgrep// ❌ Bad: Fat controller with business logic and missing validation
@Controller('users')
export class UserController {
constructor(private readonly userRepo: Repository<User>) {}
@Post()
async create(@Body() body: any) {
const user = this.userRepo.create(body);
return this.userRepo.save(user);
}
}
// ✅ Good: Thin controller with proper DTOs, validation, and service delegation
@Controller('users')
@ApiTags('Users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: 'Create a new user' })
@ApiResponse({ status: 201, type: UserResponseDto })
async create(
@Body(ValidationPipe) createUserDto: CreateUserDto,
): Promise<UserResponseDto> {
return this.userService.create(createUserDto);
}
}// ❌ Bad: Direct instantiation bypasses DI
@Injectable()
export class OrderService {
private readonly logger = new Logger();
private readonly emailService = new EmailService();
async createOrder(dto: CreateOrderDto) {
this.emailService.send(dto.email, 'Order created');
}
}
// ✅ Good: Proper constructor injection
@Injectable()
export class OrderService {
private readonly logger = new Logger(OrderService.name);
constructor(
private readonly orderRepository: OrderRepository,
private readonly emailService: EmailService,
) {}
async createOrder(dto: CreateOrderDto): Promise<Order> {
const order = await this.orderRepository.create(dto);
await this.emailService.send(dto.email, 'Order created');
return order;
}
}// ❌ Bad: Generic error handling with information leakage
@Get(':id')
async findOne(@Param('id') id: string) {
try {
return await this.service.findOne(id);
} catch (error) {
throw new HttpException(error.message, 500);
}
}
// ✅ Good: Domain-specific exceptions with proper HTTP mapping
@Get(':id')
async findOne(@Param('id', ParseUUIDPipe) id: string): Promise<UserResponseDto> {
const user = await this.userService.findOne(id);
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}// ❌ Bad: Authorization logic in controller
@Get('admin/dashboard')
async getDashboard(@Req() req: Request) {
if (req.user.role !== 'admin') {
throw new ForbiddenException();
}
return this.dashboardService.getData();
}
// ✅ Good: Guard-based authorization with decorator
@Get('admin/dashboard')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
async getDashboard(): Promise<DashboardDto> {
return this.dashboardService.getData();
}// ❌ Bad: Monolithic module with everything
@Module({
imports: [TypeOrmModule.forFeature([User, Order, Product, Review])],
controllers: [UserController, OrderController, ProductController],
providers: [UserService, OrderService, ProductService, ReviewService],
})
export class AppModule {}
// ✅ Good: Feature-based module organization
@Module({
imports: [UserModule, OrderModule, ProductModule],
})
export class AppModule {}
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService, UserRepository],
exports: [UserService],
})
export class UserModule {}ParseUUIDPipeParseIntPipeHttpExceptionnew@ApiTags@ApiOperation@ApiResponsereferences/references/patterns.mdreferences/anti-patterns.mdreferences/checklist.md