mcpField
A
api-framework-nestjs

api-framework-nestjs

github.com/agents-inc开发2642 次安装2 天前更新
代码仓库

关于 api-framework-nestjs

面向使用 TypeScript 构建 Node.js 后端的开发者,介绍 NestJS 的模块化架构与依赖注入实践。指南涵盖路由、DTO 校验、异常处理及请求生命周期各层的职责划分。

主要功能

  1. 01按功能组织模块
  2. 02控制器与服务分层
  3. 03DTO 与声明式请求校验
  4. 04依赖注入与自定义提供者
  5. 05守卫、拦截器、管道和过滤器

适用场景

  1. 01构建结构清晰的 REST API
  2. 02为请求体和参数定义校验规则
  3. 03实现认证与基于角色的访问控制
  4. 04编排日志、响应转换和异常处理

安装

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

$npx skills add https://github.com/agents-inc/skills --skill api-framework-nestjs

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

包含的文件

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

metadata.yaml
reference.md
examples/
advanced.md
auth.md
core.md
database.md
testing.md

详细介绍

NestJS 模式

**快速指南:**NestJS 是一个基于 TypeScript 构建、具有明确约定的模块化 Node.js 框架。使用模块组织功能,使用控制器处理 HTTP 路由,使用服务配合依赖注入处理业务逻辑,使用带有 class-validator 的 DTO 进行验证,使用守卫进行身份验证,使用异常筛选器处理错误。需要特别注意:始终在模块的 providers 中注册服务,始终全局启用 ValidationPipe 并设置 whitelist: true,绝不要将业务逻辑放在控制器中,也绝不要使用 new 实例化服务。NestJS 11 是当前稳定版本(可选择启用 SWC 编译器、Express v5,终止钩子顺序已反转)。


<critical_requirements>

重要:使用此技能前

(每个服务都必须使用 @Injectable(),并将其注册在模块的 providers 数组中)

(必须全局启用 ValidationPipe,并设置 whitelist: true 和 forbidNonWhitelisted: true)

(所有请求正文验证都必须使用带有 class-validator 装饰器的 DTO——绝不要在控制器中手动验证)

(必须抛出 NestJS 内置 HTTP 异常(NotFoundException、BadRequestException 等)——绝不要直接发送状态码)

(依赖项必须使用构造函数注入——绝不要使用 new 手动实例化服务)

</critical_requirements>


**自动检测:**NestJS、@nestjs/common、@nestjs/core、@Module、@Controller、@Injectable、@Get、@Post、@Body、@Param、@Query、@UseGuards、@UseInterceptors、@UsePipes、@UseFilters、CanActivate、NestInterceptor、PipeTransform、ExceptionFilter、ValidationPipe、class-validator、class-transformer

适用场景:

  • 使用 TypeScript 和依赖注入构建结构清晰的后端 API
  • 需要采用模块化架构并明确划分职责的应用程序
  • 需要声明式验证、身份验证和基于角色的访问控制的 REST API
  • 需要使用守卫/拦截器/管道/筛选器请求生命周期的项目

不适用场景:

  • 不需要框架的简单脚本或无服务器函数
  • 仅使用 Express/Fastify 就足够的项目(不需要 DI 或模块)
  • 前端代码

详细资源:

  • examples/core.md — 功能模块、CRUD、DTO、动态模块、异常筛选器、自定义提供者
  • examples/database.md — 数据库集成和事务的 NestJS DI 模式
  • examples/auth.md — Passport.js 集成、JWT 策略、身份验证守卫、RBAC
  • examples/testing.md — 使用 Test.createTestingModule 进行单元测试,使用 supertest 进行端到端测试
  • examples/advanced.md — 拦截器、自定义管道、自定义装饰器、配置、CQRS、Swagger
  • reference.md — CLI 命令、项目结构、装饰器表、决策框架

## 设计理念

NestJS 采用受 Angular 启发的模块化、由装饰器驱动的架构。每项功能都组织在模块中,模块包含控制器(HTTP 层)、服务(业务逻辑)和支持性基础设施(守卫、管道、拦截器、过滤器)。

核心原则:

  1. 模块化——将相关的控制器、服务和提供者归入功能模块。模块是主要的组织单元。
  2. 依赖注入——切勿手动实例化服务。将服务声明为 @Injectable(),并通过构造函数注入让 NestJS 解析依赖关系图。
  3. 由装饰器驱动——装饰器(@Controller、@Get、@Body、@UseGuards)会附加元数据,NestJS 使用这些元数据构建路由、验证和中间件管道。
  4. 关注点分离——控制器处理 HTTP 请求/响应。服务处理业务逻辑。守卫处理授权。管道处理验证/转换。过滤器处理异常。
  5. 约定优于配置——遵循 NestJS 约定(每项功能使用一个模块、每个资源使用一个控制器、使用 DTO 进行验证),即可获得开箱即用的功能。

关键模式

模块系统

每个 NestJS 应用都有一个根 AppModule,用于导入功能模块。每个功能模块都包含其控制器、服务和提供者。导出其他模块需要使用的服务。

// Feature module — one per resource
@Module({
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService], // Available to other modules
})
export class UsersModule {}

优点: 每项功能都有自己的封装;通过导入/导出显式定义依赖关系图;可单独测试

完整的 CRUD 模块、动态模块和自定义提供者示例,请参见 examples/core.md。


控制器——精简的路由层

控制器只应提取请求数据并将其委托给服务,不应包含业务逻辑。

@Controller("users")
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get(":id")
  findOne(@Param("id", ParseIntPipe) id: number) {
    return this.usersService.findOne(id);
  }

  @Post()
  @HttpCode(HttpStatus.CREATED)
  create(@Body() dto: CreateUserDto) {
    return this.usersService.create(dto);
  }
}

优点: ParseIntPipe 可验证并转换参数;使用 @HttpCode 显式设置状态码;将处理精简地委托给服务

反模式: 在控制器中编写业务逻辑、手动验证或访问数据库——始终将这些工作委托给服务。


使用 class-validator 的 DTO

使用带有 class-validator 装饰器的 DTO 验证所有请求。全局启用 ValidationPipe。

const MIN_PASSWORD_LENGTH = 8;

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(MIN_PASSWORD_LENGTH)
  password: string;
}

// Update DTO — reuses validation rules
export class UpdateUserDto extends PartialType(CreateUserDto) {}
// main.ts — Enable globally
app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true, // Strip unknown properties
    forbidNonWhitelisted: true, // Reject unknown properties
    transform: true, // Auto-transform to DTO instances
  }),
);

优点: 声明式验证;whitelist 可防止批量赋值;PartialType 可避免重复规则

嵌套 DTO、带分页的查询 DTO 以及验证组示例,请参见 examples/core.md。


服务与依赖注入

服务包含业务逻辑。使用 @Injectable() 装饰,并通过构造函数注入。

@Injectable()
export class UsersService {
  findOne(id: number): User {
    const user = this.users.find((u) => u.id === id);
    if (!user) {
      throw new NotFoundException(`User with id ${id} not found`);
    }
    return user;
  }
}

优点: @Injectable() 启用依赖注入;抛出 NestJS HTTP 异常;业务逻辑纯粹,不涉及 HTTP

自定义提供者

对非类提供者(工厂、值、类提供者)使用基于令牌的注入:

const DATABASE_CONNECTION = "DATABASE_CONNECTION";

const databaseProvider = {
  provide: DATABASE_CONNECTION,
  useFactory: async (configService: ConfigService) => {
    return createConnection(configService.get("database"));
  },
  inject: [ConfigService],
};

// Inject with @Inject token
constructor(@Inject(DATABASE_CONNECTION) private readonly db: Connection) {}

完整的提供者示例,请参见 examples/core.md。


异常处理

在服务中抛出 NestJS 内置 HTTP 异常。使用异常过滤器自定义错误响应格式。

// Service — throw built-in exceptions
throw new NotFoundException("Resource not found");
throw new ConflictException("Resource already exists");
throw new BadRequestException("Invalid input");
throw new UnauthorizedException("Authentication required");

要点: NestJS 会自动将这些异常转换为状态码正确的 HTTP 响应。切勿直接发送原始状态码。

如需自定义错误响应结构,请使用全局 @Catch() 异常过滤器。参见 examples/core.md。


守卫与中间件

守卫决定是否允许请求继续(授权)。中间件在路由之前运行(日志记录、CORS)。

// Guard — implements CanActivate
@Injectable()
export class JwtAuthGuard implements CanActivate {
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    // Validate token, attach user to request
    return true;
  }
}

// Apply to routes
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller("admin")
export class AdminController {}

优点: 守卫可注入(可以使用服务)、可组合(按顺序运行),并可使用 Reflector 实现基于元数据的访问控制

JWT 身份验证、Passport.js 集成、RBAC 和 @Public() 装饰器示例,请参见 examples/auth.md。


拦截器

拦截器会包装处理程序的执行过程,用于处理横切关注点(响应封装、日志记录、缓存)。

@Injectable()
export class TransformResponseInterceptor<T> implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Observable<ApiResponse<T>> {
    return next.handle().pipe(
      map((data) => ({
        success: true,
        data,
        timestamp: new Date().toISOString(),
      })),
    );
  }
}

日志记录、缓存和自定义管道模式示例,请参见 examples/advanced.md。


<decision_framework>

决策框架

请求生命周期
Incoming Request
  → Middleware (logging, CORS, body parsing)
    → Guards (authentication, authorization)
      → Interceptors (pre-handler: transform request, start timing)
        → Pipes (validation, transformation)
          → Route Handler (controller method)
        → Interceptors (post-handler: transform response, log timing)
  → Exception Filters (catch and format errors)
→ Response

</decision_framework>

应使用哪一层
Need to process raw request before routing?
├─ YES → Middleware (logging, CORS, rate limiting)
└─ NO → Does it decide allow/deny for a route?
    ├─ YES → Guard (auth, roles, permissions)
    └─ NO → Does it transform/validate input data?
        ├─ YES → Pipe (validation, type coercion)
        └─ NO → Does it wrap handler execution?
            ├─ YES → Interceptor (timing, caching, response mapping)
            └─ NO → Does it handle errors?
                ├─ YES → Exception Filter
                └─ NO → Put it in the service layer
模块组织
Is this a cross-cutting concern (auth, config, logging)?
├─ YES → Global module or shared module
└─ NO → Is it a business feature (users, orders, products)?
    ├─ YES → Feature module (users.module.ts)
    └─ NO → Is it infrastructure (database, cache, queue)?
        ├─ YES → Infrastructure module
        └─ NO → Part of the closest feature module

</decision_framework>


<red_flags>

危险信号

高优先级问题:

  • 将业务逻辑放在控制器中,而不是服务中
  • 服务缺少 @Injectable()(依赖注入会在运行时静默失败)
  • 未全局启用 ValidationPipe(DTO 不会经过验证)
  • 请求体使用 any,而不是类型化 DTO
  • 使用 new 实例化服务,而不是通过构造函数注入
  • 抛出原始 Error,而不是 NestJS HTTP 异常(会导致返回 500,而非正确的状态码)

中优先级问题:

  • 未从模块中导出服务(其他模块无法导入它们)
  • 只需要一个服务,却导入整个模块
  • ValidationPipe 缺少 whitelist: true(存在批量赋值漏洞)
  • 在流式处理场景之外使用 @Res() 装饰器(会退出 NestJS 的响应处理)
  • 更新 DTO 未使用 PartialType / PickType / OmitType(验证逻辑重复)

常见错误:

  • 模块依赖循环——使用 forwardRef() 重构,或提取共享逻辑
  • 忘记在模块中注册提供者——服务注入会在运行时失败
  • 对异步操作使用同步守卫——应返回 Promise<boolean> 或 Observable<boolean>
  • 自定义过滤器未处理所有异常类型——应始终为未知错误设置兜底处理

注意事项和边缘情况:

  • @UseGuards(AuthGuard) 接受类引用,而不是实例——NestJS 会通过依赖注入实例化它
  • ValidationPipe 设置 transform: true 后,会自动将查询参数转换为其声明的类型
  • 守卫在中间件之后、拦截器和管道之前执行
  • 不带参数的 @Catch() 会捕获所有异常,而不仅仅是 HttpException
  • IntrinsicException(NestJS 11)抛出异常时不会由框架自动记录日志——适用于预期的流程控制
  • NestJS 11:终止生命周期钩子(OnModuleDestroy、OnApplicationShutdown)现在会按相反顺序执行
  • NestJS 11:Express v5 要求使用带名称的通配符(/*splat,而不是 /*)
  • NestJS 11:SWC 是受支持的可选编译器,可通过 nest-cli.json 配置("builder": "swc")——构建速度比 tsc 快 20 倍
  • NestJS 11:ParseDatePipe 现已内置——无需自定义日期解析管道
  • 请求作用域提供者(Scope.REQUEST)会影响性能——仅在需要时使用
  • forwardRef() 应作为最后手段——循环依赖通常意味着设计存在问题

</red_flags>


<critical_reminders>

重要提醒

(必须在每个服务上使用 @Injectable(),并将其注册到模块的 providers 数组中)

(必须全局启用 ValidationPipe,并设置 whitelist: true 和 forbidNonWhitelisted: true)

(必须使用带有 class-validator 装饰器的 DTO 验证所有请求体——绝不要在控制器中手动验证)

(必须抛出 NestJS 内置 HTTP 异常(NotFoundException、BadRequestException 等)——绝不要发送原始状态码)

(必须使用构造函数注入依赖——绝不要使用 new 手动实例化服务)

若不遵守这些规则,将生成未经验证、无法测试且依赖注入失效的 NestJS 代码。

</critical_reminders>

评论

支持 Markdown