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.
 

4.7 KiB

统一响应格式使用错误修复

日期:2026-01-29
类型:Bugfix
影响范围:API 路由层

问题描述

app/api/v1/auth.py 中错误使用 ApiResponse.success() 导致运行时错误:

# ❌ 错误用法
return ApiResponse.success(data=result)
# AttributeError: success

根本原因

  1. 误解 Pydantic 模型用法ApiResponse 是 Pydantic BaseModel,不是工具类
  2. 未查阅响应格式规范:直接猜测 API 而非查看 response.py 实现
  3. 文档不完整api-design.md 缺少后端实现细节

修复方案

1. 修复 API 路由代码

# app/api/v1/auth.py

# ✅ 修复前:错误导入
from app.schemas.response import ApiResponse

# ✅ 修复后:正确导入
from app.schemas.response import ApiResponse, success_response

# ✅ 修复前:错误使用
return ApiResponse.success(data=result)

# ✅ 修复后:使用便捷函数
return success_response(data=result)

2. 补充技术栈文档

更新 .claude/skills/jointo-tech-stack/references/api-design.md

新增内容

  • 完整的响应格式字段说明(包括 successtimestamp
  • 后端实现规范章节
  • 三种正确使用方式(便捷函数、字典、Pydantic 实例)
  • 错误用法警告
  • 导入规范
  • 类型注解示例

正确用法总结

方式 1:使用便捷函数(推荐)

from app.schemas.response import success_response

@router.post("/login/phone")
async def login_with_phone(request: PhoneLoginRequest):
    result = await service.login_with_phone(...)
    return success_response(data=result, message="登录成功")

方式 2:直接返回字典

from datetime import datetime, timezone

@router.post("/login/phone")
async def login_with_phone(request: PhoneLoginRequest):
    result = await service.login_with_phone(...)
    return {
        "success": True,
        "code": 200,
        "message": "Success",
        "data": result,
        "timestamp": datetime.now(timezone.utc).isoformat()
    }

方式 3:实例化 Pydantic 模型

from app.schemas.response import ApiResponse

@router.post("/login/phone")
async def login_with_phone(request: PhoneLoginRequest):
    result = await service.login_with_phone(...)
    return ApiResponse(
        success=True,
        code=200,
        message="Success",
        data=result
    )

错误用法警告

# ❌ 错误:ApiResponse 不是工具类
return ApiResponse.success(data=result)
# AttributeError: success

# ❌ 错误:ApiResponse 没有 create() 方法
return ApiResponse.create(data=result)
# AttributeError: create

# ❌ 错误:ApiResponse 没有 ok() 方法
return ApiResponse.ok(data=result)
# AttributeError: ok

测试验证

单元测试

docker exec jointo-server-app pytest tests/unit/test_user_service.py -v
# ✅ 15/15 passed

集成测试

docker exec jointo-server-app pytest tests/integration/test_user_api.py -v
# ✅ 11/11 passed

影响范围

修改文件

  • server/app/api/v1/auth.py:修复 3 处错误用法
  • .claude/skills/jointo-tech-stack/references/api-design.md:补充实现规范

涉及端点

  • POST /api/v1/auth/login/phone:手机号登录
  • POST /api/v1/auth/refresh:刷新 Token
  • POST /api/v1/auth/logout:用户登出

预防措施

1. 代码审查清单

  • 检查是否正确导入 success_response 函数
  • 避免使用 ApiResponse.xxx() 类方法形式
  • 确保响应包含 successtimestamp 字段

2. 开发规范

推荐做法

  1. 优先使用 success_response()error_response() 便捷函数
  2. 需要类型注解时使用 ApiResponse[T]
  3. 查阅 app/schemas/response.py 确认正确用法

避免做法

  1. 不要猜测 API,先查看源码
  2. 不要使用 ApiResponse.xxx() 形式
  3. 不要省略 successtimestamp 字段

3. 文档完善

  • 已补充 api-design.md 后端实现规范
  • 已添加错误用法警告
  • 已提供完整示例代码

相关文档

总结

本次修复解决了 ApiResponse 误用问题,并完善了技术栈文档。通过补充详细的实现规范和错误用法警告,可以有效避免类似问题再次发生。

关键要点

  1. ApiResponse 是 Pydantic 模型,不是工具类
  2. 使用 success_response() 函数而非 ApiResponse.success()
  3. 遇到不确定的 API 时,先查看源码实现
  4. 保持文档与代码实现同步