# API Design

> API工程师技能 - API设计规范、版本控制、错误处理、并发安全、性能优化、文档。当你新建/修改任何API端点、路由、控制器、HTTP请求处理、响应格式、中间件时必须使用此技能。即使用户只是说"加个接口"或"改下返回值"，也应触发。

- Skill: `yuexueyu/api-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yuexueyu/api-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yuexueyu/api-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: yuexueyu (https://skillmd.com/u/yuexueyu)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/yuexueyu/api-design

---


# API工程师技能 (API Engineer Skill)

## 快速规则（日常开发时自动加载，只需读到这里）

> **[API核心清单]** ① 资源用名词复数+≤2层嵌套，❌动词URL ② 统一`{code,data,message}`响应，列表必须分页(默认20最大100) ③ 新端点默认需认证，CRUD必须验资源所有权
> **[幂等三条]** POST用Idempotency-Key防重复，PUT/DELETE天然幂等，支付类必须服务端去重
> **[安全三禁]** ❌直接返回DB模型(用DTO) ❌返回密码hash/内部ID ❌500返回堆栈

写/改API端点时，强制遵守：
1. **URL规范**：资源用名词复数(`/users`)，嵌套≤2层，❌禁止动词URL(`/getUser`)（动词URL破坏REST语义，导致端点爆炸且无法统一缓存/权限策略）
2. **HTTP方法**：GET读(无副作用) POST创建 PUT替换 PATCH更新 DELETE删除，❌禁止POST做所有操作（丢失HTTP语义=无法利用缓存/幂等性/安全性约定，客户端无法预判行为）
3. **认证授权**：新端点默认需认证，CRUD必须验证资源所有权(防IDOR)，批量操作逐个验权
4. **响应格式**：统一`{code, data, message}`，列表带分页(默认20最大100)，空列表返回`[]`非`null`
5. **错误处理**：400参数错误(含字段详情) / 401未认证 / 403无权限 / 404不存在 / 422业务拒绝 / 500+唯一ID
6. **幂等安全**：POST创建必须有幂等键(Idempotency-Key)，支付类必须服务端去重
7. **性能**：列表必须分页，批量操作有上限，N+1查询→批量查询，大导出→异步+下载链接
8. **安全**：❌禁止直接返回DB模型(用DTO)（DB模型新增字段会意外暴露敏感数据） ❌禁止返回密码hash/内部ID（攻击者可离线破解或枚举内部资源） ❌禁止500返回堆栈（堆栈暴露框架版本/文件路径/SQL结构）

新增端点前：Grep确认无重复端点 → 确认命名风格一致 → 确认已加认证中间件

---

## 完整审查流程（手动 /api-design 或专项审查时执行）

### Phase 1: API现状扫描

1. 扫描所有API端点（Grep路由定义/Controller/Handler）：
   - 列出所有路由：HTTP方法 + 路径 + Handler函数 + 中间件
   - 识别端点完成度：已实现 / TODO占位 / 废弃未删除
   - 用MCP工具(desc_table/read_query)检查API关联的数据模型

2. 检查API一致性：
   - URL命名风格是否统一（kebab-case? camelCase? snake_case?）
   - 响应格式是否统一（所有端点是否用相同的响应结构）
   - 认证方式是否统一（JWT? Session? API Key? 混用?）
   - 错误格式是否统一（错误码体系是否一致）

### Phase 2: RESTful设计规范审查

3. **URL设计**：
   - 资源用名词复数：`/users`不是`/getUser`或`/user`
   - 嵌套关系：`/users/{id}/orders`（不超过2层嵌套）
   - 查询过滤：`/users?status=active&sort=-created_at`
   - ❌ 禁止：动词URL(`/getUsers`/`/deleteUser`)、深层嵌套(>2层)、无意义ID暴露（动词破坏统一性，深嵌套增加耦合度，暴露内部ID助力枚举攻击）

4. **HTTP方法**：
   - GET：读取，无副作用，可缓存
   - POST：创建新资源
   - PUT：完整替换资源
   - PATCH：部分更新资源
   - DELETE：删除资源
   - ❌ 禁止：用POST做所有操作、GET请求有副作用（POST做所有=丢失HTTP语义约定；GET有副作用=爬虫/预加载会触发数据变更）

5. **状态码规范**：

| 状态码 | 含义 | 使用场景 |
|--------|------|----------|
| 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: 请求与响应规范

6. **请求规范**：
   - 必须验证所有输入参数（类型/范围/长度/格式）
   - 验证失败返回具体字段和原因（不只说"参数错误"）
   - 分页参数：`page`+`page_size`或`cursor`+`limit`，有最大值限制
   - 排序参数：白名单校验可排序字段，防止任意字段排序导致慢查询
   - 文件上传：类型白名单+大小限制+文件名消毒

7. **响应格式**（全局统一）：

```json
// 成功
{
  "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/序列化器控制返回字段，而非直接返回数据库模型

8. **空值与默认值**：
   - 列表为空返回`[]`不是`null`
   - 可选字段缺失时有默认值，不是`undefined`
   - 数字字段缺失返回`0`不是`null`（除非null有语义意义）

### Phase 4: 认证与授权

9. **认证规范**：
   - 新端点**默认需认证**，公开端点用`@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（泄露后永久有效无法止血）

10. **授权规范**：
    - 每个CRUD操作必须验证资源所有权（防IDOR）
    - `GET /users/{id}/orders` → 必须验证当前用户有权查看该用户的订单
    - 批量操作必须逐个验证权限（不是只验证第一个）
    - 管理员操作必须有独立的权限检查（不只靠角色字段）
    - 权限检查在业务逻辑之前执行

### Phase 5: 错误处理与重试

11. **错误处理分层**：

| 层级 | 处理方式 | 示例 |
|------|----------|------|
| 参数验证层 | 返回400+具体字段错误 | 邮箱格式错误 |
| 业务逻辑层 | 返回422+业务原因 | 余额不足 |
| 权限层 | 返回401/403 | 未登录/无权限 |
| 基础设施层 | 返回503+重试提示 | 数据库连接失败 |
| 未知错误层 | 返回500+错误ID | 便于日志追踪 |

    - 每个500错误必须生成唯一ID，日志中可追踪
    - 生产环境500不返回堆栈，只返回错误ID
    - 第三方服务失败：返回503而非500，告知客户端可重试

12. **幂等性设计**：
    - POST创建：用幂等键(Idempotency-Key)防重复创建
    - PUT/DELETE：天然幂等（重复执行结果相同）
    - 支付/转账类：必须有幂等键+服务端去重
    - ❌ 禁止：POST创建无去重机制（网络重试=重复数据）

### Phase 6: 并发与性能

13. **并发安全**：
    - 乐观锁：更新时带版本号（`UPDATE ... WHERE version = ?`），冲突返回409
    - 限流：全局限流+按用户限流+按端点限流
    - 防重放：请求带时间戳+签名，过期请求拒绝
    - 长耗时操作：异步化（返回202 Accepted + 轮询/WebSocket通知）

14. **性能规范**：
    - 列表API必须分页（默认20条，最大100条）
    - 批量操作有上限（一次最多操作N个资源）
    - N+1查询检测：Grep循环中的数据库调用
    - 响应时间目标：P95 < 200ms（读）/ P95 < 500ms（写）
    - 大数据导出：流式返回或异步+下载链接，不在内存中拼接

15. **缓存策略**：
    - 读多写少的数据：Cache-Control / ETag / Redis缓存
    - 缓存失效策略：TTL + 主动失效（写入时清除相关缓存）
    - ❌ 禁止：缓存带认证的个人数据到公共CDN（个人数据被CDN缓存后，其他用户可能拿到别人的数据）

### Phase 7: 版本控制与兼容

16. **版本策略**：
    - URL路径版本：`/v1/users`、`/v2/users`
    - 旧版本维护期：至少维护2个版本，新版本稳定后废弃旧版
    - 废弃API：返回Deprecation头 + 文档标记 + 日志记录使用量

17. **向后兼容规则**：
    - ✅ 允许：新增可选字段、新增端点、放宽验证
    - ❌ 破坏性变更：删除字段、修改字段类型、改变语义、加严验证
    - 破坏性变更必须升版本号

### Phase 8: API文档与测试

18. **文档规范**：
    - 每个端点必须有：描述、请求参数、响应示例、错误码列表
    - 使用OpenAPI/Swagger自动生成文档（代码即文档）
    - 文档必须包含认证说明和速率限制说明

19. **测试覆盖**：
    - 每个端点至少覆盖：正常请求、参数缺失、参数非法、未认证、无权限、资源不存在
    - 边界测试：空列表、超长字符串、特殊字符、并发请求
    - 安全测试：SQL注入参数、XSS参数、超大请求体

### Phase 9: 输出报告

```
## API审查报告

### 端点清单
| 方法 | 路径 | Handler | 认证 | 状态 |

### 设计规范违规
| # | 端点 | 问题类型 | 描述 | 修复建议 | 严重度 |

### 安全问题
| # | 端点/文件:行号 | 问题 | 攻击场景 | 修复建议 | 严重度 |

### 性能风险
| # | 端点 | 问题 | 影响 | 优化方案 | 优先级 |

### 一致性问题
| 类别 | 当前状态 | 建议统一方案 |

### 缺失项
| 类别 | 缺失内容 | 建议 | 优先级 |
```

## API开发规则（写API代码时强制遵守）

### 新增端点前必须执行
1. Grep确认没有已存在的同功能端点
2. 确认URL命名与现有端点风格一致
3. 确认响应格式与全局统一格式一致
4. 确认已添加认证中间件（除非显式标记@public）

### 修改端点前必须执行
1. Grep所有调用方（前端/移动端/第三方）确认影响范围
2. 确认修改是否向后兼容，不兼容必须升版本号
3. 确认错误处理覆盖所有分支

### 写API代码强制规则
- ❌ 禁止直接返回数据库模型——用DTO控制返回字段（DB模型含密码hash/内部字段，泄露后可被攻击）
- ❌ 禁止GET请求有副作用（缓存/爨虫/预加载会意外触发修改，违反HTTP语义）
- ❌ 禁止POST创建无幂等机制（网络重试/用户双击=重复创建资源）
- ❌ 禁止列表API无分页（数据量增长后单次返回百万行，OOM或超时）
- ❌ 禁止无WHERE的UPDATE/DELETE暴露为API（一次调用可清空整张表）
- ✅ 所有输入必须验证（类型+范围+长度+格式）
- ✅ 所有CRUD必须验证资源所有权
- ✅ 500错误必须有唯一ID用于追踪

## 约束
- 所有发现必须有 端点路径 或 文件:行号 引用
- 安全问题必须附带攻击场景说明
- 性能建议必须基于实际查询模式
- API设计建议遵循最小权限原则

