向最终用户显示 FastAPI 验证错误

imb*_*olc 7 python swagger openapi fastapi

我正在寻找一些库或代码示例来将 FastAPI 验证消息格式化为人类可读的格式。例如这个端点:

@app.get("/")
async def hello(name: str):
    return {"hello": name}

Run Code Online (Sandbox Code Playgroud)

如果我们错过name查询参数,将产生下一个 json 输出:

{ 
    "detail":[ 
        { 
            "loc":[ 
                "query",
                "name"
            ],
            "msg":"field required",
            "type":"value_error.missing"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,如何:

  1. 将其转换为“需要名称字段”(针对各种可能的错误)以显示在吐司中。
  2. 使用它来显示表单验证消息
  3. 如果可能的话,从 api 描述中自己生成表单

Dar*_*sky 10

I reached here with a similar question - and I ended up handling the RequestValidationError to give back a response where every field is an array of the issues with that field. The response to your request would become (with a status_code=400)

    {
        "detail": "Invalid request",
        "errors": {"name": ["field required"]}
    }
Run Code Online (Sandbox Code Playgroud)

that's quite handy to manage on the frontend for snackbar notifications and flexible enough.

Here's the handler


from collections import defaultdict

from fastapi import status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse


@app.exception_handler(RequestValidationError)
async def custom_form_validation_error(request, exc):
    reformatted_message = defaultdict(list)
    for pydantic_error in exc.errors():
        loc, msg = pydantic_error["loc"], pydantic_error["msg"]
        filtered_loc = loc[1:] if loc[0] in ("body", "query", "path") else loc
        field_string = ".".join(filtered_loc)  # nested fields with dot-notation
        reformatted_message[field_string].append(msg)

    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content=jsonable_encoder(
            {"detail": "Invalid request", "errors": reformatted_message}
        ),
    )

Run Code Online (Sandbox Code Playgroud)


Yag*_*nci 5

FastAPI 具有出色的异常处理,因此您可以通过多种方式自定义异常。

您可以引发 HTTPException,HTTPException 是一个普通的 Python 异常,带有与 API 相关的附加数据。但是你不能返回它你需要提高它,因为它是一个 Python 异常

from fastapi import HTTPException
...
@app.get("/")
async def hello(name: str):
    if not name:
        raise HTTPException(status_code=404, detail="Name field is required")
    return {"Hello": name}
Run Code Online (Sandbox Code Playgroud)

通过添加name: str为查询参数,它会自动成为必需的,因此您需要添加Optional

from typing import Optional
...
@app.get("/")
async def hello(name: Optional[str] = None):
    error = {"Error": "Name field is required"}
    if name:
        return {"Hello": name}
    return error

$ curl 127.0.0.1:8000/?name=imbolc
{"Hello":"imbolc"}
...
$ curl 127.0.0.1:8000
{"Error":"Name field is required"}
Run Code Online (Sandbox Code Playgroud)

但在您的情况下,我认为这是处理 FastAPI 中错误的最佳方法,覆盖了validation_exception_handler

from fastapi import FastAPI, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
...
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=jsonable_encoder({"detail": exc.errors(), "Error": "Name field is missing"}),
    )
...
@app.get("/")
async def hello(name: str):
    return {"hello": name}
Run Code Online (Sandbox Code Playgroud)

你会得到这样的回应:

$ curl 127.0.0.1:8000

 {
   "detail":[
      {
         "loc":[
            "query",
            "name"
         ],
         "msg":"field required",
         "type":"value_error.missing"
      }
   ],
   "Error":"Name field is missing"
}
Run Code Online (Sandbox Code Playgroud)

content如果您愿意,您可以自定义您的然而:

{
"Error":"Name field is missing",
   "Customize":{
      "This":"content",
      "Also you can":"make it simpler"
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 重写“validation_exception_handler”并在其中硬编码错误消息并不是一个好主意;基本上你只能将它应用于 hello world 示例.. (3认同)