NestJS 的强约定性(Decorators、DI、Module)既是优点也是学习曲线。 Claude Code 能帮你快速理解和生成符合 NestJS 惯例的代码,避免踩坑。
CLAUDE.md NestJS 专项配置
markdown
# CLAUDE.md(NestJS 项目)
## 项目架构
src/
modules/ # 按业务领域划分模块
users/
users.module.ts
users.controller.ts
users.service.ts
dto/ # 请求/响应 DTO(用 class-validator 装饰)
entities/ # TypeORM 实体
common/
decorators/ # 自定义装饰器
filters/ # Exception Filters
guards/ # Guards(认证/授权)
interceptors/ # Interceptors(日志/缓存/变换)
pipes/ # 自定义 Pipes
## NestJS 约定
- Controller 只处理 HTTP 层(参数解析/响应格式化),不写业务逻辑
- 业务逻辑全在 Service 中
- 跨模块调用通过 Service 注入,不直接访问其他模块的 Repository
- DTO 必须用 class-validator 装饰,并在 ValidationPipe 中校验
- 所有 API 必须加 Swagger 装饰器
## 禁止
- 在 Controller 中直接调用 Repository/DB
- 跨模块直接引用 Entity(通过 Service 暴露接口)快速生成 CRUD 模块
你:为博客文章功能生成完整的 NestJS CRUD 模块,包含:
- Post 实体(id/title/content/authorId/createdAt)
- CreatePostDto / UpdatePostDto(含 class-validator 校验)
- PostsController(5个 CRUD 端点 + Swagger 装饰器)
- PostsService(业务逻辑)
- PostsModule(组装所有组件)
Claude:生成 5 个文件:
// posts/entities/post.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, ManyToOne } from 'typeorm';
@Entity('posts')
export class Post {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ length: 200 })
title: string;
@Column('text')
content: string;
@Column()
authorId: string;
@CreateDateColumn()
createdAt: Date;
}
// posts/dto/create-post.dto.ts
import { IsString, IsNotEmpty, MaxLength, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreatePostDto {
@ApiProperty({ description: '文章标题', example: '2026 年 AI 趋势' })
@IsString()
@IsNotEmpty()
@MaxLength(200)
@MinLength(1)
title: string;
@ApiProperty({ description: '文章正文(Markdown)' })
@IsString()
@IsNotEmpty()
content: string;
}
// posts/posts.controller.ts
import { Controller, Get, Post, Body, Patch, Param, Delete,
UseGuards, ParseUUIDPipe } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import { PostsService } from './posts.service';
import { CreatePostDto } from './dto/create-post.dto';
@ApiTags('文章')
@Controller('posts')
export class PostsController {
constructor(private readonly postsService: PostsService) {}
@Post()
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: '创建文章' })
create(@Body() dto: CreatePostDto, @CurrentUser() userId: string) {
return this.postsService.create(dto, userId);
}
@Get()
@ApiOperation({ summary: '获取文章列表' })
findAll() {
return this.postsService.findAll();
}
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.postsService.findOne(id);
}
@Patch(':id')
@UseGuards(JwtAuthGuard)
update(@Param('id', ParseUUIDPipe) id: string,
@Body() dto: UpdatePostDto,
@CurrentUser() userId: string) {
return this.postsService.update(id, dto, userId);
}
@Delete(':id')
@UseGuards(JwtAuthGuard)
remove(@Param('id', ParseUUIDPipe) id: string,
@CurrentUser() userId: string) {
return this.postsService.remove(id, userId);
}
}
JWT 认证 Guard
你:帮我实现 JWT 认证完整流程:
登录返回 accessToken + refreshToken、
JwtAuthGuard 自动验证 Bearer Token、
CurrentUser 装饰器注入当前用户
Claude:
// common/guards/jwt-auth.guard.ts
import { Injectable, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
handleRequest(err, user) {
if (err || !user) throw new UnauthorizedException('Token 无效或已过期');
return user;
}
}
// common/decorators/current-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data: string | undefined, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return data ? request.user?.[data] : request.user?.id;
},
);
全局 Interceptor:统一响应格式
typescript
// common/interceptors/transform.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(data => ({
code: 0,
data,
message: 'success',
timestamp: new Date().toISOString(),
}))
);
}
}
// main.ts 全局注册
app.useGlobalInterceptors(new TransformInterceptor());
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
app.useGlobalFilters(new HttpExceptionFilter());Swagger 文档自动生成
typescript
// main.ts
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
const config = new DocumentBuilder()
.setTitle('My API')
.setDescription('API 文档')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);
// 访问 http://localhost:3000/api/docs 查看 Swagger UI你:检查所有 Controller,补全缺失的 Swagger 装饰器:
@ApiOperation、@ApiResponse、@ApiBody、@ApiParam
Claude:扫描所有 Controller 文件,为缺少 Swagger 注释的端点逐一补全
来源:Claude Code 官方文档 - docs.anthropic.com/en/docs/claude-code