Raj*_*eer 17 python python-3.x pydantic fastapi
我正在将 FastAPI 与 Pydantic 结合使用。
我的问题 - 我需要使用 Pydantic 引发 ValueError
from fastapi import FastAPI
from pydantic import BaseModel, validator
from fastapi import Depends, HTTPException
app = FastAPI()
class RankInput(BaseModel):
rank: int
@validator('rank')
def check_if_value_in_range(cls, v):
"""
check if input rank is within range
"""
if not 0 < v < 1000001:
raise ValueError("Rank Value Must be within range (0,1000000)")
#raise HTTPException(status_code=400, detail="Rank Value Error") - this works But I am looking for a solution using ValueError
return v
def get_info_by_rank(rank):
return rank
@app.get('/rank/{rank}')
async def get_rank(value: RankInput = Depends()):
result = get_info_by_rank(value.rank)
return result
Run Code Online (Sandbox Code Playgroud)
这段代码Internal Server Error在引发 ValueError 时给出
INFO: 127.0.0.1:59427 - "GET /info/?rank=-1 HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/uvicorn/protocols/http/h11_impl.py", line 396, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/fastapi/applications.py", line 199, in __call__
await super().__call__(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/applications.py", line 111, in __call__
await self.middleware_stack(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/middleware/errors.py", line 181, in __call__
raise exc from None
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/exceptions.py", line 82, in __call__
raise exc from None
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/routing.py", line 566, in __call__
await route.handle(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/routing.py", line 227, in handle
await self.app(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/routing.py", line 41, in app
response = await func(request)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/fastapi/routing.py", line 195, in app
dependency_overrides_provider=dependency_overrides_provider,
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/fastapi/dependencies/utils.py", line 550, in solve_dependencies
solved = await run_in_threadpool(call, **sub_values)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/concurrency.py", line 34, in run_in_threadpool
return await loop.run_in_executor(None, func, *args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "pydantic/main.py", line 400, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for GetInput
rank
ValueError() takes no keyword arguments (type=type_error)
ERROR:uvicorn.error:Exception in ASGI application
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/uvicorn/protocols/http/h11_impl.py", line 396, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/fastapi/applications.py", line 199, in __call__
await super().__call__(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/applications.py", line 111, in __call__
await self.middleware_stack(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/middleware/errors.py", line 181, in __call__
raise exc from None
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/exceptions.py", line 82, in __call__
raise exc from None
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/routing.py", line 566, in __call__
await route.handle(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/routing.py", line 227, in handle
await self.app(scope, receive, send)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/routing.py", line 41, in app
response = await func(request)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/fastapi/routing.py", line 195, in app
dependency_overrides_provider=dependency_overrides_provider,
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/fastapi/dependencies/utils.py", line 550, in solve_dependencies
solved = await run_in_threadpool(call, **sub_values)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/starlette/concurrency.py", line 34, in run_in_threadpool
return await loop.run_in_executor(None, func, *args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "pydantic/main.py", line 400, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for GetInput
rank
ValueError() takes no keyword arguments (type=type_error)
Run Code Online (Sandbox Code Playgroud)
我还检查了https://github.com/tiangolo/fastapi/issues/2180。
但我无法找到解决方案。
我需要做的是ValueError使用自定义状态代码来提高。
注意 - 我知道我可以通过提高 来完成工作HTTPException。
但我正在寻找使用的解决方案ValueError
你能告诉我哪里出错了吗?
还在 Github 上发布了此问题 - https://github.com/tiangolo/fastapi/issues/3761
Ben*_*Ben 14
如果您没有引发,HTTPException那么通常任何其他未捕获的异常都会生成 500 响应(Internal Server Error)。如果您的目的是在引发特定异常时响应一些其他自定义错误消息和 HTTP 状态 - 例如ValueError- 那么您可以使用向您的应用程序添加全局异常处理程序:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_exception_handler(request: Request, exc: ValueError):
return JSONResponse(
status_code=400,
content={"message": str(exc)},
)
Run Code Online (Sandbox Code Playgroud)
这将给出 400 响应(或者您可以将状态代码更改为您喜欢的任何内容),如下所示:
{
"message": "Value Must be within range (0,1000000)"
}
Run Code Online (Sandbox Code Playgroud)
Pau*_*l P 10
请注意,pydantic期望验证器提出一个ValueError, TypeError, 或AssertionError(参见文档),它将pydantic转换为ValidationError.
此外,根据FastAPI 的文档:
当请求包含无效数据时,FastAPI 会在内部引发
RequestValidationError.
RequestValidationError是 Pydantic 的子类ValidationError。
这样做的结果是,在 的 模型验证Validation期间引发的标准错误pydantic将被转换为422 Unprocessable Entity,并且响应正文将包含有关验证失败原因的详细信息。
(附带说明:pydantic带有约束类型,允许约束基本数据类型,而无需编写显式验证器。)
如果上述方法不令人满意并且您想更改行为,我将采用以下方法(有关处理的详细信息,请参阅此处ValidationError):
from fastapi import Depends, FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.exception_handlers import request_validation_exception_handler
from fastapi.responses import JSONResponse
from pydantic import BaseModel, conint
class RankInput(BaseModel):
# Constrained integer, must be greater than or equal to 0
# and less than or equal to 1 million.
rank: conint(ge=0, le=1_000_000)
async def rank_out_of_bound_handler(request: Request, exc: RequestValidationError):
validation_errors = exc.errors()
for err in validation_errors:
# You could check for other things here as well, e.g. the error type.
if "rank" in err["loc"]:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"message": "Rank must be in range [0, 1000000]."}
)
# Default response in every other case.
return await request_validation_exception_handler(request, exc)
def get_info_by_rank(rank):
return rank
app = FastAPI(
exception_handlers={RequestValidationError: rank_out_of_bound_handler},
)
@app.get('/rank/{rank}')
async def get_rank(value: RankInput = Depends()):
result = get_info_by_rank(value.rank)
return result
Run Code Online (Sandbox Code Playgroud)
现在对端点的调用给出:
$ curl -i "http://127.0.0.1:8000/rank/1"
HTTP/1.1 200 OK
date: Sat, 28 Aug 2021 20:47:58 GMT
server: uvicorn
content-length: 1
content-type: application/json
1
Run Code Online (Sandbox Code Playgroud)
$ curl -i "http://127.0.0.1:8000/rank/-1"
HTTP/1.1 400 Bad Request
date: Sat, 28 Aug 2021 20:48:24 GMT
server: uvicorn
content-length: 49
content-type: application/json
{"message":"Rank must be in range [0, 1000000]."}
Run Code Online (Sandbox Code Playgroud)
$ curl -i "http://127.0.0.1:8000/rank/1000001"
HTTP/1.1 400 Bad Request
date: Sat, 28 Aug 2021 20:48:51 GMT
server: uvicorn
content-length: 49
content-type: application/json
{"message":"Rank must be in range [0, 1000000]."}
Run Code Online (Sandbox Code Playgroud)
如果您要添加使用相同模型的不同端点,异常处理程序也会自动处理此问题,例如:
@app.get('/other-rank/{rank}')
async def get_other_rank(value: RankInput = Depends()):
result = get_info_by_rank(value.rank)
return result
Run Code Online (Sandbox Code Playgroud)
$ curl -i "http://127.0.0.1:8000/other-rank/-1"
HTTP/1.1 400 Bad Request
date: Sat, 28 Aug 2021 20:54:16 GMT
server: uvicorn
content-length: 49
content-type: application/json
{"message":"Rank must be in range [0, 1000000]."}
Run Code Online (Sandbox Code Playgroud)
如果这不是您想要的,您能解释一下为什么您想提出 吗ValueError?
| 归档时间: |
|
| 查看次数: |
29026 次 |
| 最近记录: |