# API 响应格式与异常处理标准化迁移 **日期**: 2026-02-11 **类型**: 重构 **影响范围**: 8 个 API 文件 **破坏性变更**: 无(仅内部实现改动) ## 变更概述 将 8 个 API 路由文件迁移到统一的响应格式和异常处理规范,与 `ai_conversations.py` 保持一致。 ## 变更详情 ### 1. 统一响应格式 **变更前**: ```python # 使用旧的 ApiResponse 或 success_response from app.schemas.response import ApiResponse, success_response return ApiResponse(code=200, message="Success", data=...) return success_response(data=...) ``` **变更后**: ```python # 使用标准的 SuccessResponse from app.schemas.common import SuccessResponse return SuccessResponse(data=...) ``` ### 2. 统一异常处理 **变更前**: ```python # 手动捕获异常并转换为 HTTPException try: result = await service.some_method() return ApiResponse(...) except ValidationError as e: raise HTTPException(status_code=400, detail=str(e)) except NotFoundError as e: raise HTTPException(status_code=404, detail=str(e)) ``` **变更后**: ```python # 直接调用 Service,让异常向上传播 result = await service.some_method() return SuccessResponse(data=result) ``` **原理**:Service 层直接抛出 `app.core.exceptions` 中的自定义异常(如 `NotFoundError`, `ValidationError`),这些异常继承自 `HTTPException`,FastAPI 的异常处理中间件会自动转换为正确的 HTTP 响应。 ### 3. 查询参数 camelCase 支持 **变更前**: ```python # 缺少 camelCase alias scene_id: str = Query(..., description="场景ID") storage_path: str = Query(..., description="对象存储路径") ``` **变更后**: ```python # 添加 camelCase alias scene_id: str = Query(..., alias="sceneId", description="场景ID") storage_path: str = Query(..., alias="storagePath", description="对象存储路径") ``` ## 涉及文件 ### ✅ 已迁移文件 | 文件 | 变更内容 | |-----|---------| | `wechat.py` | ✅ 替换 `ApiResponse` → `SuccessResponse`
✅ 删除异常捕获
✅ 添加查询参数 camelCase alias | | `users.py` | ✅ 替换 `success_response` → `SuccessResponse`
✅ 删除 `.model_dump()` 调用
✅ 直接返回 Pydantic Schema | | `health.py` | ✅ 替换 `success_response` → `SuccessResponse`
✅ 删除数据库异常处理(交给 Service 层) | | `folders.py` | ✅ 替换 `ApiResponse`/`success_response` → `SuccessResponse`
✅ 查询参数已有 camelCase 支持 | | `file_storage.py` | ✅ 替换响应格式
✅ 删除异常捕获
✅ 添加查询参数 `storagePath` alias | | `auth.py` | ✅ 替换 `ApiResponse.create_success` → `SuccessResponse`
✅ 删除异常捕获 | | `attachments.py` | ✅ 替换 `ApiResponse.create_success` → `SuccessResponse`
✅ 删除 `.to_dict()` 调用
✅ 直接返回 Pydantic Schema | | `ai.py` | ✅ 删除所有 14 个路由的手动异常捕获
✅ 清理冗余的 try-except 块
✅ 日志记录保留 | | `credits.py` | ✅ 已符合标准(无需修改) | ## 技术细节 ### Response Schema 自动序列化 FastAPI 会自动将 `response_model` 中指定的 Pydantic Schema 序列化为 JSON,包括: - 字段名转换(通过 `alias` 配置) - 日期时间格式化 - UUID 转字符串 因此不再需要手动调用 `.model_dump(by_alias=True, mode='json')`。 ### 异常传播机制 ```python # Service 层 from app.core.exceptions import NotFoundError async def get_item(item_id: UUID): item = await repository.find_by_id(item_id) if not item: raise NotFoundError("项目不存在") # 继承自 HTTPException(status_code=404) return item # API 层 @router.get("/{item_id}", response_model=SuccessResponse[ItemResponse]) async def get_item_endpoint(item_id: UUID, service = Depends(get_service)): item = await service.get_item(item_id) # 异常自动传播 return SuccessResponse(data=ItemResponse.model_validate(item)) ``` ## 验证方法 ### 1. 响应格式验证 ```bash # 所有 API 响应应符合统一格式 curl http://localhost:8000/api/v1/users/me | jq # 预期输出 { "code": 200, "message": "success", "data": { ... }, "timestamp": "2026-02-11T10:00:00Z" } ``` ### 2. 异常处理验证 ```bash # 测试 404 错误 curl http://localhost:8000/api/v1/folders/invalid-uuid | jq # 预期输出 { "detail": "文件夹不存在" } ``` ### 3. camelCase 查询参数验证 ```bash # 测试 camelCase 查询参数 curl "http://localhost:8000/api/v1/wechat/result?sceneId=test123" | jq curl "http://localhost:8000/api/v1/file_storage/presigned-url?storagePath=/path/to/file" | jq ``` ## 兼容性说明 - ✅ **前端兼容**: 响应格式保持一致,前端无需修改 - ✅ **查询参数兼容**: 支持 camelCase 和 snake_case 两种格式(通过 `populate_by_name=True`) - ✅ **异常响应格式**: FastAPI 标准格式,与现有前端错误处理逻辑一致 ## 后续优化 1. ✅ 完成所有 API 文件的标准化迁移 2. ⚠️ 建议:统一删除旧的 `app.schemas.response.ApiResponse` 和 `success_response` 3. ⚠️ 建议:在 Service 层统一使用自定义异常,避免返回错误码字典 ## 参考 - 标准实现:`server/app/api/v1/ai_conversations.py` - 异常定义:`server/app/core/exceptions.py` - 响应 Schema:`server/app/schemas/common.py`