mcpField
N
nestjs-expert

nestjs-expert

github.com/farmage开发224290 次安装5 周前更新
代码仓库

关于 nestjs-expert

面向 NestJS 开发的专业技能指南,涵盖 TypeScript 后端应用的架构、实现、安全与测试,并提供按主题加载的参考资料。

主要功能

  1. 01模块与依赖结构设计
  2. 02控制器、服务和 DTO 实现
  3. 03输入验证与认证安全
  4. 04单元及端到端测试
  5. 05按主题查阅参考指南

适用场景

  1. 01规划 NestJS 应用模块
  2. 02实现带验证的 API 端点
  3. 03为服务和控制器编写测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/farmage/opencode-skills --skill nestjs-expert

安装后在 Claude Code 中输入/nestjs-expert确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
authentication.md
controllers-routing.md
dtos-validation.md
migration-from-express.md
services-di.md
testing-patterns.md

详细介绍

NestJS 专家

资深 NestJS 专家,精通企业级、可扩展的 TypeScript 后端应用。

核心工作流

  1. 分析需求 — 确定模块、端点、实体及其关系
  2. 设计结构 — 规划模块组织方式和模块间依赖
  3. 实现 — 创建模块、服务和控制器,并正确配置 DI
  4. 安全保障 — 添加守卫、验证管道和身份验证
  5. 验证 — 运行 npm run lint、npm run test,并使用 nest info 确认 DI 图
  6. 测试 — 为服务编写单元测试,为控制器编写 E2E 测试

参考指南

根据上下文加载详细指南:

主题参考文档加载时机
控制器references/controllers-routing.md创建控制器、配置路由、编写 Swagger 文档时
服务references/services-di.md使用服务、依赖注入和提供者时
DTOreferences/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: 'strongPassword123', 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: 'pass1234' }),
    ).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 功能时,按以下顺序提供:

  1. 模块定义(.module.ts)
  2. 带 Swagger 装饰器的控制器(.controller.ts)
  3. 带类型化错误处理的服务(.service.ts)
  4. 带 class-validator 装饰器的 DTO(dto/*.dto.ts)
  5. 服务方法的单元测试(*.service.spec.ts)

知识参考

NestJS、TypeScript、TypeORM、Prisma、Passport、JWT、class-validator、class-transformer、Swagger/OpenAPI、Jest、Supertest、守卫、拦截器、管道、过滤器

文档

评论

支持 Markdown