You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 03:05:07