| name | api-design |
| description | API工程师技能 - API设计规范、版本控制、错误处理、并发安全、性能优化、文档。当你新建/修改任何API端点、路由、控制器、HTTP请求处理、响应格式、中间件时必须使用此技能。即使用户只是说"加个接口"或"改下返回值",也应触发。 |
API工程师技能 (API Engineer Skill)
快速规则(日常开发时自动加载,只需读到这里)
[API核心清单] ① 资源用名词复数+≤2层嵌套,❌动词URL ② 统一{code,data,message}响应,列表必须分页(默认20最大100) ③ 新端点默认需认证,CRUD必须验资源所有权
[幂等三条] POST用Idempotency-Key防重复,PUT/DELETE天然幂等,支付类必须服务端去重
[安全三禁] ❌直接返回DB模型(用DTO) ❌返回密码hash/内部ID ❌500返回堆栈
写/改API端点时,强制遵守:
- URL规范:资源用名词复数(
/users),嵌套≤2层,❌禁止动词URL(/getUser)(动词URL破坏REST语义,导致端点爆炸且无法统一缓存/权限策略)
- HTTP方法:GET读(无副作用) POST创建 PUT替换 PATCH更新 DELETE删除,❌禁止POST做所有操作(丢失HTTP语义=无法利用缓存/幂等性/安全性约定,客户端无法预判行为)
- 认证授权:新端点默认需认证,CRUD必须验证资源所有权(防IDOR),批量操作逐个验权
- 响应格式:统一
{code, data, message},列表带分页(默认20最大100),空列表返回[]非null
- 错误处理:400参数错误(含字段详情) / 401未认证 / 403无权限 / 404不存在 / 422业务拒绝 / 500+唯一ID
- 幂等安全:POST创建必须有幂等键(Idempotency-Key),支付类必须服务端去重
- 性能:列表必须分页,批量操作有上限,N+1查询→批量查询,大导出→异步+下载链接
- 安全:❌禁止直接返回DB模型(用DTO)(DB模型新增字段会意外暴露敏感数据) ❌禁止返回密码hash/内部ID(攻击者可离线破解或枚举内部资源) ❌禁止500返回堆栈(堆栈暴露框架版本/文件路径/SQL结构)
新增端点前:Grep确认无重复端点 → 确认命名风格一致 → 确认已加认证中间件
完整审查流程(手动 /api-design 或专项审查时执行)
Phase 1: API现状扫描
-
扫描所有API端点(Grep路由定义/Controller/Handler):
- 列出所有路由:HTTP方法 + 路径 + Handler函数 + 中间件
- 识别端点完成度:已实现 / TODO占位 / 废弃未删除
- 用MCP工具(desc_table/read_query)检查API关联的数据模型
-
检查API一致性:
- URL命名风格是否统一(kebab-case? camelCase? snake_case?)
- 响应格式是否统一(所有端点是否用相同的响应结构)
- 认证方式是否统一(JWT? Session? API Key? 混用?)
- 错误格式是否统一(错误码体系是否一致)
Phase 2: RESTful设计规范审查
-
URL设计:
- 资源用名词复数:
/users不是/getUser或/user
- 嵌套关系:
/users/{id}/orders(不超过2层嵌套)
- 查询过滤:
/users?status=active&sort=-created_at
- ❌ 禁止:动词URL(
/getUsers//deleteUser)、深层嵌套(>2层)、无意义ID暴露(动词破坏统一性,深嵌套增加耦合度,暴露内部ID助力枚举攻击)
-
HTTP方法:
- GET:读取,无副作用,可缓存
- POST:创建新资源
- PUT:完整替换资源
- PATCH:部分更新资源
- DELETE:删除资源
- ❌ 禁止:用POST做所有操作、GET请求有副作用(POST做所有=丢失HTTP语义约定;GET有副作用=爬虫/预加载会触发数据变更)
-
状态码规范:
| 状态码 | 含义 | 使用场景 |
|---|
| 200 | 成功 | GET/PUT/PATCH/DELETE成功 |
| 201 | 已创建 | POST创建成功 |
| 204 | 无内容 | DELETE成功且无返回体 |
| 400 | 请求错误 | 参数验证失败、格式错误 |
| 401 | 未认证 | 未登录、Token过期 |
| 403 | 无权限 | 已认证但无权访问该资源 |
| 404 | 不存在 | 资源不存在 |
| 409 | 冲突 | 资源已存在、版本冲突 |
| 422 | 无法处理 | 参数合法但业务逻辑不允许 |
| 429 | 请求过多 | 速率限制 |
| 500 | 服务器错误 | 未预期的内部错误 |
- ❌ 禁止:所有错误都返回200+自定义code、所有错误都返回500(200+自定义code让客户端无法用HTTP状态码统一处理错误;全500丢失了错误类型信息)
Phase 3: 请求与响应规范
-
请求规范:
- 必须验证所有输入参数(类型/范围/长度/格式)
- 验证失败返回具体字段和原因(不只说"参数错误")
- 分页参数:
page+page_size或cursor+limit,有最大值限制
- 排序参数:白名单校验可排序字段,防止任意字段排序导致慢查询
- 文件上传:类型白名单+大小限制+文件名消毒
-
响应格式(全局统一):
{
"code": 0,
"data": { ... },
"message": "success"
}
{
"code": 0,
"data": {
"items": [ ... ],
"total": 100,
"page": 1,
"page_size": 20
}
}
{
"code": 40001,
"message": "用户友好的错误描述",
"details": [
{ "field": "email", "reason": "格式不正确" }
]
}
- ❌ 禁止:返回原始数据库错误/堆栈/内部路径(暴露数据库结构/框架版本/文件路径给攻击者)
- ❌ 禁止:返回不需要的字段如密码hash/内部ID/调试信息(扩大攻击面,hash可离线破解,内部ID可枚举)
- ✅ 用DTO/序列化器控制返回字段,而非直接返回数据库模型
- 空值与默认值:
- 列表为空返回
[]不是null
- 可选字段缺失时有默认值,不是
undefined
- 数字字段缺失返回
0不是null(除非null有语义意义)
Phase 4: 认证与授权
-
认证规范:
- 新端点默认需认证,公开端点用
@public显式标记
- Token必须:验签+检查过期+检查吊销(不能只解码不验证)
- 刷新Token机制:Access Token短期(15-30min) + Refresh Token长期(7-30天)
- Token存储:HttpOnly Cookie(Web) / Keychain(iOS) / KeyStore(Android)
- ❌ 禁止:Token在URL参数中传递(会被日志/Referer/浏览器历史记录泄露)、LocalStorage存Token(XSS可直接读取)、永不过期的Token(泄露后永久有效无法止血)
-
授权规范:
- 每个CRUD操作必须验证资源所有权(防IDOR)
GET /users/{id}/orders → 必须验证当前用户有权查看该用户的订单
- 批量操作必须逐个验证权限(不是只验证第一个)
- 管理员操作必须有独立的权限检查(不只靠角色字段)
- 权限检查在业务逻辑之前执行
Phase 5: 错误处理与重试
- 错误处理分层:
| 层级 | 处理方式 | 示例 |
|---|
| 参数验证层 | 返回400+具体字段错误 | 邮箱格式错误 |
| 业务逻辑层 | 返回422+业务原因 | 余额不足 |
| 权限层 | 返回401/403 | 未登录/无权限 |
| 基础设施层 | 返回503+重试提示 | 数据库连接失败 |
| 未知错误层 | 返回500+错误ID | 便于日志追踪 |
- 每个500错误必须生成唯一ID,日志中可追踪
- 生产环境500不返回堆栈,只返回错误ID
- 第三方服务失败:返回503而非500,告知客户端可重试
12. 幂等性设计:
- POST创建:用幂等键(Idempotency-Key)防重复创建
- PUT/DELETE:天然幂等(重复执行结果相同)
- 支付/转账类:必须有幂等键+服务端去重
- ❌ 禁止:POST创建无去重机制(网络重试=重复数据)
Phase 6: 并发与性能
-
并发安全:
- 乐观锁:更新时带版本号(
UPDATE ... WHERE version = ?),冲突返回409
- 限流:全局限流+按用户限流+按端点限流
- 防重放:请求带时间戳+签名,过期请求拒绝
- 长耗时操作:异步化(返回202 Accepted + 轮询/WebSocket通知)
-
性能规范:
- 列表API必须分页(默认20条,最大100条)
- 批量操作有上限(一次最多操作N个资源)
- N+1查询检测:Grep循环中的数据库调用
- 响应时间目标:P95 < 200ms(读)/ P95 < 500ms(写)
- 大数据导出:流式返回或异步+下载链接,不在内存中拼接
-
缓存策略:
- 读多写少的数据:Cache-Control / ETag / Redis缓存
- 缓存失效策略:TTL + 主动失效(写入时清除相关缓存)
- ❌ 禁止:缓存带认证的个人数据到公共CDN(个人数据被CDN缓存后,其他用户可能拿到别人的数据)
Phase 7: 版本控制与兼容
-
版本策略:
- URL路径版本:
/v1/users、/v2/users
- 旧版本维护期:至少维护2个版本,新版本稳定后废弃旧版
- 废弃API:返回Deprecation头 + 文档标记 + 日志记录使用量
-
向后兼容规则:
- ✅ 允许:新增可选字段、新增端点、放宽验证
- ❌ 破坏性变更:删除字段、修改字段类型、改变语义、加严验证
- 破坏性变更必须升版本号
Phase 8: API文档与测试
-
文档规范:
- 每个端点必须有:描述、请求参数、响应示例、错误码列表
- 使用OpenAPI/Swagger自动生成文档(代码即文档)
- 文档必须包含认证说明和速率限制说明
-
测试覆盖:
- 每个端点至少覆盖:正常请求、参数缺失、参数非法、未认证、无权限、资源不存在
- 边界测试:空列表、超长字符串、特殊字符、并发请求
- 安全测试:SQL注入参数、XSS参数、超大请求体
Phase 9: 输出报告
## API审查报告
### 端点清单
| 方法 | 路径 | Handler | 认证 | 状态 |
### 设计规范违规
| # | 端点 | 问题类型 | 描述 | 修复建议 | 严重度 |
### 安全问题
| # | 端点/文件:行号 | 问题 | 攻击场景 | 修复建议 | 严重度 |
### 性能风险
| # | 端点 | 问题 | 影响 | 优化方案 | 优先级 |
### 一致性问题
| 类别 | 当前状态 | 建议统一方案 |
### 缺失项
| 类别 | 缺失内容 | 建议 | 优先级 |
API开发规则(写API代码时强制遵守)
新增端点前必须执行
- Grep确认没有已存在的同功能端点
- 确认URL命名与现有端点风格一致
- 确认响应格式与全局统一格式一致
- 确认已添加认证中间件(除非显式标记@public)
修改端点前必须执行
- Grep所有调用方(前端/移动端/第三方)确认影响范围
- 确认修改是否向后兼容,不兼容必须升版本号
- 确认错误处理覆盖所有分支
写API代码强制规则
- ❌ 禁止直接返回数据库模型——用DTO控制返回字段(DB模型含密码hash/内部字段,泄露后可被攻击)
- ❌ 禁止GET请求有副作用(缓存/爨虫/预加载会意外触发修改,违反HTTP语义)
- ❌ 禁止POST创建无幂等机制(网络重试/用户双击=重复创建资源)
- ❌ 禁止列表API无分页(数据量增长后单次返回百万行,OOM或超时)
- ❌ 禁止无WHERE的UPDATE/DELETE暴露为API(一次调用可清空整张表)
- ✅ 所有输入必须验证(类型+范围+长度+格式)
- ✅ 所有CRUD必须验证资源所有权
- ✅ 500错误必须有唯一ID用于追踪
约束
- 所有发现必须有 端点路径 或 文件:行号 引用
- 安全问题必须附带攻击场景说明
- 性能建议必须基于实际查询模式
- API设计建议遵循最小权限原则