You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.8 KiB
5.8 KiB
ADR 011: API 响应格式标准化
状态
已接受 (Accepted) - 2026-02-05
背景
在代码审查过程中,发现 API 响应格式存在不一致的问题:
发现的问题
-
文档不一致
api-design.md第 90-96 行定义了完整的响应格式(5 个字段)- 但第 617-628 行及其他多处示例缺少
success和timestamp字段
-
Schema 定义不完整
schemas/common.py中的SuccessResponse只有 3 个字段(code, message, data)- 缺少
success和timestamp字段 - 导致部分 API(如
credits.py)返回不完整的响应
-
前端已兼容
client/src/services/api/client.ts已经支持完整格式- 响应拦截器正确处理 5 字段格式(第 48 行)
- 并兼容旧的 3 字段格式(第 66 行)
正确的响应格式
成功响应:
{
"success": true,
"code": 200,
"message": "Success",
"data": {...},
"timestamp": "2026-02-05T10:30:00+00:00"
}
错误响应:
{
"success": false,
"code": 400,
"message": "错误消息",
"data": null,
"timestamp": "2026-02-05T10:30:00+00:00"
}
决策
统一所有 API 响应格式为 5 字段格式:
success(boolean) - 请求是否成功code(number) - 业务状态码message(string) - 响应消息data(T | null) - 业务数据timestamp(string) - ISO 8601 格式的响应时间戳
实施
1. 修复文档
已修复:.claude/skills/jointo-tech-stack/references/api-design.md
- ✅ 第 617-628 行:分页响应示例
- ✅ 第 352-366 行:邮箱登录响应
- ✅ 第 380-389 行:发送验证码响应
- ✅ 第 403-418 行:手机号登录响应
- ✅ 第 428-437 行:微信二维码响应
- ✅ 第 446-455 行:微信登录(等待扫码)
- ✅ 第 458-472 行:微信登录(成功)
- ✅ 第 490-497 行:未认证响应
- ✅ 第 499-506 行:权限不足响应
- ✅ 第 660-680 行:项目列表响应
- ✅ 第 700-710 行:创建项目响应
- ✅ 第 733-740 行:删除项目响应
- ✅ 第 788-799 行:积分余额响应
- ✅ 第 809-830 行:积分交易记录响应
- ✅ 第 849-861 行:上传附件响应
- ✅ 第 872-880 行:下载链接响应
- ✅ 第 906-917 行:创建充值订单响应
- ✅ 第 928-940 行:查询订单状态响应
2. 修复 Schema 定义
已修复:server/app/schemas/common.py
class SuccessResponse(BaseModel, Generic[T]):
"""统一成功响应格式(完整版本)"""
success: bool = Field(default=True, description="请求是否成功")
code: int = Field(default=200, description="业务状态码")
message: str = Field(default="Success", description="响应消息")
data: Optional[T] = Field(default=None, description="响应数据")
timestamp: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
description="响应时间戳"
)
@field_serializer('timestamp')
def serialize_timestamp(self, value: datetime) -> str:
return value.isoformat()
3. API 路由现状
已确认正确:
- ✅
api/v1/projects.py- 使用success_response()✅ - ✅
api/v1/folders.py- 使用success_response()✅ - ✅
api/v1/auth.py- 使用success_response()✅ - ✅
api/v1/credits.py- 使用SuccessResponse()(已修复 Schema)✅
4. 前端兼容性
已确认:client/src/services/api/client.ts
前端响应拦截器已正确处理:
- ✅ 优先检查新格式(5 字段,第 48 行)
- ✅ 兼容旧格式(3 字段,第 66 行)
- ✅ 正确处理错误响应(第 96 行)
影响
正面影响
- 统一性:所有 API 响应格式一致,前端处理更简单
- 可追踪性:
timestamp字段便于排查问题 - 明确性:
success字段明确表示请求成功/失败 - 兼容性:前端已兼容新旧格式,无破坏性变更
需要注意
- 新 API 开发:必须使用完整的 5 字段格式
- 旧 API 迁移:逐步迁移使用不完整格式的旧接口
- 测试用例:更新测试用例验证响应格式
实施指南
后端开发
✅ 推荐方式 1:使用便捷函数
from app.schemas.response import success_response
@router.get("/example")
async def example():
return success_response(data={"key": "value"})
✅ 推荐方式 2:使用 Pydantic 模型(推荐用于有明确类型的场景)
from app.schemas.common import SuccessResponse
@router.get("/example", response_model=SuccessResponse[MyResponse])
async def example():
return SuccessResponse(data=my_data)
❌ 禁止方式:手动构建不完整的字典
# ❌ 错误:缺少 success 和 timestamp
return {"code": 200, "message": "Success", "data": data}
前端开发
前端无需修改,响应拦截器已正确处理:
// 自动提取 data 字段
const projects = await projectApi.getAll(); // 直接得到 data 内容
// 错误自动抛出异常
try {
await api.call();
} catch (error) {
console.error(error.message); // 来自 response.message
}
检查清单
创建新 API 时必须确认:
- 使用
success_response()或SuccessResponse返回 response_model使用ApiResponse[T]或SuccessResponse[T]- 响应包含 5 个必需字段:success, code, message, data, timestamp
- 错误响应也遵循相同格式
- 更新 API 文档示例
相关文档
.claude/skills/jointo-tech-stack/references/api-design.md- API 设计规范server/app/schemas/response.py- 响应格式定义server/app/schemas/common.py- 通用响应模型client/src/services/api/client.ts- 前端响应拦截器
历史
- 2026-02-05: 创建 ADR,修复文档和 Schema 定义