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.
 

7.8 KiB

ADR 001: API 响应格式标准化

状态: 提议中 (Proposed)
日期: 2026-02-11
决策者: 后端团队
影响范围: 所有 API 接口

背景

项目中目前存在两套并行的 API 响应格式系统,导致代码不一致和维护困难:

当前状态

系统 A:app.schemas.response (旧系统)

from app.schemas.response import ApiResponse, success_response

@router.get("", response_model=ApiResponse[DataType])
async def get_data():
    data = await service.get_data()
    return success_response(
        data=data.model_dump(by_alias=True, mode='json'),
        message="成功"
    )

使用模块

  • projects.py
  • folders.py
  • recharge.py
  • wechat.py
  • attachments.py
  • ai.py
  • auth.py
  • health.py
  • public/shared_folders.py

特点

  • 使用 ApiResponse[T] 泛型类
  • 通过 success_response() 函数返回字典
  • 需要手动调用 model_dump(by_alias=True, mode='json')
  • 代码冗余度高

系统 B:app.schemas.common (新系统)

from app.schemas.common import SuccessResponse

@router.get("", response_model=SuccessResponse[DataType])
async def get_data():
    data = await service.get_data()
    return SuccessResponse(
        data=data,
        message="成功"
    )

使用模块

  • credits.py
  • storyboards.py
  • project_resources.py
  • project_elements.py
  • project_element_tags.py

特点

  • 使用 SuccessResponse[T] 泛型类
  • 直接返回 Pydantic 对象
  • 依赖 Pydantic 自动序列化
  • 代码简洁,类型安全

混用情况

  • storyboard_resources.py 同时导入了两个系统

问题分析

  1. 代码不一致:同一项目中存在两种不同的响应格式实现
  2. 维护成本高:开发者需要记住两套不同的使用方式
  3. 代码冗余:系统 A 需要在每个接口手动序列化
  4. 类型安全性差:系统 A 返回字典,失去类型检查优势
  5. 新人困惑:不清楚应该使用哪个系统

决策

统一使用 app.schemas.common.SuccessResponse 作为标准响应格式。

理由

  1. 符合 FastAPI 最佳实践

    • 充分利用 Pydantic 的自动序列化能力
    • 保持类型安全,IDE 支持更好
  2. 代码更简洁

    • 无需手动调用 model_dump()
    • 减少重复代码
    • 统一的返回模式
  3. 更易维护

    • 单一职责:Pydantic 负责序列化
    • 修改序列化逻辑只需改 Schema 配置
    • 降低出错概率
  4. 向前兼容

    • 最终 JSON 响应格式完全一致
    • 前端无需任何修改

实施方案

阶段 1:标准化 common.py(立即执行)

  1. 确认 SuccessResponse 为标准

    # app/schemas/common.py
    class SuccessResponse(BaseModel, Generic[T]):
        success: bool = Field(default=True)
        code: int = Field(default=200)
        message: str = Field(default="Success")
        data: Optional[T] = Field(default=None)
        timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
    
  2. response.py 添加废弃警告

    # app/schemas/response.py
    import warnings
    
    warnings.warn(
        "app.schemas.response is deprecated. "
        "Use app.schemas.common.SuccessResponse instead.",
        DeprecationWarning,
        stacklevel=2
    )
    

阶段 2:迁移现有 API(分批执行)

优先级 1(高频接口)

  • projects.py - 项目管理核心接口
  • folders.py - 文件夹管理
  • ai.py - AI 服务接口

优先级 2(中频接口)

  • auth.py - 认证接口
  • recharge.py - 充值接口
  • wechat.py - 微信集成

优先级 3(低频接口)

  • attachments.py - 附件管理
  • health.py - 健康检查
  • public/shared_folders.py - 公开分享

迁移步骤(每个文件):

  1. 修改导入语句

    # 修改前
    from app.schemas.response import ApiResponse, success_response
    
    # 修改后
    from app.schemas.common import SuccessResponse
    
  2. 修改 response_model

    # 修改前
    @router.get("", response_model=ApiResponse[DataType])
    
    # 修改后
    @router.get("", response_model=SuccessResponse[DataType])
    
  3. 修改返回语句

    # 修改前
    return success_response(
        data=response_data.model_dump(by_alias=True, mode='json'),
        message="成功"
    )
    
    # 修改后
    return SuccessResponse(
        data=response_data,
        message="成功"
    )
    
  4. 运行测试验证

  5. 创建 Changelog

阶段 3:清理废弃代码(最后执行)

  1. 确认所有模块已迁移

    # 检查是否还有使用 response.py 的代码
    grep -r "from app.schemas.response import" server/app/api/
    
  2. 删除 response.py

    • 或保留但标记为 @deprecated
    • 添加明确的迁移指南
  3. 更新文档

    • API 开发规范
    • 代码审查清单
    • 新人入职文档

迁移检查清单

代码修改

  • 修改导入语句
  • 修改 response_model 类型
  • 修改返回语句(移除 model_dump()
  • 运行 getDiagnostics 检查语法错误

测试验证

  • 单元测试通过
  • 集成测试通过
  • 响应格式验证(JSON 结构一致)
  • 前端兼容性测试

文档更新

  • 创建 Changelog
  • 更新 API 文档
  • 更新开发规范

影响评估

前端影响

  • 无影响:JSON 响应格式完全一致
  • 无需修改:前端代码保持不变

后端影响

  • 代码简化:每个接口减少 1-2 行序列化代码
  • 类型安全:编译时类型检查更严格
  • 维护性提升:统一模式,降低认知负担

性能影响

  • 无影响:Pydantic 序列化性能相同
  • 可能提升:减少手动序列化的开销

风险与缓解

风险 1:迁移过程中引入 Bug

缓解措施

  • 分批迁移,每批完成后充分测试
  • 保持 response.py 可用,出问题可快速回滚
  • 使用自动化测试验证响应格式

风险 2:开发者不知道新标准

缓解措施

  • response.py 添加废弃警告
  • 更新开发文档和代码审查清单
  • 团队内部培训和宣讲

风险 3:第三方依赖使用旧格式

缓解措施

  • 检查所有依赖和插件
  • 必要时保留 response.py 作为兼容层

替代方案

方案 A:保持现状(不推荐)

  • 优点:无需修改代码
  • 缺点:问题持续存在,技术债累积

方案 B:统一到 response.py(不推荐)

  • 优点:保持旧代码不变
  • 缺点:需要手动序列化,代码冗余

方案 C:创建新的统一模块(不推荐)

  • 优点:全新开始,避免历史包袱
  • 缺点:引入第三套系统,问题更严重

后续工作

  1. 制定迁移时间表

    • 第 1 周:迁移优先级 1 接口
    • 第 2 周:迁移优先级 2 接口
    • 第 3 周:迁移优先级 3 接口
    • 第 4 周:清理废弃代码
  2. 更新开发规范

    • API 响应格式标准
    • 代码审查要点
    • 最佳实践文档
  3. 团队培训

    • 新标准介绍
    • 迁移指南讲解
    • Q&A 答疑

参考资料

  • FastAPI 官方文档:Response Model
  • Pydantic 文档:Model Serialization
  • 项目现有实现:
    • server/app/schemas/common.py
    • server/app/schemas/response.py
    • server/app/api/v1/project_elements.py(参考实现)

决策结果

待定 - 需要团队评审和批准

评审记录

日期 评审人 意见 状态
2026-02-11 - 待评审 Pending

更新历史

  • 2026-02-11: 初始版本,提出统一响应格式方案