簡體   English   中英

如何在 FastApi 和 Pydantic 中自定義錯誤模式?

[英]How to customize error schema in FastApi and Pydantic?

我使 FastAPI 應用程序面臨結構性問題。 例如,假設存在這個簡單的應用程序

from fastapi import FastAPI, Header
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field

app = FastAPI()


class PydanticSchema(BaseModel):
    test_int: int = Field(..., ge=0)


class CustomException(Exception):
    def __init__(self, status_code, msg):
        self.status_code = status_code
        self.msg = msg


@app.exception_handler(CustomException)
async def handle_custom_exception(request, exc: CustomException):
    return JSONResponse(
        status_code=exc.status_code, content={"error": exc.msg}
    )


@app.post("/")
def index(
    some_form: PydanticSchema,
    some_header: str = Header("", alias="X-Header", max_length=3),
):
    is_special_case = some_form.test_int == 42
    if is_special_case:
        raise CustomException(418, "Very special case")
    return "ok"

這就是問題所在。
我有三個獨立的錯誤產生者:我的手動 raise,Pydantic Model,FastApi。

if __name__ == "__main__":
    client = TestClient(app)
    cases = (
        ({"X-Header": "abc"}, {"test_int": 0}),
        ({"X-Header": "abcdef"}, {"test_int": 0}),
        ({"X-Header": "abc"}, {"test_int": -1}),
        ({"X-Header": "abc"}, {"test_int": 42}),
    )
    for case in cases:
        r = client.post("/", headers=case[0], json=case[1])
        print(f"#####\n{case=}:\n{r.status_code=}\n{r.text=}")

我的目標是獲得一致的錯誤響應所以我必須為我的CustomException添加異常處理程序,我必須將error_msg_templates添加到 PydanticModel.Config 我必須為 FastApi 異常和 Pydantic 異常添加非常愚蠢的處理程序以將它們重新格式化為我的自定義響應。 因為 fastapi 覆蓋了來自 pydantic 模板的自定義消息。 像這樣:

# ---snip---
from fastapi.exceptions import RequestValidationError

# ---snip---
class PydanticSchema(BaseModel):
    test_int: int = Field(..., ge=0)

    class Config:
        error_msg_templates = {"value_error.number.not_ge": "Custom GE error"}

# ---snip---
@app.exception_handler(RequestValidationError)
async def fastapi_error_handler(request, exc: RequestValidationError):
    errors = exc.errors()
    error_wrapper = exc.raw_errors[0]
    validation_error = error_wrapper.exc
    from pydantic import error_wrappers as ew
    if isinstance(validation_error, ew.ValidationError):
        errors = validation_error.errors()
    
    first_error = errors[0]
    msg = first_error.get("msg")
    # [!] Demonstration
    etype = first_error.get("type")
    if etype == "value_error.any_str.max_length":
        msg = "Custom MAX length error"
    return JSONResponse(status_code=400, content={"error": msg})

# ---snip---

這是不可維護的。 但是需要自定義錯誤消息——我不能依賴默認的 pydantic\fastapi 錯誤響應模式。

有沒有人遇到過這個問題並優雅地解決了它?

為什么不是 FastAPI 的 Exception_handler 參數? 您可以在發生此錯誤時查看響應的狀態代碼,然后添加異常處理程序。 異常處理程序可以訪問 Request 和 Exception 對象,它們分別是導致異常的請求和引發的異常。

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError

def val_err(request: Request, exception: Exception):
    if not isinstance(exception, RequestValidationError):
        return
    errors = exc.errors()
    error_wrapper = exc.raw_errors[0]
    validation_error = error_wrapper.exc
    from pydantic import error_wrappers as ew
    if isinstance(validation_error, ew.ValidationError):
        errors = validation_error.errors()
    
    first_error = errors[0]
    msg = first_error.get("msg")
    # [!] Demonstration
    etype = first_error.get("type")
    if etype == "value_error.any_str.max_length":
        msg = "Custom MAX length error"
    return JSONResponse(status_code=400, content={"error": msg})
    

exception_handlers = {422: val_err}
app = FastAPI(exception_handlers=exception_handlers)

您可以參考我的另一個答案,該答案剖析了代碼並對其進行了更詳細的解釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM