Files
XingHuo/app/utils/response.py
T

34 lines
1.5 KiB
Python
Raw Normal View History

"""统一 API 响应外壳(B7 · 挂账④)。
成功响应:业务字段平铺不变(B5 评审 P2-2 口径「路由返回体不变」),trace_id
经 X-Trace-Id 响应头贯通(main 中间件);错误响应统一 JWT 手册 §10 结构
{error_code, message, trace_id, request_id}(request_id 沿用 trace_id,
独立请求级标识尚未引入)。main 与测试 app 共用 register_error_handlers。
"""
from __future__ import annotations
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from app.utils.exceptions import ApiError, PermissionDenied
from app.utils.trace import current_trace, new_trace
def error_body(error_code: str, message: str) -> dict[str, str]:
"""手册 §10 错误体(trace 缺失时兜底生成,保证响应可归因)。"""
tid = current_trace() or new_trace()
return {"error_code": error_code, "message": message, "trace_id": tid, "request_id": tid}
def register_error_handlers(app: FastAPI) -> None:
"""注册统一错误体 handler(替代 FastAPI 默认 detail 结构)。"""
@app.exception_handler(ApiError)
async def _api_error_handler(request: Request, exc: ApiError) -> JSONResponse:
return JSONResponse(status_code=exc.status_code, content=error_body(exc.error_code, exc.message))
@app.exception_handler(PermissionDenied)
async def _permission_denied_handler(request: Request, exc: PermissionDenied) -> JSONResponse:
return JSONResponse(status_code=403, content=error_body(exc.code, str(exc)))