如何在FastAPI中通过Pydantic模型设置自定义错误响应媒体类型?
实现方案
1. 定义基础RFC Problem Pydantic模型
先实现符合RFC 7807规范的基础模型,后续所有特定错误模型都继承它:
from pydantic import BaseModel, HttpUrl from typing import Optional class Problem(BaseModel): type: Optional[HttpUrl] = "about:blank" title: str status: int detail: Optional[str] = None instance: Optional[str] = None class Config: schema_extra = { "example": { "type": "https://your-domain.com/problems/generic-error", "title": "Server Error", "status": 500, "detail": "An unexpected error occurred", "instance": "/api/endpoint" } }
2. 自定义Problem响应类
继承FastAPI的JSONResponse,强制设置媒体类型为application/problem+json,并支持直接传入Pydantic模型序列化:
from fastapi.responses import JSONResponse class ProblemResponse(JSONResponse): def __init__(self, problem: Problem, **kwargs): super().__init__( content=problem.dict(), media_type="application/problem+json", status_code=problem.status, **kwargs )
3. 扩展特定错误模型
基于基础Problem模型创建各状态码对应的错误类型,复用通用字段的同时自定义专属属性:
class UnauthorizedProblem(Problem): type: HttpUrl = "https://your-domain.com/problems/unauthorized" title: str = "Unauthorized" status: int = 401 class ValidationProblem(Problem): type: HttpUrl = "https://your-domain.com/problems/validation-failed" title: str = "Validation Error" status: int = 422
4. 配置路由与OpenAPI文档
在路由的responses参数中明确指定对应状态码的媒体类型和关联模型,确保Swagger UI正确识别:
from fastapi import FastAPI, HTTPException app = FastAPI() @app.get("/protected", responses={ 401: { "description": "Invalid or missing authentication credentials", "content": { "application/problem+json": { "model": UnauthorizedProblem, "example": { "type": "https://your-domain.com/problems/unauthorized", "title": "Unauthorized", "status": 401, "detail": "Invalid API key provided", "instance": "/protected" } } } } }) async def protected_resource(api_key: str): if api_key != "valid-key": # 直接返回自定义Problem响应 return ProblemResponse( UnauthorizedProblem(detail="Invalid API key provided", instance="/protected") ) return {"message": "Access granted"}
5. 全局异常处理器(可选)
为FastAPI默认抛出的异常(如HTTPException、RequestValidationError)添加全局处理,自动转换为Problem格式响应:
from fastapi import Request from fastapi.exceptions import RequestValidationError @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): problem = Problem( title=exc.detail if exc.detail else f"HTTP {exc.status_code}", status=exc.status_code, detail=exc.detail, instance=str(request.url) ) return ProblemResponse(problem) @app.exception_handler(RequestValidationError) async def validation_error_handler(request: Request, exc: RequestValidationError): error_details = "\n".join([f"{err['loc'][-1]}: {err['msg']}" for err in exc.errors()]) problem = ValidationProblem(detail=error_details, instance=str(request.url)) return ProblemResponse(problem)
方案优势
- 基于Pydantic继承体系,轻松扩展各类业务错误模型
- 自定义响应类确保媒体类型全局统一
- 路由
responses配置直接映射到OpenAPI文档,Swagger UI可正确展示响应结构与媒体类型 - 全局异常处理器自动兼容FastAPI默认异常,无需逐个路由修改
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

