nestjs
Node.js/TypeScript backend framework with dependency injection and modular architecture
What this skill does
# NestJS Framework Skill
## Quick Reference
**When to Use**: Building scalable Node.js/TypeScript backend applications with modular architecture
**Core Strengths**: Dependency injection, modular design, enterprise patterns, comprehensive testing
**Target Coverage**: Services ≥80%, Controllers ≥70%, E2E ≥60%, Overall ≥75%
## Essential Patterns
### Module Architecture
```typescript
// users/users.module.ts
@Module({
imports: [TypeOrmModule.forFeature([User]), AuthModule],
controllers: [UserController],
providers: [
UserService,
UserRepository,
{ provide: 'USER_REPOSITORY', useClass: UserRepository },
],
exports: [UserService],
})
export class UsersModule {}
```
**Key Principles**:
- Clear module boundaries and responsibilities
- Export only what other modules need
- Import shared modules (AuthModule, DatabaseModule)
- Use token-based providers for abstraction
### Dependency Injection
```typescript
// users/services/user.service.ts
@Injectable()
export class UserService {
constructor(
@Inject('USER_REPOSITORY') private readonly userRepository: UserRepository,
private readonly hashingService: HashingService,
private readonly eventEmitter: EventEmitter2,
) {}
async createUser(dto: CreateUserDto): Promise<User> {
const hashedPassword = await this.hashingService.hash(dto.password);
const user = await this.userRepository.create({
...dto,
password: hashedPassword,
});
this.eventEmitter.emit('user.created', user);
return user;
}
}
```
**Best Practices**:
- Use constructor injection for all dependencies
- Inject interfaces/tokens, not concrete implementations
- Keep services focused on single responsibility
- Emit events for cross-cutting concerns
### DTO Validation
```typescript
// users/dto/create-user.dto.ts
export class CreateUserDto {
@ApiProperty({ example: '[email protected]' })
@IsEmail({}, { message: 'Invalid email format' })
email: string;
@ApiProperty({ example: 'StrongP@ss123', minLength: 8 })
@IsString()
@MinLength(8)
@Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/, {
message: 'Password must contain uppercase, lowercase, number, symbol'
})
password: string;
@ApiProperty({ example: 'John Doe', required: false })
@IsOptional()
@MaxLength(100)
name?: string;
}
```
**Validation Rules**:
- All inputs validated with class-validator decorators
- API documentation via @ApiProperty
- Custom error messages for user clarity
- Optional fields with @IsOptional()
### Repository Pattern
```typescript
// users/repositories/user.repository.ts
@Injectable()
export class UserRepository {
constructor(
@InjectRepository(User) private readonly repository: Repository<User>
) {}
async findByEmail(email: string): Promise<User | null> {
return this.repository.findOne({ where: { email } });
}
async findById(id: number): Promise<User> {
const user = await this.repository.findOne({ where: { id } });
if (!user) throw new NotFoundException('User not found');
return user;
}
async create(data: Partial<User>): Promise<User> {
const user = this.repository.create(data);
return this.repository.save(user);
}
}
```
**Repository Guidelines**:
- Encapsulate all database operations
- Throw domain-specific exceptions
- Use TypeORM query builder for complex queries
- Keep repositories focused on data access only
### Controller Best Practices
```typescript
// users/controllers/user.controller.ts
@ApiTags('users')
@Controller('users')
@UseInterceptors(ClassSerializerInterceptor)
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: 'Create new user' })
@ApiResponse({ status: 201, type: UserResponseDto })
@ApiResponse({ status: 400, description: 'Validation failed' })
async create(
@Body(ValidationPipe) dto: CreateUserDto
): Promise<UserResponseDto> {
const user = await this.userService.create(dto);
return plainToInstance(UserResponseDto, user);
}
@Get(':id')
@UseGuards(JwtAuthGuard)
@ApiParam({ name: 'id', type: 'number' })
async findOne(
@Param('id', ParseIntPipe) id: number
): Promise<UserResponseDto> {
const user = await this.userService.findById(id);
return plainToInstance(UserResponseDto, user);
}
}
```
**Controller Checklist**:
- [ ] @ApiTags for logical grouping
- [ ] @ApiOperation for endpoint description
- [ ] @ApiResponse for status codes + types
- [ ] ValidationPipe for DTO validation
- [ ] Guards for authentication/authorization
- [ ] Transform responses with DTOs
### Authentication & Authorization
```typescript
// auth/guards/jwt-auth.guard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
handleRequest(err, user, info) {
if (err || !user) {
throw new UnauthorizedException('Invalid or expired token');
}
return user;
}
}
// auth/guards/roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<Role[]>('roles', context.getHandler());
if (!requiredRoles) return true;
const request = context.switchToHttp().getRequest();
const user = request.user;
return requiredRoles.some(role => user.roles?.includes(role));
}
}
// Usage in controller
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
@Delete(':id')
async delete(@Param('id') id: number): Promise<void> {
await this.userService.delete(id);
}
```
**Auth Patterns**:
- JWT strategy with Passport.js
- Role-based access control with custom decorators
- Guard composition for complex rules
- Secure password hashing (bcrypt, argon2)
### Exception Handling
```typescript
// common/filters/http-exception.filter.ts
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const exceptionResponse = exception.getResponse();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: ctx.getRequest().url,
message: typeof exceptionResponse === 'string'
? exceptionResponse
: (exceptionResponse as any).message,
});
}
}
// Usage in main.ts
app.useGlobalFilters(new HttpExceptionFilter());
```
**Error Strategy**:
- Global exception filter for consistency
- Domain-specific exceptions (UserNotFoundException)
- Include correlation IDs for debugging
- Log errors with appropriate severity
### Testing
```typescript
// users/services/user.service.spec.ts
describe('UserService', () => {
let service: UserService;
let repository: MockType<UserRepository>;
let hashingService: MockType<HashingService>;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
UserService,
{
provide: 'USER_REPOSITORY',
useFactory: mockRepository,
},
{
provide: HashingService,
useFactory: mockHashingService,
},
],
}).compile();
service = module.get<UserService>(UserService);
repository = module.get('USER_REPOSITORY');
hashingService = module.get(HashingService);
});
describe('createUser', () => {
it('should hash password and create user', async () => {
const dto = { email: '[email protected]', password: 'Pass123!' };
const hashedPassword = 'hashed_password';
hashingService.hash.mockResolvedValue(hashedPassword);
repository.findByEmail.mockResolvedValue(null);
repository.create.mockResolvedValue({ id: 1, ...dto, password: hashedPassword });
const result = await service.createUser(dto);
expect(hashingService.hash).toHaveBeenCalRelated in backend
NestJS Framework
IncludedNode.js/TypeScript backend framework with dependency injection and modular architecture
Supabase Developer
IncludedBuild full-stack applications with Supabase (PostgreSQL, Auth, Storage, Real-time, Edge Functions). Use when implementing authentication, database design with RLS, file storage, real-time features, or serverless functions.
expressjs-development
IncludedComprehensive Express.js development skill covering routing, middleware, request/response handling, error handling, and building production-ready REST APIs
nodejs-development
IncludedComprehensive Node.js development skill covering event loop, async patterns, streams, file system, HTTP servers, process management, and modern Node.js best practices
spring-boot-development
IncludedComprehensive Spring Boot development skill covering auto-configuration, dependency injection, REST APIs, Spring Data, security, and enterprise Java applications