gpt4 book ai didi

python - 如何在模型中引发 HTTP 400?

转载 作者:行者123 更新时间:2023-12-05 08:46:54 25 4
gpt4 key购买 nike

我的路线:

@router.get('/check/{value}', status_code=200)
def ranks_check(value: BasicInput = Depends()):
"""
Test endpoint
"""

return value

我的模型:

class BasicInput:
"""
Get Confidence to score Input class
"""

value: int

@validator('value')
def check_if_value_in_range(cls, v):
if not 0 < v < 1000001:
raise ValueError('Value Exceeded Limit')

我需要做的:

我需要验证输入并在出现 ValueError 时引发 HTTP 400。

我知道我可以使用 Pydantic 的 Field 类型完成整数验证,并在路由函数本身中运行 check_if_value_in_range。我正在寻找使用该模型的解决方案。

最佳答案

请参阅 Raise an HTTPException in your code 上的 FastAPI 文档:

HTTPException is a normal Python exception with additional data relevant for APIs.

Because it's a Python exception, you don't return it, you raise it.

This also means that if you are inside a utility function that you are calling inside of your path operation function, and you raise the HTTPException from inside of that utility function, it won't run the rest of the code in the path operation function, it will terminate that request right away and send the HTTP error from the HTTPException to the client.

from fastapi.exceptions import HTTPException

class BasicInput(BaseModel):
value: int

@validator("value")
def check_if_value_in_range(cls, v):
if not 0 < v < 1000001:
# raise ValueError("Value Exceeded Limit")
raise HTTPException(status_code=400, detail="value exceeded limit")

return v
$ curl -i -XGET localhost:8000/check/1000002
HTTP/1.1 400 Bad Request
...

{"detail":"value exceeded limit"}

$ curl -i -XGET localhost:8000/check/42
HTTP/1.1 200 OK
...

{"value":42}

但要使其正常工作,您当前的代码中有一些问题需要修复:

  1. 如果您使用 Pydantic 的 validator装饰器,那么你的类需要是 Pydantic BaseModela Pydantic dataclass .

    class BasicInput(BaseModel):  # <--------------------
    value: int

    如果您还在 validator 函数上添加 print 语句或断点,您会看到它实际上从未被调用,因为它不是 Pydantic BaseModel

  2. if 条件为 False 时验证器函数缺少处理(当 v 在范围内有效时).来自 Pydantic 文档:

    validators should either return the parsed value or raise a ValueError, TypeError, or AssertionError (assert statements may be used).

    class BasicInput(BaseModel):
    value: int

    @validator("value")
    def check_if_value_in_range(cls, v):
    if not 0 < v < 1000001:
    raise ValueError("Value Exceeded Limit")

    # v is good
    return v # <--------------------

在您的原始代码中,您 mentioned that you were getting "nothing" .我假设您得到的是针对有效和无效 value 的空 {} 响应:

$ curl -XGET localhost:8000/check/42
{}

$ curl -XGET localhost:8000/check/1000002
{}

这是因为在路由函数中,valueBasicInput类,不是{value}路径值或者BasicInput.value 整数值

@router.get("/check/{value}", status_code=200)
def ranks_check(value: BasicInput = Depends()):
print(type(value)) # <class 'main.BasicInput'>
return value

实际上得到的“空”响应是 FastAPI 应用其 jsonable_encoder 的结果到 BasicInput 类。当 FastAPI 到达您的路由函数的 返回值 时,它将使用 jsonable_encoder 将其转换为 JSONResponse。请参阅 Return a Response Directly 上的文档.

在内部,由于 BasicInput 不是 Pydantic BaseModel 或可迭代对象(例如 dict 类对象),它会产生一个空字典 {}。 (您可以检查 code for jsonable_encoder ,但这是因为 dict(obj)vars(obj))。

因此,如 MatsLindh's answer 中所述,FastAPI 请求/响应上下文中使用的模型通常是 Pydantic BaseModel 的子类,在正确地对其进行子类化之后,您现在应该得到非空响应:

$ curl -XGET localhost:8000/check/42
{"value":42}

$ curl -XGET localhost:8000/check/1000002
Internal Server Error

...
pydantic.error_wrappers.ValidationError: 1 validation error for BasicInput
value
Value Exceeded Limit (type=value_error)

修复后,只需按照 FastAPI 的 Raise an HTTPException in your code 中的指南进行操作即可(正如我在此答案开头提到的)直接从模型中引发 HTTP 错误。

但我同意 MatsLindh's comment ,这不是一个“好的”做法,因为它违反了SRP/Single Responsibility Principle .您的模型正在做两件事:验证您的输入引发适当的 HTTP 错误响应。

FastAPI 应该处理您的请求和响应,而 Pydantic 应该代表您的模型和数据。您让 FastAPI 接受请求,将其传递给 Pydantic 以验证和存储模型数据,然后让 FastAPI 将结果转换为适当的响应。您的预期解决方案也令人困惑,因为对于有效/成功案例,它是在路由函数中处理的,但对于无效/错误案例,它是在模型验证函数中处理的。

FastAPI 已经知道如何捕获 Pydantic ValidationError 并将它们转换为适当的 HTTP 错误响应。在这种情况下,FastAPI 返回 HTTP 500 内部服务器错误。

如果目的是提供特定于模型的错误响应,您应该在模型上保留 raise ValueError,然后覆盖 FastAPI 的默认验证错误处理程序。请参阅有关 Override the default exception handlers 的部分.

这是我推荐的代码:

from fastapi import APIRouter, Depends, FastAPI
from fastapi.exceptions import ValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel, validator

# MODELS

class BasicInput(BaseModel):
value: int

@validator("value")
def check_if_value_in_range(cls, v):
if not 0 < v < 1000001:
raise ValueError("Value Exceeded Limit")

return v

# VIEWS

api = FastAPI()
router = APIRouter()

@api.exception_handler(ValidationError)
async def validation_exception_handler(request, exc: ValidationError):
return JSONResponse(status_code=400, content={"error": str(exc)})

@router.get("/check/{value}")
def ranks_check(value: BasicInput = Depends()):
return value

api.include_router(router)
$ curl -i -XGET localhost:8000/check/42
HTTP/1.1 200 OK
...

{"value":42}

$ curl -i -XGET localhost:8000/check/1000002
HTTP/1.1 400 Bad Request
...

{"error":"1 validation error for BasicInput\nvalue\n Value Exceeded Limit (type=value_error)"}

关于python - 如何在模型中引发 HTTP 400?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68770979/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com