Skip to Content

28b - API设计与生成

本文是《AI Agent 实战手册》第 28 章第 2 节。 上一节:28a-AI辅助后端开发概览 | 下一节:28c-Spec-Driven业务逻辑

概述

API 是后端系统的”门面”——它定义了前端、移动端、第三方服务与后端交互的契约。在 AI 辅助开发时代,API 设计与生成正在从”手动编写路由和控制器”演进为”Schema-first 设计 + AI 自动生成实现代码”的工作流。本节系统覆盖 REST、GraphQL、tRPC 三种主流 API 范式的 AI 辅助设计与生成方法,包括 Schema-first 设计方法论、输入验证中间件(Zod/Pydantic/Joi)、OpenAPI 文档自动生成,以及 API 版本管理策略。


1. API 范式选择:REST vs GraphQL vs tRPC

1.1 三种范式的核心差异

在开始 AI 辅助 API 设计之前,首先需要理解三种主流范式的本质区别和适用场景。

维度RESTGraphQLtRPC
协议基础HTTP 方法 + URL 路径单一端点 + 查询语言TypeScript 函数调用
数据获取固定端点返回固定结构客户端按需查询字段类型推断自动同步
类型安全需要额外工具(OpenAPI)Schema 内置类型系统TypeScript 原生类型推断
学习曲线低(HTTP 基础即可)中(需学习查询语言)低(TypeScript 开发者)
生态成熟度极高(行业标准 20+ 年)高(2015 年发布,广泛采用)中(2021 年发布,快速增长)
AI 生成质量⭐⭐⭐⭐⭐(训练数据极丰富)⭐⭐⭐⭐(模式化程度高)⭐⭐⭐⭐(类型系统辅助)
适用团队任何团队前后端分离的中大型团队全栈 TypeScript 团队
跨语言支持所有语言所有语言(需 SDK)仅 TypeScript/JavaScript
缓存友好度极高(HTTP 缓存原生支持)低(POST 请求为主)中(需额外配置)
实时能力需要 WebSocket/SSE 补充Subscription 内置支持需要额外配置

1.2 AI 辅助选择决策树

你的项目需要什么类型的 API? ├── 对外公开 API(第三方集成) │ └── REST + OpenAPI ← AI 生成 OpenAPI 规范 + 实现代码 ├── 前后端分离(多客户端:Web + Mobile + 第三方) │ ├── 数据关系复杂,客户端需要灵活查询? │ │ └── GraphQL ← AI 生成 Schema + Resolver │ └── 数据结构相对固定? │ └── REST ← AI 生成 RESTful 端点 ├── 全栈 TypeScript 项目(Next.js / Nuxt / SvelteKit) │ ├── 团队全部使用 TypeScript? │ │ └── tRPC ← AI 生成 Router + Procedure │ └── 团队有非 TypeScript 成员? │ └── REST 或 GraphQL └── 微服务间通信 ├── 高性能要求? │ └── gRPC(不在本节范围,见微服务章节) └── 标准 HTTP 通信? └── REST + OpenAPI

1.3 混合使用策略

实际项目中,三种范式可以混合使用:

┌─────────────────────────────────────────────┐ │ 典型混合架构 │ ├─────────────────────────────────────────────┤ │ │ │ 外部 API(第三方集成) │ │ └── REST + OpenAPI 3.1 │ │ │ │ Web 前端 ↔ BFF(Backend for Frontend) │ │ └── tRPC(全栈 TypeScript 类型安全) │ │ │ │ Mobile App ↔ API Gateway │ │ └── GraphQL(灵活数据查询) │ │ │ │ 微服务间通信 │ │ └── gRPC / REST(内部服务) │ │ │ └─────────────────────────────────────────────┘

工具推荐:API 设计与生成工具

工具用途支持范式价格适用场景
Swagger Editor / SwaggerHubOpenAPI 规范编辑与协作REST免费(Editor)/ $95/月起(Hub)团队协作的 API 设计
Stoplight Studio可视化 API 设计REST (OpenAPI)免费(个人)/ $99/月(Team)非技术人员参与的 API 设计
ApidogAPI 设计、Mock、测试、文档一体化REST / GraphQL免费 / $9/月(Basic)API 全生命周期管理
PostmanAPI 开发与测试平台REST / GraphQL / gRPC免费 / $14/月(Basic)API 测试和文档自动化
Apollo StudioGraphQL Schema 管理与监控GraphQL免费 / $59/月(Team)GraphQL API 的生产监控
GraphQL Code Generator从 Schema 生成类型和 SDKGraphQL免费(开源)GraphQL 客户端/服务端代码生成
openapi-generator从 OpenAPI 规范生成客户端/服务端代码REST免费(开源)多语言 API 客户端生成
Orval从 OpenAPI 生成 TypeScript 客户端REST免费(开源)TypeScript 前端的 API 客户端
tRPC端到端类型安全 API 框架tRPC免费(开源)全栈 TypeScript 项目
Hono轻量级 Web 框架(支持 RPC 模式)REST / RPC免费(开源)Serverless 和边缘计算
ScalarOpenAPI 文档渲染与交互REST免费(开源)/ 按需定价(Cloud)美观的 API 文档站点
RedoclyOpenAPI 文档生成与 lintREST免费(CLI)/ $69/月(Starter)企业级 API 文档
TheneoAI 驱动的 API 文档生成REST / GraphQL免费 / $120/月(Startup)从 Postman/OpenAPI 生成文档
express-zod-apiZod 驱动的 Express API 框架REST免费(开源)Zod-first 的 Express API 开发

2. Schema-First 设计方法论

2.1 什么是 Schema-First 设计

Schema-First(契约优先)是一种 API 设计方法论,核心思想是:先定义 API 契约(Schema),再生成实现代码。与之相对的是 Code-First(代码优先),即先写代码,再从代码生成文档。

┌─────────────────────────────────────────────────────┐ │ Schema-First vs Code-First 对比 │ ├─────────────────────────────────────────────────────┤ │ │ │ Schema-First(推荐用于 AI 辅助开发) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ API 契约 │ → │ AI 生成 │ → │ 实现代码 │ │ │ │ (Schema) │ │ 代码骨架 │ │ + 测试 │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ 优点:一致性高、前后端可并行、AI 生成质量高 │ │ │ │ Code-First(传统方式) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 写实现 │ → │ 提取注解 │ → │ 生成文档 │ │ │ │ 代码 │ │ /装饰器 │ │ (Schema) │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ 优点:开发速度快、适合快速原型 │ │ │ └─────────────────────────────────────────────────────┘

2.2 为什么 Schema-First 更适合 AI 辅助开发

  1. AI 生成的一致性更高:有了明确的 Schema,AI 生成的代码严格遵循契约,不会出现”不同端点风格不一致”的问题
  2. 前后端可并行开发:Schema 定义完成后,前端可以基于 Schema 生成 Mock 数据和类型定义,后端同时实现 API
  3. 自动化验证:Schema 可以自动生成输入验证、类型检查、文档,减少手动维护成本
  4. 变更可追踪:Schema 文件纳入版本控制,API 变更有明确的 diff 记录
  5. AI 的”单一事实来源”:Schema 作为 AI 的上下文输入,确保生成的代码与设计一致

2.3 三种范式的 Schema-First 实践

REST:OpenAPI 3.1 Schema-First

OpenAPI 3.1 是 REST API 的行业标准规范格式,完全兼容 JSON Schema 2020-12。

AI 辅助 OpenAPI Schema 设计的提示词模板:

请为以下业务需求设计 OpenAPI 3.1 规范: ## 业务需求 [描述 API 的业务目的和核心功能] ## 资源列表 [列出核心资源/实体,如 User, Product, Order] ## 设计约束 - API 基础路径:/api/v1 - 认证方式:Bearer Token (JWT) - 分页方式:cursor-based(使用 cursor + limit 参数) - 错误响应格式:RFC 7807 Problem Details - 日期格式:ISO 8601 - ID 格式:CUID2 ## 要求 - 每个资源包含 CRUD 端点 - 使用 [占位符] 标记需要替换的部分 - 包含请求/响应 Schema 定义(使用 $ref 引用 components) - 包含认证安全方案定义 - 包含分页、过滤、排序的查询参数 - 包含标准错误响应(400, 401, 403, 404, 409, 422, 500)

AI 生成的 OpenAPI Schema 示例(部分):

openapi: 3.1.0 info: title: 项目管理 API version: 1.0.0 description: 多租户项目管理 SaaS 的 RESTful API servers: - url: https://api.example.com/v1 description: 生产环境 security: - BearerAuth: [] paths: /projects: get: operationId: listProjects summary: 获取项目列表 tags: [Projects] parameters: - $ref: '#/components/parameters/CursorParam' - $ref: '#/components/parameters/LimitParam' - name: status in: query schema: $ref: '#/components/schemas/ProjectStatus' responses: '200': description: 项目列表 content: application/json: schema: $ref: '#/components/schemas/ProjectListResponse' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createProject summary: 创建项目 tags: [Projects] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateProjectRequest' responses: '201': description: 项目创建成功 content: application/json: schema: $ref: '#/components/schemas/ProjectResponse' '400': $ref: '#/components/responses/BadRequest' '422': $ref: '#/components/responses/ValidationError' components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT schemas: ProjectStatus: type: string enum: [active, archived, deleted] CreateProjectRequest: type: object required: [name] properties: name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 2000 ProjectResponse: type: object properties: id: type: string name: type: string description: type: string nullable: true status: $ref: '#/components/schemas/ProjectStatus' createdAt: type: string format: date-time updatedAt: type: string format: date-time ProjectListResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/ProjectResponse' pagination: $ref: '#/components/schemas/CursorPagination' CursorPagination: type: object properties: nextCursor: type: string nullable: true hasMore: type: boolean ProblemDetail: type: object description: RFC 7807 Problem Details properties: type: type: string format: uri title: type: string status: type: integer detail: type: string instance: type: string format: uri parameters: CursorParam: name: cursor in: query schema: type: string LimitParam: name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 20 responses: BadRequest: description: 请求参数错误 content: application/json: schema: $ref: '#/components/schemas/ProblemDetail' Unauthorized: description: 未认证 content: application/json: schema: $ref: '#/components/schemas/ProblemDetail' ValidationError: description: 输入验证失败 content: application/json: schema: $ref: '#/components/schemas/ProblemDetail'

GraphQL:Schema-First 设计

GraphQL 天然是 Schema-First 的——SDL(Schema Definition Language)就是 API 契约。

AI 辅助 GraphQL Schema 设计的提示词模板:

请为以下业务需求设计 GraphQL Schema(SDL 格式): ## 业务需求 [描述业务领域和核心实体] ## 设计约束 - 使用 Relay 风格的连接分页(Connection/Edge/Node) - 使用 Input 类型封装变更参数 - 错误处理使用 Union 类型(Result Pattern) - 包含 Subscription 定义(如需实时功能) ## 要求 - 定义所有 Query、Mutation、Subscription - 使用自定义标量类型(DateTime, Email, URL) - 包含权限指令(@auth) - 包含输入验证指令(@constraint) - 遵循 GraphQL 命名约定(camelCase 字段,PascalCase 类型)

AI 生成的 GraphQL Schema 示例:

# schema.graphql — AI 生成的项目管理 GraphQL Schema # 自定义标量 scalar DateTime scalar Email scalar URL # 权限指令 directive @auth(requires: Role!) on FIELD_DEFINITION # 枚举类型 enum Role { OWNER ADMIN MEMBER VIEWER } enum TaskStatus { TODO IN_PROGRESS IN_REVIEW DONE CANCELLED } enum Priority { LOW MEDIUM HIGH URGENT } enum SortDirection { ASC DESC } # 接口 interface Node { id: ID! } interface Timestamped { createdAt: DateTime! updatedAt: DateTime! } # 核心类型 type User implements Node & Timestamped { id: ID! email: Email! name: String! avatarUrl: URL createdAt: DateTime! updatedAt: DateTime! memberships: [Membership!]! } type Project implements Node & Timestamped { id: ID! name: String! description: String archived: Boolean! createdAt: DateTime! updatedAt: DateTime! tasks( first: Int after: String filter: TaskFilterInput sort: TaskSortInput ): TaskConnection! taskCount: Int! } type Task implements Node & Timestamped { id: ID! title: String! description: String status: TaskStatus! priority: Priority! dueDate: DateTime assignee: User creator: User! project: Project! createdAt: DateTime! updatedAt: DateTime! } type Membership { id: ID! role: Role! user: User! organization: Organization! } type Organization implements Node & Timestamped { id: ID! name: String! slug: String! createdAt: DateTime! updatedAt: DateTime! members: [Membership!]! projects(first: Int, after: String): ProjectConnection! } # Relay 风格分页 type TaskConnection { edges: [TaskEdge!]! pageInfo: PageInfo! totalCount: Int! } type TaskEdge { node: Task! cursor: String! } type ProjectConnection { edges: [ProjectEdge!]! pageInfo: PageInfo! totalCount: Int! } type ProjectEdge { node: Project! cursor: String! } type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String } # 输入类型 input CreateProjectInput { name: String! description: String } input UpdateProjectInput { name: String description: String archived: Boolean } input CreateTaskInput { title: String! description: String priority: Priority = MEDIUM assigneeId: ID dueDate: DateTime } input UpdateTaskInput { title: String description: String status: TaskStatus priority: Priority assigneeId: ID dueDate: DateTime } input TaskFilterInput { status: [TaskStatus!] priority: [Priority!] assigneeId: ID } input TaskSortInput { field: TaskSortField! direction: SortDirection! } enum TaskSortField { CREATED_AT UPDATED_AT PRIORITY DUE_DATE } # Result Pattern(错误处理) union CreateProjectResult = Project | ValidationError | AuthorizationError union UpdateTaskResult = Task | ValidationError | NotFoundError | AuthorizationError type ValidationError { message: String! field: String code: String! } type NotFoundError { message: String! resourceType: String! resourceId: ID! } type AuthorizationError { message: String! requiredRole: Role } # 查询 type Query { # 当前用户 me: User! @auth(requires: VIEWER) # 组织 organization(slug: String!): Organization @auth(requires: VIEWER) # 项目 project(id: ID!): Project @auth(requires: VIEWER) # 任务 task(id: ID!): Task @auth(requires: VIEWER) # Node 接口查询 node(id: ID!): Node } # 变更 type Mutation { # 项目 createProject( organizationId: ID! input: CreateProjectInput! ): CreateProjectResult! @auth(requires: MEMBER) updateProject( id: ID! input: UpdateProjectInput! ): Project! @auth(requires: ADMIN) deleteProject(id: ID!): Boolean! @auth(requires: OWNER) # 任务 createTask( projectId: ID! input: CreateTaskInput! ): Task! @auth(requires: MEMBER) updateTask( id: ID! input: UpdateTaskInput! ): UpdateTaskResult! @auth(requires: MEMBER) deleteTask(id: ID!): Boolean! @auth(requires: ADMIN) } # 订阅 type Subscription { taskUpdated(projectId: ID!): Task! @auth(requires: VIEWER) taskCreated(projectId: ID!): Task! @auth(requires: VIEWER) }

tRPC:类型即契约

tRPC 的独特之处在于不需要单独的 Schema 文件——TypeScript 类型本身就是契约。tRPC v11(2025 年 3 月正式发布)引入了多项改进,包括更好的中间件类型推断和标准 HTTP 支持。

tRPC 的 Schema-First 等价物:先定义 Zod Schema,再构建 Router。

// schemas/task.ts — 先定义验证 Schema(这就是 tRPC 的"契约") import { z } from 'zod'; export const TaskStatus = z.enum([ 'TODO', 'IN_PROGRESS', 'IN_REVIEW', 'DONE', 'CANCELLED' ]); export const Priority = z.enum(['LOW', 'MEDIUM', 'HIGH', 'URGENT']); export const CreateTaskSchema = z.object({ title: z.string().min(1).max(200), description: z.string().max(5000).optional(), priority: Priority.default('MEDIUM'), assigneeId: z.string().cuid2().optional(), dueDate: z.coerce.date().optional(), }); export const UpdateTaskSchema = z.object({ title: z.string().min(1).max(200).optional(), description: z.string().max(5000).optional(), status: TaskStatus.optional(), priority: Priority.optional(), assigneeId: z.string().cuid2().nullable().optional(), dueDate: z.coerce.date().nullable().optional(), }); export const TaskFilterSchema = z.object({ status: z.array(TaskStatus).optional(), priority: z.array(Priority).optional(), assigneeId: z.string().cuid2().optional(), cursor: z.string().optional(), limit: z.number().int().min(1).max(100).default(20), }); // 类型自动从 Schema 推断 export type CreateTaskInput = z.infer<typeof CreateTaskSchema>; export type UpdateTaskInput = z.infer<typeof UpdateTaskSchema>; export type TaskFilter = z.infer<typeof TaskFilterSchema>;
// routers/task.ts — 基于 Schema 构建 tRPC Router import { router, protectedProcedure } from '../trpc'; import { CreateTaskSchema, UpdateTaskSchema, TaskFilterSchema, } from '../schemas/task'; import { z } from 'zod'; export const taskRouter = router({ list: protectedProcedure .input(TaskFilterSchema) .query(async ({ ctx, input }) => { const tasks = await ctx.db.task.findMany({ where: { projectId: ctx.projectId, ...(input.status && { status: { in: input.status } }), ...(input.priority && { priority: { in: input.priority } }), ...(input.assigneeId && { assigneeId: input.assigneeId }), }, take: input.limit + 1, ...(input.cursor && { cursor: { id: input.cursor }, skip: 1, }), orderBy: { createdAt: 'desc' }, }); const hasMore = tasks.length > input.limit; const data = hasMore ? tasks.slice(0, -1) : tasks; return { data, nextCursor: hasMore ? data[data.length - 1]?.id : null, hasMore, }; }), create: protectedProcedure .input(CreateTaskSchema) .mutation(async ({ ctx, input }) => { return ctx.db.task.create({ data: { ...input, projectId: ctx.projectId, creatorId: ctx.user.id, }, }); }), update: protectedProcedure .input(z.object({ id: z.string().cuid2(), data: UpdateTaskSchema, })) .mutation(async ({ ctx, input }) => { return ctx.db.task.update({ where: { id: input.id }, data: input.data, }); }), delete: protectedProcedure .input(z.object({ id: z.string().cuid2() })) .mutation(async ({ ctx, input }) => { await ctx.db.task.delete({ where: { id: input.id } }); return { success: true }; }), });

3. REST API 设计与 AI 生成

3.1 RESTful API 设计原则(AI 友好版)

以下原则不仅是好的 REST 设计实践,也是让 AI 生成更一致代码的关键约束:

原则说明AI 友好度Steering 规则建议
资源命名用复数名词/users, /projects, /tasks⭐⭐⭐⭐⭐“URL 路径使用复数名词,禁止动词”
HTTP 方法语义化GET 读取、POST 创建、PUT/PATCH 更新、DELETE 删除⭐⭐⭐⭐⭐“严格遵循 HTTP 方法语义”
嵌套资源表示关系/projects/:projectId/tasks⭐⭐⭐⭐“嵌套不超过 2 层”
统一错误响应格式RFC 7807 Problem Details⭐⭐⭐⭐“所有错误响应使用 ProblemDetail 格式”
Cursor 分页?cursor=xxx&limit=20⭐⭐⭐⭐“列表端点必须支持分页”
版本化/api/v1/...⭐⭐⭐⭐⭐“所有端点包含版本前缀”
HATEOAS(可选)响应中包含相关资源链接⭐⭐⭐仅在公开 API 中使用

3.2 AI 生成 REST API 的操作步骤

步骤 1:定义 OpenAPI Schema

使用 AI 生成 OpenAPI 3.1 规范文件(见 2.3 节的模板)。

步骤 2:从 Schema 生成服务端代码

方法 A:使用 openapi-generator(多语言支持)

# 安装 openapi-generator npm install @openapitools/openapi-generator-cli -g # 从 OpenAPI 规范生成 NestJS 服务端代码 openapi-generator-cli generate \ -i openapi.yaml \ -g typescript-nestjs \ -o src/generated \ --additional-properties=useTags=true # 从 OpenAPI 规范生成 FastAPI 服务端代码 openapi-generator-cli generate \ -i openapi.yaml \ -g python-fastapi \ -o src/generated

方法 B:使用 AI Agent 直接生成(推荐)

基于以下 OpenAPI 规范,为每个端点生成 NestJS 的 Controller + Service + DTO: [粘贴 OpenAPI YAML 或指定文件路径] ## 生成要求 - Controller 使用 @nestjs/swagger 装饰器(与 OpenAPI 规范一致) - DTO 使用 class-validator + class-transformer 装饰器 - Service 使用 Prisma Client 操作数据库 - 包含统一的异常过滤器(映射到 RFC 7807 格式) - 每个 Service 方法包含日志记录 - 生成对应的单元测试文件

方法 C:Zod-first 生成(TypeScript 推荐)

使用 express-zod-api 或类似框架,从 Zod Schema 同时生成路由、验证和 OpenAPI 文档:

// 使用 express-zod-api 的 Schema-First 方式 import { createConfig, Routing, EndpointsFactory } from 'express-zod-api'; import { z } from 'zod'; const config = createConfig({ server: { listen: 3000 }, cors: true, logger: { level: 'info' }, }); const endpointsFactory = new EndpointsFactory(defaultResultHandler); // 定义端点 — Zod Schema 同时用于验证和文档生成 const createTaskEndpoint = endpointsFactory.build({ method: 'post', input: z.object({ title: z.string().min(1).max(200), description: z.string().max(5000).optional(), priority: z.enum(['LOW', 'MEDIUM', 'HIGH', 'URGENT']).default('MEDIUM'), }), output: z.object({ id: z.string(), title: z.string(), status: z.string(), createdAt: z.string(), }), handler: async ({ input }) => { const task = await prisma.task.create({ data: input }); return task; }, }); // 路由定义 const routing: Routing = { v1: { tasks: { '': createTaskEndpoint, }, }, };

步骤 3:生成客户端 SDK

# 使用 Orval 从 OpenAPI 生成 TypeScript 客户端(React Query 集成) npx orval --input openapi.yaml --output src/api/generated # 使用 openapi-typescript 生成类型定义 npx openapi-typescript openapi.yaml -o src/api/types.ts

3.3 REST API 的 AI 生成提示词模板

模板:完整 CRUD 端点生成

请为 [资源名称] 资源生成完整的 RESTful CRUD API: ## 技术栈 - 框架:[NestJS / FastAPI / Express / Gin] - ORM:[Prisma / SQLAlchemy / TypeORM / GORM] - 验证:[Zod / Pydantic / class-validator / Joi] - 数据库:[PostgreSQL / MySQL] ## 资源定义 [描述资源的字段、类型、约束] ## API 端点 - GET /api/v1/[资源复数] — 列表(支持分页、过滤、排序) - GET /api/v1/[资源复数]/:id — 详情 - POST /api/v1/[资源复数] — 创建 - PATCH /api/v1/[资源复数]/:id — 部分更新 - DELETE /api/v1/[资源复数]/:id — 删除 ## 必须包含 1. 输入验证 Schema(创建和更新分开定义) 2. 统一错误响应(RFC 7807 格式) 3. Cursor 分页(cursor + limit) 4. 过滤参数(按 [指定字段] 过滤) 5. 排序参数(sortBy + sortDirection) 6. 认证守卫(JWT Bearer Token) 7. 权限检查(基于角色) 8. 请求日志中间件 9. 单元测试(覆盖正常路径和错误路径) ## 禁止 - 禁止使用 SELECT * - 禁止在响应中暴露内部错误堆栈 - 禁止硬编码任何密钥或配置值

4. GraphQL API 设计与 AI 辅助

4.1 GraphQL Schema 设计最佳实践

实践说明AI 提示建议
Relay 风格分页使用 Connection/Edge/Node 模式”列表字段使用 Relay Connection 分页”
Input 类型封装Mutation 参数使用 Input 类型”所有 Mutation 参数使用 Input 类型”
Result Union错误处理使用 Union 类型”Mutation 返回 Result Union(成功类型 | 错误类型)“
接口复用使用 interface 定义共享字段”使用 Node 和 Timestamped 接口”
自定义标量DateTime、Email、URL 等”定义 DateTime、Email 自定义标量”
N+1 防护使用 DataLoader 批量加载”所有关联字段使用 DataLoader”
深度限制限制查询嵌套深度”查询深度限制为 5 层”
复杂度分析限制查询复杂度”查询复杂度上限为 1000”

4.2 AI 生成 GraphQL Resolver 的操作步骤

步骤 1:从 Schema 生成类型和 Resolver 骨架

使用 GraphQL Code Generator 从 SDL 生成 TypeScript 类型:

# 安装 GraphQL Code Generator npm install -D @graphql-codegen/cli @graphql-codegen/typescript \ @graphql-codegen/typescript-resolvers # codegen.ts 配置
// codegen.ts import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: 'src/schema.graphql', generates: { 'src/generated/types.ts': { plugins: [ 'typescript', 'typescript-resolvers', ], config: { contextType: '../context#GraphQLContext', mappers: { User: '../models#UserModel', Project: '../models#ProjectModel', Task: '../models#TaskModel', }, useIndexSignature: true, }, }, }, }; export default config;
# 生成类型 npx graphql-codegen

步骤 2:AI 生成 Resolver 实现

基于以下 GraphQL Schema 和生成的 TypeScript 类型,实现 Resolver: ## Schema 文件 [粘贴 schema.graphql 内容] ## 生成的类型文件 [粘贴 generated/types.ts 内容] ## 技术栈 - 运行时:Node.js + TypeScript - GraphQL 服务器:Apollo Server 4 / Yoga - ORM:Prisma - 认证:JWT(通过 context 传递) ## 要求 - 所有关联字段使用 DataLoader 批量加载(防止 N+1) - Mutation 包含输入验证(使用 Zod) - 错误处理使用 Result Union 模式 - 包含权限检查(基于 @auth 指令) - 分页使用 Relay Connection 规范 - 包含查询复杂度分析中间件

AI 生成的 Resolver 示例:

// resolvers/task.ts — AI 生成的 Task Resolver import { Resolvers } from '../generated/types'; import { GraphQLContext } from '../context'; import { CreateTaskSchema, UpdateTaskSchema } from '../schemas/task'; import { GraphQLError } from 'graphql'; export const taskResolvers: Resolvers<GraphQLContext> = { Query: { task: async (_parent, { id }, ctx) => { const task = await ctx.prisma.task.findUnique({ where: { id }, }); if (!task) { throw new GraphQLError('Task not found', { extensions: { code: 'NOT_FOUND' }, }); } return task; }, }, Mutation: { createTask: async (_parent, { projectId, input }, ctx) => { // 输入验证 const validated = CreateTaskSchema.safeParse(input); if (!validated.success) { return { __typename: 'ValidationError', message: validated.error.issues[0].message, field: validated.error.issues[0].path.join('.'), code: 'VALIDATION_ERROR', }; } // 权限检查 const membership = await ctx.prisma.membership.findFirst({ where: { userId: ctx.user.id, organization: { projects: { some: { id: projectId } } }, role: { in: ['OWNER', 'ADMIN', 'MEMBER'] }, }, }); if (!membership) { return { __typename: 'AuthorizationError', message: 'Insufficient permissions', requiredRole: 'MEMBER', }; } const task = await ctx.prisma.task.create({ data: { ...validated.data, projectId, creatorId: ctx.user.id, }, }); return { __typename: 'Task', ...task }; }, }, Task: { // DataLoader 批量加载关联 assignee: (task, _args, ctx) => { if (!task.assigneeId) return null; return ctx.loaders.userLoader.load(task.assigneeId); }, creator: (task, _args, ctx) => { return ctx.loaders.userLoader.load(task.creatorId); }, project: (task, _args, ctx) => { return ctx.loaders.projectLoader.load(task.projectId); }, }, // Result Union 类型解析 CreateProjectResult: { __resolveType(obj) { if ('name' in obj && 'id' in obj) return 'Project'; if ('field' in obj) return 'ValidationError'; if ('requiredRole' in obj) return 'AuthorizationError'; return null; }, }, };

4.3 GraphQL 的 AI 生成提示词模板

请为以下 GraphQL Schema 生成完整的服务端实现: ## Schema [粘贴 SDL] ## 技术栈 - GraphQL 服务器:[Apollo Server 4 / GraphQL Yoga / Mercurius] - ORM:[Prisma / TypeORM / Drizzle] - 验证:Zod ## 必须包含 1. DataLoader 工厂函数(防止 N+1 查询) 2. Relay Connection 分页辅助函数 3. 输入验证(Zod Schema) 4. Result Union 错误处理 5. 权限中间件(基于 @auth 指令) 6. 查询深度限制(最大 [N] 层) 7. 查询复杂度分析(最大 [N] 点) 8. 上下文工厂函数(包含认证、DataLoader、Prisma)

5. tRPC 端到端类型安全

5.1 tRPC v11 核心特性

tRPC v11 于 2025 年 3 月正式发布,带来了多项重要改进:

特性说明AI 辅助价值
标准 HTTP 支持支持标准 HTTP 方法和路径AI 可以生成符合 REST 风格的 tRPC 路由
改进的中间件类型中间件链的类型推断更精确AI 生成的中间件代码类型错误更少
FormData 支持原生支持文件上传AI 可以生成文件上传端点
Server-Sent Events内置 SSE 支持AI 可以生成实时推送端点
更好的错误处理类型安全的错误类型AI 生成的错误处理更精确
React Server Components与 RSC 深度集成AI 可以生成 RSC 友好的数据获取

5.2 tRPC 项目结构(AI 友好)

src/ ├── server/ │ ├── trpc.ts # tRPC 初始化(context, middleware) │ ├── routers/ │ │ ├── _app.ts # 根 Router(合并所有子 Router) │ │ ├── auth.ts # 认证相关 │ │ ├── user.ts # 用户管理 │ │ ├── project.ts # 项目管理 │ │ └── task.ts # 任务管理 │ ├── schemas/ # Zod Schema(共享验证逻辑) │ │ ├── auth.ts │ │ ├── user.ts │ │ ├── project.ts │ │ └── task.ts │ └── services/ # 业务逻辑层 │ ├── auth.service.ts │ ├── user.service.ts │ ├── project.service.ts │ └── task.service.ts ├── client/ │ └── trpc.ts # tRPC 客户端配置 └── shared/ └── types.ts # 共享类型(从 Zod Schema 推断)

5.3 tRPC 的 AI 生成操作步骤

步骤 1:初始化 tRPC 配置

// server/trpc.ts — tRPC 初始化 import { initTRPC, TRPCError } from '@trpc/server'; import { type CreateNextContextOptions } from '@trpc/server/adapters/next'; import superjson from 'superjson'; import { ZodError } from 'zod'; import { prisma } from '../lib/prisma'; import { verifyToken } from '../lib/auth'; // Context 创建 export const createTRPCContext = async (opts: CreateNextContextOptions) => { const token = opts.req.headers.authorization?.replace('Bearer ', ''); const user = token ? await verifyToken(token) : null; return { prisma, user, req: opts.req, }; }; type Context = Awaited<ReturnType<typeof createTRPCContext>>; // tRPC 初始化 const t = initTRPC.context<Context>().create({ transformer: superjson, errorFormatter({ shape, error }) { return { ...shape, data: { ...shape.data, zodError: error.cause instanceof ZodError ? error.cause.flatten() : null, }, }; }, }); // 导出 export const router = t.router; export const publicProcedure = t.procedure; export const createCallerFactory = t.createCallerFactory; // 认证中间件 const enforceAuth = t.middleware(({ ctx, next }) => { if (!ctx.user) { throw new TRPCError({ code: 'UNAUTHORIZED' }); } return next({ ctx: { ...ctx, user: ctx.user }, }); }); export const protectedProcedure = t.procedure.use(enforceAuth); // 日志中间件 const loggerMiddleware = t.middleware(async ({ path, type, next }) => { const start = Date.now(); const result = await next(); const duration = Date.now() - start; console.log(`[tRPC] ${type} ${path} - ${duration}ms`); return result; }); export const loggedProcedure = t.procedure.use(loggerMiddleware);

步骤 2:AI 生成 Router

提示词模板:

请基于以下 Zod Schema 生成 tRPC Router: ## Zod Schema [粘贴 schemas/ 目录下的 Schema 定义] ## 技术栈 - tRPC v11 - Prisma ORM - Zod 验证 - SuperJSON 序列化 ## 要求 - 使用 protectedProcedure(需要认证的端点) - 列表查询支持 cursor 分页 - 包含输入验证(使用已定义的 Zod Schema) - 包含权限检查中间件 - 错误处理使用 TRPCError - 业务逻辑封装在 Service 层 - 包含乐观更新支持(返回更新后的完整对象)

步骤 3:客户端集成

// client/trpc.ts — Next.js 客户端配置 import { createTRPCReact } from '@trpc/react-query'; import { httpBatchLink } from '@trpc/client'; import superjson from 'superjson'; import type { AppRouter } from '../server/routers/_app'; export const trpc = createTRPCReact<AppRouter>(); export function getTRPCClient() { return trpc.createClient({ links: [ httpBatchLink({ url: '/api/trpc', transformer: superjson, headers() { return { authorization: `Bearer ${getToken()}`, }; }, }), ], }); }
// 客户端使用 — 完全类型安全,零代码生成 // 修改服务端 Schema → 客户端自动获得类型错误提示 // 列表查询 const { data, fetchNextPage, hasNextPage } = trpc.task.list.useInfiniteQuery( { limit: 20, status: ['TODO', 'IN_PROGRESS'] }, { getNextPageParam: (lastPage) => lastPage.nextCursor } ); // 创建任务(带乐观更新) const utils = trpc.useUtils(); const createTask = trpc.task.create.useMutation({ onSuccess: () => { utils.task.list.invalidate(); }, }); // 调用 — 参数类型自动推断,拼写错误立即报错 createTask.mutate({ title: '实现用户注册 API', priority: 'HIGH', // 类型安全:只能是 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT' });

6. 输入验证中间件

6.1 为什么输入验证是 API 安全的第一道防线

输入验证是防止注入攻击、数据损坏和意外行为的最基本也是最重要的安全措施。AI 生成的 API 代码如果缺少输入验证,就像没有锁的门——看起来完整,但毫无防护。

AI 生成代码中常见的验证缺失:

缺失类型风险示例
缺少类型验证类型混淆攻击期望 number 收到 string
缺少长度限制DoS 攻击(超大 payload)无限长度的 description 字段
缺少格式验证注入攻击email 字段接受任意字符串
缺少范围验证业务逻辑错误负数的 price 或 quantity
缺少枚举验证非法状态status 字段接受任意值
缺少嵌套验证深层注入嵌套对象中的恶意字段

6.2 三大验证库对比

特性Zod (TypeScript)Pydantic (Python)Joi (JavaScript)
语言TypeScript/JavaScriptPythonJavaScript/TypeScript
类型推断✅ 自动推断 TS 类型✅ 自动推断 Python 类型❌ 需要手动定义类型
运行时验证
Schema 复用.extend(), .pick(), .omit()✅ 继承、model_validator.keys(), .fork()
错误消息可自定义,支持 i18n可自定义,详细的错误路径可自定义,丰富的错误模板
性能快(v3.x 大幅优化)极快(Rust 核心,v2.x)中等
生态集成tRPC、NestJS、Express、HonoFastAPI(内置)、DjangoExpress、Hapi、NestJS
OpenAPI 生成zod-to-openapi✅ FastAPI 内置joi-to-swagger
AI 生成质量⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
推荐指数强烈推荐(TS 项目)强烈推荐(Python 项目)可用(遗留项目)

6.3 Zod 验证中间件实战

基础 Schema 定义模式

// schemas/user.ts — Zod Schema 最佳实践 import { z } from 'zod'; // 基础字段定义(可复用) const emailField = z.string().email('请输入有效的邮箱地址').max(255); const passwordField = z.string() .min(8, '密码至少 8 个字符') .max(128, '密码最多 128 个字符') .regex(/[A-Z]/, '密码必须包含至少一个大写字母') .regex(/[a-z]/, '密码必须包含至少一个小写字母') .regex(/[0-9]/, '密码必须包含至少一个数字'); const nameField = z.string().min(1).max(100).trim(); // 创建用户 Schema export const CreateUserSchema = z.object({ email: emailField, password: passwordField, name: nameField, }); // 更新用户 Schema(所有字段可选,使用 .partial()) export const UpdateUserSchema = CreateUserSchema .omit({ password: true }) // 更新时不允许直接修改密码 .partial(); // 所有字段变为可选 // 修改密码 Schema export const ChangePasswordSchema = z.object({ currentPassword: z.string().min(1), newPassword: passwordField, confirmPassword: z.string(), }).refine( (data) => data.newPassword === data.confirmPassword, { message: '两次输入的密码不一致', path: ['confirmPassword'] } ); // 查询参数 Schema export const UserQuerySchema = z.object({ search: z.string().max(100).optional(), role: z.enum(['ADMIN', 'MEMBER', 'VIEWER']).optional(), cursor: z.string().cuid2().optional(), limit: z.coerce.number().int().min(1).max(100).default(20), sortBy: z.enum(['name', 'email', 'createdAt']).default('createdAt'), sortDir: z.enum(['asc', 'desc']).default('desc'), }); // 类型导出(从 Schema 自动推断) export type CreateUserInput = z.infer<typeof CreateUserSchema>; export type UpdateUserInput = z.infer<typeof UpdateUserSchema>; export type UserQuery = z.infer<typeof UserQuerySchema>;

Express 验证中间件

// middleware/validate.ts — 通用 Zod 验证中间件 import { Request, Response, NextFunction } from 'express'; import { ZodSchema, ZodError } from 'zod'; type ValidationTarget = 'body' | 'query' | 'params'; interface ValidationConfig { body?: ZodSchema; query?: ZodSchema; params?: ZodSchema; } export function validate(config: ValidationConfig) { return (req: Request, res: Response, next: NextFunction) => { const errors: Array<{ target: ValidationTarget; issues: Array<{ path: string; message: string }>; }> = []; for (const [target, schema] of Object.entries(config)) { if (!schema) continue; const result = schema.safeParse(req[target as ValidationTarget]); if (!result.success) { errors.push({ target: target as ValidationTarget, issues: result.error.issues.map((issue) => ({ path: issue.path.join('.'), message: issue.message, })), }); } else { // 用验证后的数据替换原始数据(包含默认值和类型转换) (req as any)[target] = result.data; } } if (errors.length > 0) { return res.status(422).json({ type: 'https://api.example.com/errors/validation', title: 'Validation Error', status: 422, detail: 'One or more fields failed validation', errors, }); } next(); }; } // 使用示例 import { CreateUserSchema, UserQuerySchema } from '../schemas/user'; router.post( '/users', validate({ body: CreateUserSchema }), userController.create ); router.get( '/users', validate({ query: UserQuerySchema }), userController.list );

6.4 Pydantic 验证实战(FastAPI)

# schemas/user.py — Pydantic v2 Schema from pydantic import BaseModel, EmailStr, Field, field_validator from typing import Optional from enum import Enum from datetime import datetime import re class UserRole(str, Enum): ADMIN = "admin" MEMBER = "member" VIEWER = "viewer" class SortDirection(str, Enum): ASC = "asc" DESC = "desc" class CreateUserRequest(BaseModel): email: EmailStr = Field(..., max_length=255) password: str = Field(..., min_length=8, max_length=128) name: str = Field(..., min_length=1, max_length=100) @field_validator("password") @classmethod def validate_password_strength(cls, v: str) -> str: if not re.search(r"[A-Z]", v): raise ValueError("密码必须包含至少一个大写字母") if not re.search(r"[a-z]", v): raise ValueError("密码必须包含至少一个小写字母") if not re.search(r"[0-9]", v): raise ValueError("密码必须包含至少一个数字") return v @field_validator("name") @classmethod def strip_name(cls, v: str) -> str: return v.strip() class UpdateUserRequest(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) email: Optional[EmailStr] = Field(None, max_length=255) class UserQueryParams(BaseModel): search: Optional[str] = Field(None, max_length=100) role: Optional[UserRole] = None cursor: Optional[str] = None limit: int = Field(default=20, ge=1, le=100) sort_by: str = Field(default="created_at") sort_dir: SortDirection = Field(default=SortDirection.DESC) class UserResponse(BaseModel): id: str email: str name: str role: UserRole created_at: datetime updated_at: datetime model_config = {"from_attributes": True}
# routes/user.py — FastAPI 路由(Pydantic 自动验证 + OpenAPI 文档生成) from fastapi import APIRouter, Depends, HTTPException, Query from typing import Annotated from ..schemas.user import ( CreateUserRequest, UpdateUserRequest, UserQueryParams, UserResponse, ) from ..services.user import UserService from ..dependencies import get_current_user, get_user_service router = APIRouter(prefix="/api/v1/users", tags=["Users"]) @router.post("/", response_model=UserResponse, status_code=201) async def create_user( body: CreateUserRequest, # Pydantic 自动验证请求体 service: Annotated[UserService, Depends(get_user_service)], ): """创建新用户。密码要求:至少 8 位,包含大小写字母和数字。""" return await service.create(body) @router.get("/", response_model=list[UserResponse]) async def list_users( params: Annotated[UserQueryParams, Query()], # 自动验证查询参数 current_user=Depends(get_current_user), service: Annotated[UserService, Depends(get_user_service)], ): """获取用户列表,支持搜索、过滤和分页。""" return await service.list(params) @router.patch("/{user_id}", response_model=UserResponse) async def update_user( user_id: str, body: UpdateUserRequest, current_user=Depends(get_current_user), service: Annotated[UserService, Depends(get_user_service)], ): """更新用户信息。仅传入需要修改的字段。""" return await service.update(user_id, body)

6.5 验证中间件的 AI 生成提示词模板

请为以下 API 端点生成输入验证 Schema: ## 技术栈 - 验证库:[Zod / Pydantic / Joi] - 框架:[Express / NestJS / FastAPI / Hono] ## 端点列表 [列出每个端点的路径、方法、参数] ## 验证要求 - 字符串字段:最小/最大长度、格式(email/url/uuid)、trim - 数字字段:最小/最大值、整数/浮点数 - 枚举字段:明确列出允许的值 - 日期字段:格式验证、范围限制 - 数组字段:最小/最大长度、元素类型验证 - 嵌套对象:递归验证 - 可选字段:明确标注,提供默认值 - 自定义验证:[描述业务规则] ## 安全要求 - 所有字符串输入必须有最大长度限制(防止 DoS) - 分页 limit 参数必须有上限(如 100) - ID 参数必须验证格式(CUID2/UUID) - 禁止接受未定义的额外字段(strict mode) ## 输出要求 - 创建和更新使用不同的 Schema(更新字段可选) - 导出 TypeScript 类型(从 Schema 推断) - 包含自定义错误消息(中文)

7. OpenAPI 文档自动生成

7.1 文档生成策略对比

API 文档是开发者体验的关键组成部分。2025-2026 年,AI 驱动的文档生成工具正在改变 API 文档的创建方式。

策略工具优点缺点推荐场景
Schema-First 生成Swagger UI、Scalar、Redocly文档与实现始终一致需要维护 Schema 文件公开 API、团队协作
Code-First 提取NestJS Swagger、FastAPI 内置开发速度快,无需额外文件文档质量依赖代码注释内部 API、快速原型
AI 辅助生成Theneo、Mintlify、AI Agent可从代码/Postman 集合生成可能不够精确遗留 API 文档补全
Zod-to-OpenAPI@asteasolutions/zod-to-openapiZod Schema 即文档仅限 TypeScripttRPC/Express + Zod 项目

7.2 NestJS + Swagger 自动文档生成

// main.ts — NestJS Swagger 配置 import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // Swagger 文档配置 const config = new DocumentBuilder() .setTitle('项目管理 API') .setDescription('多租户项目管理 SaaS 的 RESTful API') .setVersion('1.0.0') .addBearerAuth( { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' }, 'JWT-auth' ) .addTag('Projects', '项目管理') .addTag('Tasks', '任务管理') .addTag('Users', '用户管理') .addServer('https://api.example.com', '生产环境') .addServer('http://localhost:3000', '开发环境') .build(); const document = SwaggerModule.createDocument(app, config); // 导出 OpenAPI JSON(用于客户端代码生成) const fs = await import('fs'); fs.writeFileSync('./openapi.json', JSON.stringify(document, null, 2)); // 挂载 Swagger UI SwaggerModule.setup('docs', app, document, { swaggerOptions: { persistAuthorization: true, tagsSorter: 'alpha', operationsSorter: 'alpha', }, }); await app.listen(3000); } bootstrap();
// dto/create-task.dto.ts — 使用装饰器生成文档 import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsString, IsEnum, IsOptional, MinLength, MaxLength } from 'class-validator'; export class CreateTaskDto { @ApiProperty({ description: '任务标题', example: '实现用户注册 API', minLength: 1, maxLength: 200, }) @IsString() @MinLength(1) @MaxLength(200) title: string; @ApiPropertyOptional({ description: '任务描述', example: '包含邮箱验证和密码强度检查', maxLength: 5000, }) @IsOptional() @IsString() @MaxLength(5000) description?: string; @ApiPropertyOptional({ description: '优先级', enum: ['LOW', 'MEDIUM', 'HIGH', 'URGENT'], default: 'MEDIUM', }) @IsOptional() @IsEnum(['LOW', 'MEDIUM', 'HIGH', 'URGENT']) priority?: string; }

7.3 FastAPI 内置文档生成

FastAPI 的一大优势是 Pydantic 模型自动生成 OpenAPI 文档,无需额外配置:

# main.py — FastAPI 自动文档 from fastapi import FastAPI from fastapi.openapi.utils import get_openapi app = FastAPI( title="项目管理 API", description="多租户项目管理 SaaS 的 RESTful API", version="1.0.0", docs_url="/docs", # Swagger UI redoc_url="/redoc", # ReDoc openapi_url="/openapi.json", ) # 自定义 OpenAPI Schema def custom_openapi(): if app.openapi_schema: return app.openapi_schema openapi_schema = get_openapi( title=app.title, version=app.version, description=app.description, routes=app.routes, ) # 添加安全方案 openapi_schema["components"]["securitySchemes"] = { "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", } } openapi_schema["security"] = [{"BearerAuth": []}] app.openapi_schema = openapi_schema return app.openapi_schema app.openapi = custom_openapi

7.4 Zod-to-OpenAPI(TypeScript 推荐方案)

对于使用 Zod 的 TypeScript 项目,@asteasolutions/zod-to-openapi 可以从 Zod Schema 直接生成 OpenAPI 文档:

// openapi.ts — 从 Zod Schema 生成 OpenAPI 文档 import { OpenAPIRegistry, OpenApiGeneratorV31, extendZodWithOpenApi, } from '@asteasolutions/zod-to-openapi'; import { z } from 'zod'; extendZodWithOpenApi(z); const registry = new OpenAPIRegistry(); // 注册 Schema const TaskSchema = z.object({ id: z.string().cuid2().openapi({ example: 'clx1234567890' }), title: z.string().min(1).max(200).openapi({ example: '实现用户注册 API' }), status: z.enum(['TODO', 'IN_PROGRESS', 'IN_REVIEW', 'DONE']), priority: z.enum(['LOW', 'MEDIUM', 'HIGH', 'URGENT']), createdAt: z.string().datetime(), }).openapi('Task'); const CreateTaskSchema = z.object({ title: z.string().min(1).max(200), description: z.string().max(5000).optional(), priority: z.enum(['LOW', 'MEDIUM', 'HIGH', 'URGENT']).default('MEDIUM'), }).openapi('CreateTaskInput'); // 注册端点 registry.registerPath({ method: 'post', path: '/api/v1/tasks', summary: '创建任务', tags: ['Tasks'], request: { body: { content: { 'application/json': { schema: CreateTaskSchema } }, }, }, responses: { 201: { description: '任务创建成功', content: { 'application/json': { schema: TaskSchema } }, }, 422: { description: '输入验证失败', }, }, }); // 生成 OpenAPI 文档 const generator = new OpenApiGeneratorV31(registry.definitions); const document = generator.generateDocument({ openapi: '3.1.0', info: { title: '项目管理 API', version: '1.0.0' }, servers: [{ url: 'https://api.example.com' }], }); // 导出为 JSON 文件 import fs from 'fs'; fs.writeFileSync('openapi.json', JSON.stringify(document, null, 2));

7.5 文档生成的 AI 提示词模板

请为以下 API 端点生成完整的 OpenAPI 3.1 文档: ## 端点列表 [列出所有端点的路径、方法、参数、请求体、响应] ## 文档要求 - 每个端点包含 summary 和 description(中文) - 每个参数包含 description 和 example - 每个 Schema 包含 example 值 - 包含认证安全方案(Bearer Token) - 包含标准错误响应(400, 401, 403, 404, 422, 500) - 使用 $ref 引用共享的 Schema 组件 - 包含 tags 分组 ## 输出格式 - YAML 格式 - 符合 OpenAPI 3.1.0 规范 - 可直接导入 Swagger UI / Scalar / Redocly

8. API 版本管理策略

8.1 版本管理方式对比

API 版本管理是后端开发中最容易被忽视但影响深远的决策之一。选择错误的版本策略可能导致维护噩梦。

策略示例优点缺点推荐场景
URL 路径版本/api/v1/users直观、缓存友好、易于路由URL 变长、版本间代码重复公开 API(最常用,约 70% 采用)
Header 版本Accept: application/vnd.api+json;version=1URL 干净、灵活不直观、调试困难内部 API、高级场景
Query 参数版本/api/users?version=1简单、向后兼容缓存不友好、不够规范简单 API、过渡方案
日期版本/api/2025-01-15/users精确、适合频繁变更版本号不直观Stripe 风格的 API
无版本(演进式)/api/users + 向后兼容最简单、无版本管理开销需要严格的兼容性纪律内部微服务通信

8.2 推荐的版本管理实践

URL 路径版本(推荐默认方案)

// NestJS — URL 路径版本管理 // main.ts import { VersioningType } from '@nestjs/common'; app.enableVersioning({ type: VersioningType.URI, defaultVersion: '1', prefix: 'api/v', }); // controllers/user.controller.ts @Controller({ path: 'users', version: '1' }) export class UserControllerV1 { @Get() findAll() { return this.userService.findAllV1(); } } @Controller({ path: 'users', version: '2' }) export class UserControllerV2 { @Get() findAll() { // V2 返回不同的响应格式 return this.userService.findAllV2(); } }

版本废弃策略

// middleware/deprecation.ts — 版本废弃通知中间件 import { Request, Response, NextFunction } from 'express'; interface VersionConfig { current: string; supported: string[]; deprecated: Record<string, { sunset: string; successor: string }>; } const versionConfig: VersionConfig = { current: 'v2', supported: ['v1', 'v2'], deprecated: { v1: { sunset: '2026-06-01', successor: 'v2', }, }, }; export function versionDeprecationMiddleware( req: Request, res: Response, next: NextFunction ) { const version = req.path.match(/\/api\/(v\d+)\//)?.[1]; if (!version) return next(); const deprecation = versionConfig.deprecated[version]; if (deprecation) { res.setHeader('Deprecation', 'true'); res.setHeader('Sunset', deprecation.sunset); res.setHeader( 'Link', `</api/${deprecation.successor}${req.path.replace(`/api/${version}`, '')}>; rel="successor-version"` ); // 可选:记录废弃版本的使用情况 console.warn( `[DEPRECATED] ${version} API called: ${req.method} ${req.path}` ); } next(); }

8.3 AI 辅助版本迁移

当需要从 v1 迁移到 v2 时,AI 可以辅助生成迁移代码和兼容层:

提示词模板:

请帮我将以下 API 从 v1 迁移到 v2: ## v1 API 定义 [粘贴 v1 的 OpenAPI 规范或代码] ## v2 变更列表 - [描述每个破坏性变更] - 例如:User 响应中 fullName 拆分为 firstName + lastName - 例如:分页从 offset 改为 cursor - 例如:错误格式从自定义改为 RFC 7807 ## 要求 1. 生成 v2 的 Controller/Router 代码 2. 生成 v1 → v2 的兼容适配层(让 v1 调用者平滑过渡) 3. 生成迁移指南文档(面向 API 消费者) 4. v1 添加 Deprecation 响应头 5. 包含版本路由配置

9. AI 辅助 API 设计的完整工作流

操作步骤

步骤 1:需求分析与资源建模

使用 AI 从业务需求中提取 API 资源和关系:

请分析以下业务需求,提取 API 资源模型: ## 业务需求 [描述业务场景] ## 输出要求 1. 核心资源列表(名称、描述、关键属性) 2. 资源间关系图(Mermaid ER 图) 3. 每个资源的 CRUD 需求分析 4. 非 CRUD 操作识别(如"审批"、"发布"、"归档") 5. 建议的 URL 结构

步骤 2:Schema 设计

根据资源模型,使用 AI 生成 API Schema(OpenAPI/GraphQL SDL/Zod)。

步骤 3:Mock 服务生成

在实现代码之前,先生成 Mock 服务供前端开发使用:

# 使用 Prism 从 OpenAPI 生成 Mock 服务 npx @stoplight/prism-cli mock openapi.yaml --port 4010 # 使用 MSW(Mock Service Worker)生成前端 Mock # AI 可以从 OpenAPI 规范生成 MSW handlers

步骤 4:实现代码生成

使用 AI 基于 Schema 生成服务端实现代码(见第 3-5 节)。

步骤 5:测试生成

请基于以下 OpenAPI 规范生成 API 集成测试: ## OpenAPI 规范 [粘贴规范] ## 测试框架 - [Jest + Supertest / Pytest + httpx / Go testing] ## 测试覆盖要求 - 每个端点的正常路径(200/201) - 输入验证失败(422) - 认证失败(401) - 权限不足(403) - 资源不存在(404) - 分页边界(空列表、最后一页) - 并发创建(幂等性验证)

步骤 6:文档生成与发布

使用 Scalar 或 Redocly 渲染 OpenAPI 文档:

# 使用 Scalar 渲染美观的 API 文档 npx @scalar/cli serve openapi.yaml --port 3100 # 使用 Redocly 生成静态文档站点 npx @redocly/cli build-docs openapi.yaml --output docs/api/index.html

实战案例:用 AI 从零设计并生成一个电商 API

案例背景

为一个中型电商平台设计和生成后端 API,技术栈为 TypeScript + NestJS + Prisma + PostgreSQL,采用 Schema-First 方法论。

步骤 1:需求分析(AI 辅助资源建模)

向 AI 描述业务需求:

我需要为一个电商平台设计 API,核心功能包括: 1. 商品管理(CRUD、分类、搜索、库存管理) 2. 购物车(添加/移除/更新数量) 3. 订单(创建、支付、发货、退款) 4. 用户(注册、登录、地址管理) 请提取资源模型和 URL 结构。

AI 输出资源模型:

核心资源: - Product(商品): id, name, description, price, stock, categoryId, images, status - Category(分类): id, name, slug, parentId - Cart(购物车): id, userId, items[] - CartItem(购物车项): id, cartId, productId, quantity - Order(订单): id, userId, items[], status, totalAmount, shippingAddress - OrderItem(订单项): id, orderId, productId, quantity, unitPrice - User(用户): id, email, name, addresses[] - Address(地址): id, userId, street, city, state, zipCode, isDefault URL 结构: /api/v1/products — 商品 CRUD + 搜索 /api/v1/categories — 分类 CRUD /api/v1/cart — 当前用户购物车 /api/v1/cart/items — 购物车项操作 /api/v1/orders — 订单 CRUD /api/v1/orders/:id/pay — 支付(非 CRUD 操作) /api/v1/orders/:id/ship — 发货(非 CRUD 操作) /api/v1/orders/:id/refund — 退款(非 CRUD 操作) /api/v1/users/me — 当前用户信息 /api/v1/users/me/addresses — 地址管理

步骤 2:Schema 设计(AI 生成 OpenAPI)

AI 生成关键部分的 OpenAPI Schema(以订单为例):

# 订单相关端点(OpenAPI 3.1 片段) paths: /api/v1/orders: post: operationId: createOrder summary: 创建订单 tags: [Orders] requestBody: required: true content: application/json: schema: type: object required: [shippingAddressId] properties: shippingAddressId: type: string description: 收货地址 ID note: type: string maxLength: 500 description: 订单备注 responses: '201': description: 订单创建成功 content: application/json: schema: $ref: '#/components/schemas/OrderResponse' '400': description: 购物车为空或库存不足 /api/v1/orders/{orderId}/pay: post: operationId: payOrder summary: 支付订单 tags: [Orders] parameters: - name: orderId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: type: object required: [paymentMethod] properties: paymentMethod: type: string enum: [credit_card, alipay, wechat_pay] paymentToken: type: string description: 支付网关返回的 token responses: '200': description: 支付成功 '402': description: 支付失败 '409': description: 订单状态不允许支付

步骤 3:验证 Schema 生成(Zod)

AI 基于 OpenAPI Schema 生成 Zod 验证:

// schemas/order.ts import { z } from 'zod'; export const PaymentMethod = z.enum(['credit_card', 'alipay', 'wechat_pay']); export const CreateOrderSchema = z.object({ shippingAddressId: z.string().cuid2(), note: z.string().max(500).optional(), }); export const PayOrderSchema = z.object({ paymentMethod: PaymentMethod, paymentToken: z.string().min(1).optional(), }); export const OrderQuerySchema = z.object({ status: z.enum([ 'PENDING', 'PAID', 'SHIPPED', 'DELIVERED', 'CANCELLED', 'REFUNDED' ]).optional(), cursor: z.string().optional(), limit: z.coerce.number().int().min(1).max(50).default(20), });

步骤 4:Controller 生成

AI 生成 NestJS Controller(关键部分):

// controllers/order.controller.ts @Controller('api/v1/orders') @UseGuards(JwtAuthGuard) @ApiTags('Orders') export class OrderController { constructor(private readonly orderService: OrderService) {} @Post() @HttpCode(HttpStatus.CREATED) @ApiOperation({ summary: '创建订单(从购物车)' }) async create( @CurrentUser() user: AuthUser, @Body(new ZodValidationPipe(CreateOrderSchema)) dto: CreateOrderInput, ) { return this.orderService.createFromCart(user.id, dto); } @Post(':orderId/pay') @ApiOperation({ summary: '支付订单' }) async pay( @CurrentUser() user: AuthUser, @Param('orderId') orderId: string, @Body(new ZodValidationPipe(PayOrderSchema)) dto: PayOrderInput, ) { return this.orderService.processPayment(user.id, orderId, dto); } @Post(':orderId/refund') @Roles('ADMIN') @UseGuards(RolesGuard) @ApiOperation({ summary: '退款(仅管理员)' }) async refund( @Param('orderId') orderId: string, @Body() dto: RefundOrderDto, ) { return this.orderService.processRefund(orderId, dto); } }

步骤 5:安全审查

AI 对生成的 API 进行安全审查,发现以下问题:

严重程度问题修复
Critical创建订单时未验证库存充足性(可能超卖)在 Service 层添加库存检查 + 数据库事务 + 乐观锁
High支付端点缺少幂等性保护(重复支付风险)添加幂等键(Idempotency-Key header)
High退款端点仅检查角色,未验证订单归属添加订单归属验证
Medium订单查询未限制只能查看自己的订单添加 userId 过滤条件
Low缺少请求速率限制添加 @Throttle() 装饰器

案例分析

关键决策点:

  1. Schema-First 的价值:先定义 OpenAPI Schema,确保了前后端对 API 契约的共识。前端团队可以立即基于 Schema 生成 Mock 数据和类型定义,无需等待后端实现
  2. 非 CRUD 操作的设计:支付、发货、退款等操作使用 POST /orders/:id/pay 风格,而非 PATCH /orders/:id,因为这些是有副作用的业务操作,不是简单的状态更新
  3. 安全审查的必要性:AI 生成的 CRUD 代码质量很高,但涉及支付、库存等业务关键路径时,必须人工审查并补充安全措施(幂等性、事务、乐观锁)

学习要点:

  • Schema-First + AI 生成是目前最高效的 API 开发方式——Schema 作为”单一事实来源”,AI 从 Schema 生成实现代码、验证逻辑、文档和测试
  • 非 CRUD 操作(状态转换、业务动作)是 AI 生成的薄弱环节,需要人工设计 URL 结构和业务逻辑
  • 安全审查应该是 API 开发流程的固定环节,特别是涉及金融交易和数据修改的端点

避坑指南

❌ 常见错误

  1. 跳过 Schema 设计直接让 AI 写代码

    • 问题:没有明确的 API 契约,AI 生成的不同端点可能风格不一致——有的用 camelCase,有的用 snake_case;有的返回数组,有的返回包装对象;错误格式各不相同。这在多人协作时尤其致命
    • 正确做法:先用 AI 生成 OpenAPI/GraphQL Schema/Zod Schema,审查确认后再生成实现代码。Schema 是”单一事实来源”,所有代码从 Schema 派生
  2. AI 生成的验证 Schema 缺少安全约束

    • 问题:AI 生成的 Zod/Pydantic Schema 通常只包含基本类型检查,缺少关键的安全约束:字符串没有最大长度限制(可被用于 DoS 攻击)、数字没有范围限制、分页 limit 没有上限、ID 格式未验证
    • 正确做法:在 Steering 规则中明确要求”所有字符串字段必须有 maxLength,所有数字字段必须有 min/max,分页 limit 上限为 100,ID 必须验证格式”。审查每个 Schema 的安全约束
  3. GraphQL 未防护 N+1 查询

    • 问题:AI 生成的 GraphQL Resolver 通常直接在关联字段中调用数据库查询,导致严重的 N+1 问题。例如查询 100 个任务的创建者,会触发 100 次用户查询
    • 正确做法:在 Prompt 中明确要求”所有关联字段使用 DataLoader 批量加载”。同时配置查询深度限制和复杂度分析,防止恶意的深层嵌套查询
  4. tRPC 项目中 Schema 和 Router 混在一起

    • 问题:AI 倾向于在 Router 文件中直接定义 Zod Schema(内联定义),导致 Schema 无法复用、难以测试、前后端无法共享类型
    • 正确做法:将 Zod Schema 独立到 schemas/ 目录,Router 文件只引用 Schema。这样 Schema 可以在前端、后端、测试中复用
  5. API 版本管理从一开始就被忽略

    • 问题:项目初期不考虑版本管理,等到需要破坏性变更时才发现没有版本策略,被迫在不兼容的情况下修改 API,导致客户端崩溃
    • 正确做法:从第一天起就使用 URL 路径版本(/api/v1/)。即使短期内不需要 v2,版本前缀的成本几乎为零,但未来的灵活性极高
  6. 让 AI 生成 API 时不指定错误响应格式

    • 问题:如果不明确要求,AI 会为每个端点生成不同的错误格式——有的返回 { error: "message" },有的返回 { message: "...", code: "..." },有的直接返回字符串。前端处理错误时需要为每个端点写不同的逻辑
    • 正确做法:在 Prompt 和 Steering 规则中指定统一的错误格式(推荐 RFC 7807 Problem Details)。所有端点的错误响应必须遵循同一格式
  7. GraphQL Schema 设计中滥用 nullable 字段

    • 问题:AI 生成的 GraphQL Schema 倾向于将大量字段标记为 nullable(可空),因为这样”更安全”。但过多的 nullable 字段会让客户端代码充满空值检查,降低类型安全的价值
    • 正确做法:遵循”默认 non-null,显式标记 nullable”的原则。只有在业务上确实可能为空的字段才标记为 nullable。在 Prompt 中明确要求”字段默认 non-null,仅在 [列出字段] 使用 nullable”
  8. 忽略 API 的幂等性设计

    • 问题:AI 生成的 POST 端点通常不考虑幂等性。如果客户端因网络问题重试请求,可能导致重复创建资源(重复订单、重复支付等)
    • 正确做法:对于有副作用的操作(创建订单、支付、发送通知),要求 AI 实现幂等键(Idempotency-Key header)机制。在 Steering 规则中标注哪些端点需要幂等性保护
  9. REST API 中混用 PUT 和 PATCH

    • 问题:AI 有时混淆 PUT(全量替换)和 PATCH(部分更新)的语义,生成的 PUT 端点实际上只更新传入的字段(PATCH 行为),或者 PATCH 端点要求传入所有字段(PUT 行为)
    • 正确做法:在 Prompt 中明确指定”使用 PATCH 进行部分更新(仅更新传入的字段),不使用 PUT”。大多数现代 API 只需要 PATCH,不需要 PUT
  10. OpenAPI 文档与实际 API 行为不一致

    • 问题:Code-First 方式生成的 OpenAPI 文档可能与实际 API 行为不一致——文档说必填的字段实际上可选,文档说返回 200 实际返回 201,文档中的 example 值与实际格式不匹配
    • 正确做法:使用契约测试(如 Schemathesis、Dredd)自动验证 API 实现是否符合 OpenAPI 规范。将契约测试集成到 CI/CD 管线中

✅ 最佳实践

  1. Schema-First 是默认选择:无论使用 REST、GraphQL 还是 tRPC,都应该先定义数据契约(OpenAPI/SDL/Zod Schema),再生成实现代码。这是 AI 辅助 API 开发中收益最高的实践

  2. 验证 Schema 即文档:使用 Zod/Pydantic 定义的验证 Schema 应该同时作为 API 文档的数据源。避免维护两套定义(验证 + 文档)

  3. 统一错误格式从第一天开始:选择 RFC 7807 Problem Details 或类似的标准格式,在项目初始化时就配置好全局错误处理中间件

  4. 分页策略统一:所有列表端点使用相同的分页方式(推荐 cursor-based)。在 Steering 规则中固定分页参数名和响应格式

  5. AI 生成 + 契约测试:让 AI 生成 API 代码后,使用契约测试工具自动验证实现是否符合 Schema。这是验证 AI 输出质量的最可靠方式

  6. 安全验证是 Schema 的一部分:不要把安全验证(长度限制、格式检查、范围约束)当作”额外工作”——它们应该直接定义在 Schema 中,与业务验证一起执行

  7. 版本策略写入 Steering 规则:将 API 版本管理策略(URL 路径版本、废弃通知、迁移周期)写入 Steering 规则,确保 AI 生成的每个端点都遵循版本规范

  8. GraphQL 必须配置安全防护:查询深度限制、复杂度分析、DataLoader 批量加载——这三项是 GraphQL API 的必备安全措施,必须在项目初始化时就配置好


相关资源与延伸阅读

规范与标准

  1. OpenAPI Specification 3.1.0  — REST API 描述的行业标准规范,完全兼容 JSON Schema 2020-12
  2. GraphQL 官方规范  — GraphQL 查询语言和类型系统的官方规范文档
  3. RFC 7807 — Problem Details for HTTP APIs  — HTTP API 错误响应的标准格式

工具与框架

  1. tRPC v11 官方文档  — tRPC v11 的完整文档,包含 Next.js、React Query 集成指南
  2. Zod 官方文档  — TypeScript-first 的 Schema 验证库,广泛用于 tRPC 和 API 验证
  3. Pydantic v2 官方文档  — Python 的数据验证库,FastAPI 的核心依赖
  4. Scalar — 现代 API 文档渲染  — 开源的 OpenAPI 文档渲染工具,替代 Swagger UI
  5. GraphQL Code Generator  — 从 GraphQL Schema 生成 TypeScript 类型和 SDK

深度阅读

  1. Generating OpenAPI Specifications from API Documentation with LLMs  — 使用大语言模型从 API 文档自动生成 OpenAPI 规范的研究论文
  2. AI-Powered API Documentation and Client Generation (2026)  — AI 驱动的 API 文档和客户端生成的最新实践综述

参考来源


📖 返回 总览与导航 | 上一节:28a-AI辅助后端开发概览 | 下一节:28c-Spec-Driven业务逻辑

Last updated on