api-design
基于需求与设计文档生成可实施的 API 设计文档(接口契约、关键代码设计、错误码定义、请求/响应示例)。触发:"设计 API"、"接口设计"、"api design",或 design-craft 之后补充 API 设计细节。
SKILL.mdskills/api-design/SKILL.md
GitHubAPI Design(API 接口设计)
概述
目的:将设计文档中的 demo 级 API 示例升级为详细的、可实施的 API 设计文档
功能:基于需求文档和设计文档,生成包含完整接口契约、关键代码设计、错误码定义、请求/响应示例的 API 设计文档
使用场景:
- design-craft 完成设计文档后,作为后续步骤补充 API 设计细节
- 需要从 demo 级别升级为可实施的 API 设计时
- 用户明确要求"设计 API"、"写 API 文档"、"接口设计"时
定位
requirement-mining → design-craft → api-design(本 skill)
理解需求 技术设计 API 详细设计
- 输入:需求文档 + 设计文档(含 demo 接口参考)
- 输出:API 设计文档(详细接口契约 + 关键代码设计)
- 边界:只设计接口契约和关键代码骨架,不写完整实现代码
核心原则
- 契约优先:先定义接口契约(方法、路径、参数、返回值),再设计关键代码
- 独立设计:设计文档中的 demo 接口只是展示流程用的最简示意,便于理解设计意图。实际 API 设计时,必须基于当前的数据结构、业务场景、使用需求和约束条件,独立重新设计。demo 示例可能正确,也可能不完整或不匹配实际场景——重点是「经过独立判断后再决定是否采纳」,而非直接套用
- 关键代码:只写影响接口行为的关键代码(校验逻辑、状态转换、核心算法),不写样板代码
- 错误完备:每个接口必须定义完整的错误码和错误响应
- 示例真实:请求/响应示例必须是真实可用的,不能是占位符
工作流总览
阶段 1:输入收集 → 读取设计文档,提取 demo 接口和需求上下文
阶段 2:接口清单确认 → 识别所有需要设计的 API 接口
阶段 3:接口契约设计 → 为每个接口定义完整契约
阶段 4:关键代码设计 → 设计影响接口行为的关键代码
阶段 5:错误码与异常定义 → 定义统一的错误码体系
阶段 6:落盘输出 → 生成 API 设计文档
未得到用户对当前阶段的确认前,不进入下一阶段。
阶段 1:输入收集
1.1 读取设计文档
检查并读取以下输入:
设计文档(必需):
- 检查
.requirements/config获取storage_path - 读取
{storage_path}/{feature}/design/DESIGN.md(父文档) - 读取
{storage_path}/{feature}/design/S*.md(子文档) - 提取所有 demo 接口示例和接口设计章节
- 检查
需求文档(可选):
- 读取
{storage_path}/{feature}/requirement.md - 提取验收标准和非功能性约束
- 读取
依赖文档(可选):
- 检查
{storage_path}/{feature}/dependencies/目录 - 读取第三方 API 文档作为参考
- 检查
1.2 提取 demo 接口
从设计文档中提取所有 demo 接口示例:
⚠️ 重要提醒:设计文档中的 demo 接口仅作为理解设计意图的参考,是最简示意。这些 demo 可能缺少字段、参数不完整、错误处理缺失、数据结构与实际场景不匹配。真正的 API 设计必须基于需求文档中的业务场景、数据流图中的数据结构、以及实际使用约束独立重新设计,不可直接照搬 demo。
📥 输入收集
━━━━━━━━━━━━━━━━
【设计文档】
- 父文档:<路径>
- 子文档:<路径列表>
【demo 接口提取】
| 来源 | 接口路径 | 方法 | demo 状态 |
|------|----------|------|-----------|
| S-01 | /api/users | POST | 仅有响应示例 |
| S-02 | /api/orders/{id} | GET | 有请求+响应 |
【需求上下文】
- 功能描述:<摘要>
- 验收标准:<关键点>
请确认输入信息是否完整。
阶段 2:接口清单确认
基于设计文档的接口设计章节,列出所有需要详细设计的 API 接口。
2.1 接口识别规则
- 设计文档中标记为"新增"或"修改"的接口
- 设计文档中 demo 示例涉及的接口
- 需求文档中验收标准涉及的接口
2.2 输出格式
📋 API 接口清单
━━━━━━━━━━━━━━━━
| 编号 | 方法 | 路径 | 所属子需求 | 优先级 | demo 状态 |
|------|------|------|-----------|--------|-----------|
| API-01 | POST | /api/v1/users | S-01 用户模块 | P0 | 需补充 |
| API-02 | GET | /api/v1/users/{id} | S-01 用户模块 | P0 | 已有 demo |
| API-03 | PUT | /api/v1/users/{id} | S-01 用户模块 | P1 | 需补充 |
【接口分组】
- 用户模块(S-01):API-01, API-02, API-03
- 订单模块(S-02):API-04, API-05
请确认接口清单是否完整、优先级是否合理。
阶段 3:接口契约设计
为每个 API 接口定义完整契约。
3.1 契约模板
每个接口必须包含以下信息:
## API-XX:{接口名称}
### 基本信息
| 项目 | 值 |
|------|-----|
| 方法 | GET/POST/PUT/DELETE/PATCH |
| 路径 | /api/v1/{resource} |
| 认证 | Bearer Token / API Key / 无 |
| 权限 | {required_role} |
| 限流 | {rate_limit} |
| 幂等 | 是/否 |
### 请求参数
#### Path Parameters
| 参数 | 类型 | 必填 | 说明 | 示例 |
|------|------|------|------|------|
| id | string | 是 | 资源唯一标识 | usr_abc123 |
#### Query Parameters
| 参数 | 类型 | 必填 | 默认值 | 说明 | 示例 |
|------|------|------|--------|------|------|
| page | integer | 否 | 1 | 页码 | 1 |
| limit | integer | 否 | 20 | 每页数量 | 20 |
#### Request Body
```typescript
interface CreateUserRequest {
name: string; // 用户名,2-50 字符
email: string; // 邮箱,唯一
role?: "admin" | "user"; // 角色,默认 user
}
响应
成功响应(200/201)
interface CreateUserResponse {
code: 200;
data: {
id: string; // 用户 ID
name: string;
email: string;
role: string;
created_at: string; // ISO 8601
};
message: "success";
}
错误响应
| HTTP Status | 错误码 | 说明 | 触发条件 |
|---|---|---|---|
| 400 | INVALID_INPUT | 输入参数无效 | name 为空或超长 |
| 409 | EMAIL_EXISTS | 邮箱已存在 | email 唯一约束冲突 |
| 401 | UNAUTHORIZED | 未认证 | Token 无效或过期 |
| 403 | FORBIDDEN | 无权限 | 角色不满足 |
Demo 请求示例
curl -X POST https://api.example.com/api/v1/users \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "张三",
"email": "zhangsan@example.com",
"role": "user"
}'
Demo 响应示例
{
"code": 200,
"data": {
"id": "usr_abc123",
"name": "张三",
"email": "zhangsan@example.com",
"role": "user",
"created_at": "2026-06-22T10:30:00Z"
},
"message": "success"
}
### 3.2 契约设计规则
1. **RESTful 规范**:
- GET:查询,无 Request Body
- POST:创建,返回 201
- PUT:全量更新
- PATCH:部分更新
- DELETE:删除,返回 204 或 200
2. **版本控制**:路径中包含版本号 `/api/v1/`
3. **命名规范**:
- 路径:小写、连字符分隔 `/api/v1/user-profiles`
- 参数:snake_case
- JSON 字段:snake_case
4. **分页规范**:
- 请求:`page` + `limit` 或 `cursor` + `limit`
- 响应:`total` + `items[]`
### 3.3 输出格式
```text
📝 接口契约设计
━━━━━━━━━━━━━━━━
【API-01:创建用户】
(完整契约内容)
【API-02:查询用户】
(完整契约内容)
请确认接口契约是否完整、参数定义是否准确。
阶段 4:关键代码设计
设计影响接口行为的关键代码,不写样板代码。
4.1 关键代码范围
| 代码类型 | 是否需要设计 | 说明 |
|---|---|---|
| 参数校验逻辑 | ✅ | 复杂校验规则、跨字段校验 |
| 状态转换逻辑 | ✅ | 状态机、状态流转约束 |
| 核心算法 | ✅ | 业务计算、排序、过滤逻辑 |
| 权限校验 | ✅ | 角色检查、资源权限 |
| 数据库 CRUD | ❌ | 标准增删改查 |
| 框架配置 | ❌ | 路由注册、中间件配置 |
| 日志记录 | ❌ | 标准日志 |
4.2 关键代码模板
## API-01 关键代码设计
### 参数校验
```python
def validate_create_user(request: CreateUserRequest) -> None:
# 名称长度校验
if not (2 <= len(request.name) <= 50):
raise InvalidInputError("name", "长度必须在 2-50 之间")
# 邮箱格式校验
if not EMAIL_REGEX.match(request.email):
raise InvalidInputError("email", "邮箱格式无效")
# 角色枚举校验
if request.role and request.role not in ("admin", "user"):
raise InvalidInputError("role", "角色必须是 admin 或 user")
业务逻辑
async def create_user(request: CreateUserRequest) -> User:
# 检查邮箱唯一性
existing = await user_repo.find_by_email(request.email)
if existing:
raise ConflictError("EMAIL_EXISTS", "邮箱已存在")
# 创建用户
user = User(
id=generate_id("usr"),
name=request.name,
email=request.email,
role=request.role or "user",
created_at=utc_now()
)
await user_repo.save(user)
return user
权限校验
def check_create_permission(current_user: User) -> None:
if current_user.role not in ("admin",):
raise ForbiddenError("只有管理员可以创建用户")
### 4.3 输出格式
```text
💻 关键代码设计
━━━━━━━━━━━━━━━━
【API-01:创建用户】
- 参数校验:<代码>
- 业务逻辑:<代码>
- 权限校验:<代码>
【API-02:查询用户】
- 参数校验:<代码>
- 业务逻辑:<代码>
请确认关键代码逻辑是否准确。
阶段 5:错误码与异常定义
5.1 错误码体系
定义统一的错误码格式和分类:
## 错误码规范
### 格式
{MODULE}_{ERROR_TYPE}
示例:USER_NOT_FOUND, ORDER_ALREADY_PAID
### 分类
| HTTP Status | 错误类型 | 说明 | 示例 |
|-------------|----------|------|------|
| 400 | INVALID_INPUT | 输入参数无效 | 参数缺失、格式错误、范围越界 |
| 401 | UNAUTHORIZED | 未认证 | Token 缺失、Token 过期 |
| 403 | FORBIDDEN | 无权限 | 角色不足、资源无权限 |
| 404 | NOT_FOUND | 资源不存在 | ID 不存在 |
| 409 | CONFLICT | 冲突 | 唯一约束冲突、状态冲突 |
| 422 | UNPROCESSABLE | 语义错误 | 业务规则不满足 |
| 429 | RATE_LIMITED | 限流 | 请求过于频繁 |
| 500 | INTERNAL_ERROR | 服务器内部错误 | 未捕获异常 |
5.2 错误响应格式
interface ErrorResponse {
code: number; // HTTP Status
error: string; // 错误码,如 "USER_NOT_FOUND"
message: string; // 用户可读的错误描述
details?: { // 可选,字段级错误详情
field: string;
message: string;
}[];
}
5.3 输出格式
⚠️ 错误码定义
━━━━━━━━━━━━━━━━
【统一错误响应格式】
(格式定义)
【错误码清单】
| 错误码 | HTTP Status | 说明 | 触发条件 |
|--------|-------------|------|----------|
| USER_NOT_FOUND | 404 | 用户不存在 | ID 查询不到 |
| EMAIL_EXISTS | 409 | 邮箱已存在 | 创建时邮箱重复 |
【字段级错误】
| 字段 | 错误码 | 说明 |
|------|--------|------|
| name | INVALID_LENGTH | 长度不在 2-50 范围 |
| email | INVALID_FORMAT | 邮箱格式无效 |
请确认错误码体系是否完整。
阶段 6:落盘输出
6.1 文档结构
按模块拆分,每个接口模块一个独立 md 文档,外加一份索引文件汇总接口清单和错误码体系。
api/
├── INDEX.md # API 总览:接口清单 + 错误码 + 通用约定
├── users.md # 用户模块:API-01~03 契约 + 关键代码
├── orders.md # 订单模块:API-04~05 契约 + 关键代码
INDEX.md(索引枢纽):
# API 总览:{功能名称}
> 版本:v1
> 状态:草案
> 基础路径:/api/v1
## 1. 概述
- 接口数量:X 个
- 认证方式:{Bearer Token / API Key / 无}
- 通用约定(分页、排序、过滤)
## 2. 接口清单
| 编号 | 方法 | 路径 | 模块 | 文档 | 优先级 |
|------|------|------|------|------|--------|
| API-01 | POST | /api/v1/users | 用户 | [users.md](users.md) | P0 |
| API-02 | GET | /api/v1/users/{id} | 用户 | [users.md](users.md) | P0 |
| API-03 | PUT | /api/v1/users/{id} | 用户 | [users.md](users.md) | P1 |
| API-04 | POST | /api/v1/orders | 订单 | [orders.md](orders.md) | P0 |
## 3. 错误码定义
(阶段 5 统一错误码体系)
## 4. 待确认事项
| 编号 | 事项 | 影响范围 | 状态 |
|------|------|----------|------|
{module}.md(模块 API 文档):
# {模块名称} API
> 所属需求:{REQ-NNN}
> 基础路径:/api/v1
## API-XX:{接口名称}
### 基本信息
| 项目 | 值 |
|------|-----|
| 方法 | GET/POST/PUT/DELETE/PATCH |
| 路径 | /api/v1/{resource} |
| 认证 | Bearer Token / API Key / 无 |
| 权限 | {required_role} |
| 限流 | {rate_limit} |
| 幂等 | 是/否 |
### 请求参数
#### Path Parameters
| 参数 | 类型 | 必填 | 说明 | 示例 |
|------|------|------|------|------|
#### Query Parameters
| 参数 | 类型 | 必填 | 默认值 | 说明 | 示例 |
|------|------|------|--------|------|------|
#### Request Body
```typescript
interface XxxRequest { ... }
响应
成功响应(200/201)
interface XxxResponse { ... }
错误响应
| HTTP Status | 错误码 | 说明 | 触发条件 |
|---|
Demo 请求示例
curl ...
Demo 响应示例
{ ... }
关键代码设计
(阶段 4 内容:参数校验、业务逻辑、权限校验)
### 6.2 存储位置
检查项目中是否已配置存储位置(`.requirements/config`):
- **已配置**:读取 `storage_path`,API 设计文档存放在 `{storage_path}/{feature}/api/` 目录下
- `INDEX.md`:接口清单 + 错误码 + 通用约定
- `{module}.md`:每个模块一个独立文件(如 `users.md`、`orders.md`)
- **未配置**:询问用户,给出默认建议 `.requirements/{feature}/api/`
### 6.3 质量自检
```text
✅ API 设计文档已生成
📄 <路径>
🔍 质量自检清单
━━━━━━━━━━━━━━━━
【契约完整性】
☐ 每个接口都有完整的方法、路径、认证、权限定义
☐ 每个接口都有完整的请求参数定义(Path/Query/Body)
☐ 每个接口都有完整的响应定义(成功+错误)
☐ 每个接口都有 Demo 请求和响应示例
【关键代码】
☐ 复杂参数校验逻辑已设计
☐ 状态转换逻辑已设计
☐ 核心业务算法已设计
☐ 权限校验逻辑已设计
【错误处理】
☐ 统一错误响应格式已定义
☐ 每个接口的主要错误码已列出
☐ 字段级错误详情已定义
【一致性】
☐ 接口命名符合 RESTful 规范
☐ 错误码格式统一
☐ 分页/排序/过滤规范一致
下一步建议:
- 是否需要将 API 设计文档传递给开发团队?
- 是否需要生成 API 测试计划?
6.4 后续行动
🚀 后续行动选择
━━━━━━━━━━━━━━━━
API 设计已完成,文档已输出。请选择后续行动:
1. 📁 落盘归档
将 API 设计文档保存到需求目录,注册到需求管理系统
2. 📖 生成前端集成指南
使用 frontend-api-guide 技能为前端生成可直接编码的调用流程文档
3. 📋 生成测试计划
使用 test-planner 技能基于 API 设计生成接口测试计划
4. ⏭️ 跳过
不进行后续操作,结束 API 设计流程
请选择 [1/2/3/4]:
与 design-craft 的衔接
作为后续步骤推荐
design-craft 完成设计文档后,在"后续行动选择"中推荐:
2. 📡 补充 API 设计
使用 api-design 技能将设计文档中的 demo 接口升级为详细的 API 设计文档
输入输出关系
| design-craft 产出 | api-design 使用方式 |
|---|---|
| 接口设计章节(含 demo) | 作为接口契约设计的基础,补充完整契约 |
| 数据模型章节 | 作为 Request/Response 结构的参考 |
| 异常处理章节 | 作为错误码定义的参考 |
| 时序图 | 作为关键代码设计的参考 |
反模式
- ❌ 跳过设计文档直接设计 API → 缺乏业务上下文,设计可能偏离需求
- ❌ 写完整实现代码 → 本 skill 只设计关键代码,实现留给开发
- ❌ 直接照搬 demo 示例 → 设计文档的 demo 仅是最简示意便于理解流程,实际设计需基于数据结构、业务场景、使用约束独立重新判断
- ❌ Demo 示例使用占位符 → 示例必须真实可用
- ❌ 遗漏错误响应定义 → 每个接口必须有完整错误码
- ❌ 不定义幂等性 → POST/PUT 接口必须明确是否幂等
- ❌ 跳过确认直接进入下一阶段 → 接口契约是开发的基础,必须确认