关于 nestjs
为使用 Express 5 的 NestJS v11 后端提供开发约定,涵盖分层、请求处理、验证、错误及生态包,并避免改动未涉及的模块。
主要功能
- 01明确的双层依赖规则
- 02DTO 验证约定
- 03响应与错误处理
- 04Express 5 路由指引
- 05常见改动的参考索引
适用场景
- 01组织 NestJS 后端改动
- 02验证请求输入
- 03检查响应与异常处理
- 04核对 Express 5 路由语法
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ alexander-danilenko/ cortex-ai-skills --skill nestjs安装后在 Claude Code 中输入/nestjs确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/architecture.mdconfiguration-and-logging.mddependency-injection.mddto-validation-openapi.mdecosystem-packages.mderrors.mdnestjs-11-migration.mdrequest-lifecycle.md详细介绍
NestJS
NestJS v11 / Express 5 后端的常规约定。编写或修改代码时请遵循这些约定;除非有人要求,否则不要重构未触及的模块。
以下示例使用虚构的货运领域,仅用于具体展示结构。关注结构,而非名称。
分层
分为两层,依赖箭头只能指向一个方向。
core/ domain + infrastructure. No controllers, no HTTP. → core only
app/ features. Controllers, DTOs, guards, middleware, CQRS. → app + core
如果核心模块需要深入访问某个功能模块,这说明它所负责的概念位于错误的层级——应将该概念下移,而不是向上导入。确保依赖方向正确,核心模块才能由 HTTP 请求、cron 作业、CLI 或队列消费者驱动,而不必牵入控制器。
始终遵循
这些约定几乎适用于每次改动,因此放在这里,而不是藏在参考资料中:
- 一个模块负责一个领域,其根 barrel 只导出
.module.ts。 未导出的提供者可以自由重构;导出后就成为公共 API。 - 控制器负责转换 HTTP 数据并委派处理;服务负责业务逻辑。 在控制器中根据业务规则分支,就无法在作业、CLI 或队列消费者中复用;而要让测试说明任何问题,也必须经过 HTTP 层。
- 每个请求正文、查询参数和路径参数都必须通过使用
class-validator的 DTO 校验,并由设置了whitelist: true、forbidNonWhitelisted: true、transform: true的ValidationPipe处理。 如果不启用白名单,意外属性就会一路进入持久化层。 - 响应 DTO 是离开进程的数据。 返回实体会泄露未来迁移添加到表中的任何内容——密码哈希、内部标记、软删除列——而且无需修改代码就会发生。
- 领域错误应继承同一个基类,并由一个全局过滤器呈现。 直接抛出
Error会变成 500,因此本应返回“未找到”的情况会触发告警。 - 全局增强器应通过
APP_GUARD/APP_PIPE/APP_INTERCEPTOR/APP_FILTER注册。app.useGlobal*()会在任何模块之外绑定实例,因此这些实例无法注入依赖。 - 领域服务不得导入供应商 SDK。 支付网关、数据库客户端和邮件服务提供商都应各自拥有包装模块;SDK 的重大升级就只会影响一个模块。
默认情况下的错误行为
有六种行为与 API 名称所暗示的含义相矛盾,因此在这里列出,而不是放在只有怀疑出问题时才会查看的参考资料中。它们都能顺利编译,却会在运行时失败。
- Express 5 的通配符必须命名。
@Get("files/*")和forRoutes("*")不再匹配——请写成@Get("files/*splat")和forRoutes("{*splat}")。:param?也已移除。 - 异常过滤器的解析顺序是路由 → 控制器 → 全局,与守卫和管道相反;拦截器则按后进先出顺序展开。路由范围的过滤器会覆盖全局过滤器。
@Res()会让处理程序退出框架的响应处理流程——@HttpCode、@Header、序列化以及所有响应拦截器都会停止生效。除非你要自行发送响应,否则请添加{ passthrough: true }。ClassSerializerInterceptor只会转换类实例。 返回{ user: new UserEntity() }会静默跳过@Exclude(),并将被排除的字段发送出去。- 在
@nestjs/cache-manager和@nestjs/throttler中,ttl的单位是毫秒;缓存的ttl: 0表示永不过期,而不是“不缓存”。 ClientProxy.send()返回冷 Observable,HttpService也会返回 Observable——只有订阅后才会执行。
第一项和第五项与版本有关。应用此技能中标记为 v11 的内容前,请检查 package.json 中的 @nestjs/core 版本;如果项目版本较旧,请阅读 references/nestjs-11-migration.md。
参考文档索引
根据修改内容阅读对应文件;不要预先加载所有文件。
| 处理内容 | 阅读 |
|---|---|
| 目录布局、文件名、入口文件、CQRS 与服务的区别、持久化 | references/architecture.md |
Provider、令牌、作用域、ModuleRef、循环依赖、生命周期钩子 | references/dependency-injection.md |
| Guard、拦截器、管道、中间件、装饰器、响应、版本控制 | references/request-lifecycle.md |
| DTO、class-validator、序列化、Swagger/OpenAPI | references/dto-validation-openapi.md |
| 异常、异常过滤器、错误消息 | references/errors.md |
ConfigModule、ConfigService、日志记录 | references/configuration-and-logging.md |
@nestjs/axios、event-emitter、bullmq、throttler、cache-manager、schedule、微服务 | references/ecosystem-packages.md |
| 从 v10 升级,或早于 Express 5 的代码 | references/nestjs-11-migration.md |
| 测试 | testing 技能的 NestJS Jest 参考文档 |
在审查而非编写时,references/request-lifecycle.md 和 references/nestjs-11-migration.md 最能帮助发现缺陷,且阅读量最少:增强器的执行顺序和 Express 5 路由语法都可能出现类型检查通过、运行却失败的情况。