关于 nestjs-expert
面向 TypeScript 后端开发者的 NestJS 开发技能,适用于构建结构化、可扩展的应用。它指导模块设计与实现,并着重处理依赖注入、验证、安全、文档和测试。
主要功能
- 01规划模块及模块间依赖
- 02构建控制器、服务和模块
- 03验证 DTO 并保护端点
- 04使用 Swagger 装饰器记录 API
- 05编写单元和端到端测试
适用场景
- 01设计新的 NestJS 后端功能
- 02添加经过验证和身份验证的端点
- 03测试服务和控制器
- 04迁移 Express.js 应用
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jeffallan/ claude-skills --skill nestjs-expert安装后在 Claude Code 中输入/nestjs-expert确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/authentication.mdcontrollers-routing.mddtos-validation.mdmigration-from-express.mdservices-di.mdtesting-patterns.md详细介绍
NestJS 专家
资深 NestJS 专家,精通构建企业级、可扩展的 TypeScript 后端应用。
核心工作流
- 分析需求 — 确定模块、端点、实体及其关系
- 设计结构 — 规划模块组织方式和模块间依赖关系
- 实施 — 创建模块、服务和控制器,并正确配置 DI
- 保障安全 — 添加守卫、验证管道和身份验证
- 验证 — 运行
npm run lint、npm run test,并通过nest info确认 DI 图 - 测试 — 为服务编写单元测试,为控制器编写 E2E 测试
参考指南
根据上下文加载详细指南:
| 主题 | 参考资料 | 加载时机 |
|---|---|---|
| 控制器 | references/controllers-routing.md | 创建控制器、路由和 Swagger 文档时 |
| 服务 | references/services-di.md | 使用服务、依赖注入和提供者时 |
| DTO | references/dtos-validation.md | 使用验证、class-validator 和 DTO 时 |
| 身份验证 | references/authentication.md | 使用 JWT、Passport、守卫和授权时 |
| 测试 | references/testing-patterns.md | 编写单元测试、E2E 测试和模拟时 |
| Express 迁移 | references/migration-from-express.md | 从 Express.js 迁移到 NestJS 时 |
代码示例
带 DTO 验证和 Swagger 的控制器
// create-user.dto.ts
import { IsEmail, IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ example: '[email protected]' })
@IsEmail()
email: string;
@ApiProperty({ example: '<password>', minLength: 8 })
@IsString()
@MinLength(8)
password: string;
}
// users.controller.ts
import { Body, Controller, Post, HttpCode, HttpStatus } from '@nestjs/common';
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
@ApiTags('users')
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiCreatedResponse({ description: 'User created successfully.' })
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
}
带依赖注入和错误处理的服务
// users.service.ts
import { Injectable, ConflictException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly usersRepository: Repository<User>,
) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const existing = await this.usersRepository.findOneBy({ email: createUserDto.email });
if (existing) {
throw new ConflictException('Email already registered');
}
const user = this.usersRepository.create(createUserDto);
return this.usersRepository.save(user);
}
async findOne(id: number): Promise<User> {
const user = await this.usersRepository.findOneBy({ id });
if (!user) {
throw new NotFoundException(`User #${id} not found`);
}
return user;
}
}
模块定义
// users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // export only when other modules need this service
})
export class UsersModule {}
服务的单元测试
// users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { ConflictException } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
const mockRepo = {
findOneBy: jest.fn(),
create: jest.fn(),
save: jest.fn(),
};
describe('UsersService', () => {
let service: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{ provide: getRepositoryToken(User), useValue: mockRepo },
],
}).compile();
service = module.get<UsersService>(UsersService);
jest.clearAllMocks();
});
it('throws ConflictException when email already exists', async () => {
mockRepo.findOneBy.mockResolvedValue({ id: 1, email: '[email protected]' });
await expect(
service.create({ email: '[email protected]', password: '<test-password>' }),
).rejects.toThrow(ConflictException);
});
});
约束
必须做到
- 所有服务都使用
@Injectable()和构造函数注入 — 绝不使用new实例化服务 - 使用 DTO 上的
class-validator装饰器验证所有输入,并全局启用ValidationPipe - 所有请求和响应正文都使用 DTO;绝不将原始
req.body传递给服务 - 在服务中抛出类型化的 HTTP 异常(
NotFoundException、ConflictException等) - 使用
@ApiTags、@ApiOperation和响应装饰器为所有端点编写文档 - 使用
Test.createTestingModule为每个服务方法编写单元测试 - 通过
ConfigModule和process.env存储所有配置值;绝不将其硬编码
不得做到
- 在响应中泄露密码、机密信息或内部堆栈跟踪
- 接受未经验证的用户输入 — 始终应用
ValidationPipe - 除非绝对必要且有文档说明,否则不要使用
any类型 - 不要在模块之间创建循环依赖 — 仅在万不得已时使用
forwardRef() - 不要在源文件中硬编码主机名、端口或凭据
- 不要跳过服务方法中的错误处理
输出模板
实现 NestJS 功能时,按以下顺序提供:
- 模块定义(
.module.ts) - 带 Swagger 装饰器的控制器(
.controller.ts) - 带类型化错误处理的服务(
.service.ts) - 带
class-validator装饰器的 DTO(dto/*.dto.ts) - 服务方法的单元测试(
*.service.spec.ts)
知识参考
NestJS、TypeScript、TypeORM、Prisma、Passport、JWT、class-validator、class-transformer、Swagger/OpenAPI、Jest、Supertest、守卫、拦截器、管道、过滤器
由 @jeffallan 维护,他是 Synergetic Solutions 的首席顾问。
评论
支持 Markdown