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

问题描述 投票:0回答:4

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

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

如果我们错过了

name
查询参数,将会产生下一个 json 输出:

{ 
    "detail":[ 
        { 
            "loc":[ 
                "query",
                "name"
            ],
            "msg":"field required",
            "type":"value_error.missing"
        }
    ]
}

所以我的问题是,如何:

  1. 将其转换为“需要名称字段”(针对各种可能的错误)之类的内容以显示在 toast 中。
  2. 用它来显示表单验证消息
  3. 如果可能的话,根据 api 描述自行生成表单
python swagger openapi fastapi
4个回答
18
投票

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}

通过添加

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"}

但就你而言,我认为这是处理 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}

您将得到如下回复:

$ curl 127.0.0.1:8000

 {
   "detail":[
      {
         "loc":[
            "query",
            "name"
         ],
         "msg":"field required",
         "type":"value_error.missing"
      }
   ],
   "Error":"Name field is missing"
}

您可以自定义您的

content
,但是如果您愿意:

{
"Error":"Name field is missing",
   "Customize":{
      "This":"content",
      "Also you can":"make it simpler"
   }
}

13
投票

我带着类似的问题来到这里 - 我最终处理了

RequestValidationError
以给出回复,其中每个字段都是该字段问题的数组。 对您请求的响应将变为(status_code=400)

    {
        "detail": "Invalid request",
        "errors": {"name": ["field required"]}
    }

在前端管理小吃栏通知非常方便,而且足够灵活。

这是处理程序


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}
        ),
    )


3
投票

我认为我能想到的最好的实际上是

PlainTextResponse

添加这些:

from fastapi.exceptions import RequestValidationError

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return PlainTextResponse(str(exc), status_code=400)

您会收到更人性化的错误消息,如下纯文本所示:

1 validation error
path -> item_id
  value is not a valid integer (type=type_error.integer)

FastAPI 文档中有详细记录这里


0
投票

基于此处的其他答案,您可以捕获 RequestValidationError,并为任何错误构建一个良好的格式化字符串。与其他的不同,它会打印任何错误的好消息(缺少字段、正则表达式问题、长度等)

这会返回类似

Name: String should have at most 120 characters
的消息,同时仍返回另一个字段中的结构化错误。

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
    request: Request, exc: RequestValidationError
):
    # Write user friendly error messages
    error_messages = []
    for error in exc.errors():
        field = error["loc"][-1]  # Get the field name
        message = error["msg"]
        error_messages.append(f"{field.capitalize()}: {message}")

    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content={
            "message": ".\n".join(error_messages),
            "source_errors": exc.errors(),
        },
    )

© www.soinside.com 2019 - 2024. All rights reserved.