mcpField
N
nestjs-expert

nestjs-expert

github.com/jeffallan开发12.1k6.0k 次安装今天更新
代码仓库

关于 nestjs-expert

面向 TypeScript 后端开发者的 NestJS 开发技能,适用于构建结构化、可扩展的应用。它指导模块设计与实现,并着重处理依赖注入、验证、安全、文档和测试。

主要功能

  1. 01规划模块及模块间依赖
  2. 02构建控制器、服务和模块
  3. 03验证 DTO 并保护端点
  4. 04使用 Swagger 装饰器记录 API
  5. 05编写单元和端到端测试

适用场景

  1. 01设计新的 NestJS 后端功能
  2. 02添加经过验证和身份验证的端点
  3. 03测试服务和控制器
  4. 04迁移 Express.js 应用

安装

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

$npx skills add https://github.com/jeffallan/claude-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: '<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 功能时,按以下顺序提供:

  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、守卫、拦截器、管道、过滤器

由 @jeffallan 维护,他是 Synergetic Solutions 的首席顾问。

文档

评论

支持 Markdown