nestjs-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNestJS 11 Best Practices
NestJS 11 最佳实践
Quick Reference
快速参考
| Topic | When to Use | Reference |
|---|---|---|
| Core Architecture | Modules, Providers, DI, forwardRef, custom decorators | core-architecture.md |
| Request Lifecycle | Middleware, Guards, Interceptors, Pipes, Filters | request-lifecycle.md |
| Validation & Pipes | DTOs, class-validator, ValidationPipe, transforms | validation-pipes.md |
| Authentication | JWT, Passport, Guards, Local/OAuth strategies, RBAC | authentication.md |
| Database | TypeORM, Prisma, Drizzle ORM, repository patterns | database-integration.md |
| Testing | Unit tests, E2E tests, mocking providers | testing.md |
| OpenAPI & GraphQL | Swagger decorators, resolvers, subscriptions | openapi-graphql.md |
| Microservices | TCP, Redis, NATS, Kafka patterns | microservices.md |
| 主题 | 使用场景 | 参考文档 |
|---|---|---|
| 核心架构 | 模块、提供者、依赖注入、forwardRef、自定义装饰器 | core-architecture.md |
| 请求生命周期 | 中间件、守卫、拦截器、管道、过滤器 | request-lifecycle.md |
| 验证与管道 | DTO、class-validator、ValidationPipe、转换逻辑 | validation-pipes.md |
| 身份认证 | JWT、Passport、守卫、本地/OAuth策略、RBAC | authentication.md |
| 数据库集成 | TypeORM、Prisma、Drizzle ORM、仓库模式 | database-integration.md |
| 测试 | 单元测试、E2E测试、提供者模拟 | testing.md |
| OpenAPI与GraphQL | Swagger装饰器、解析器、订阅 | openapi-graphql.md |
| 微服务 | TCP、Redis、NATS、Kafka模式 | microservices.md |
Essential Patterns
核心模式
Module with Providers
包含提供者的模块
typescript
@Module({
imports: [DatabaseModule],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Export for other modules
})
export class UsersModule {}typescript
@Module({
imports: [DatabaseModule],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Export for other modules
})
export class UsersModule {}Controller with Validation
带验证的控制器
typescript
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
}typescript
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
}DTO with Validation
带验证的DTO
typescript
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsString()
name?: string;
}typescript
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsString()
name?: string;
}Exception Filter
异常过滤器
typescript
@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();
response.status(status).json({
statusCode: status,
message: exception.message,
timestamp: new Date().toISOString(),
});
}
}typescript
@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();
response.status(status).json({
statusCode: status,
message: exception.message,
timestamp: new Date().toISOString(),
});
}
}Guard with JWT
基于JWT的守卫
typescript
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
}typescript
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
}NestJS 11 Breaking Changes
NestJS 11 破坏性变更
- Express v5: Wildcards must be named (e.g., ), optional params use braces
*splat/:file{.:ext} - Node.js 20+: Minimum required version
- Fastify v5: Updated adapter for Fastify users
- Dynamic Modules: Same module with identical config imported multiple times = separate instances
- Express v5:通配符必须命名(例如),可选参数使用大括号
*splat/:file{.:ext} - Node.js 20+:最低要求版本
- Fastify v5:为Fastify用户更新了适配器
- 动态模块:多次导入配置相同的同一模块会生成独立实例
Common Mistakes
常见错误
- Not using for circular deps - Causes "cannot resolve dependency" errors; wrap in
forwardRef()forwardRef(() => ModuleName) - Throwing plain errors instead of HttpException - Loses status codes, breaks exception filters; use
throw new BadRequestException('message') - Missing decorator - Provider won't be injectable; always decorate services
@Injectable() - Global ValidationPipe without - Allows unexpected properties; set
whitelist: truewhitelist: true, forbidNonWhitelisted: true - Importing modules instead of exporting providers - Use array to share providers across modules
exports - Async config without - ConfigService undefined; import ConfigModule in AppModule
ConfigModule.forRoot() - Testing without - Uses real services in unit tests; mock dependencies with
overrideProvider()overrideProvider(Service).useValue(mock) - E2E tests sharing database state - No isolation between tests; use transactions or truncate tables in beforeEach
- 未使用处理循环依赖 - 会导致“无法解析依赖”错误;需用
forwardRef()包裹forwardRef(() => ModuleName) - 抛出普通错误而非HttpException - 丢失状态码,破坏异常过滤器;请使用
throw new BadRequestException('message') - 缺少装饰器 - 提供者无法被注入;务必为服务添加该装饰器
@Injectable() - 全局ValidationPipe未设置- 允许意外属性传入;需设置
whitelist: truewhitelist: true, forbidNonWhitelisted: true - 导入模块而非导出提供者 - 使用数组在模块间共享提供者
exports - 异步配置未使用- 会导致ConfigService未定义;在AppModule中导入ConfigModule
ConfigModule.forRoot() - 测试时未使用- 单元测试中使用真实服务;用
overrideProvider()模拟依赖overrideProvider(Service).useValue(mock) - E2E测试共享数据库状态 - 测试间无隔离;在beforeEach中使用事务或清空表数据