[英]catch errors using pydantic @validator decorator for fastapi input query
到目前为止,我有 2 个问题无法使用 docs/goole/stack info 解决:-)
1)当使用 model 作为 fastapi get 查询的查询输入时,我应该如何捕获 pydantic model 验证器装饰器抛出的 ValidationErrors?
语境:
我有一个 pydantic model:
class PointRankReqParams(BaseModel):
rat: Optional[Literal['2G', '3G', '4G', '5G']] = '3G'
h3resolution: Optional[int] = 5
input_srid: Optional[int] = 4326
bufferdistance: Optional[int] = 5000
x: float
y: float
@validator('h3resolution')
def h3resolution_bins(cls, v):
if v not in [4,5,6,7,8]:
raise ValueError('Hexabin size not permitted')
return v
和服务 GET 请求的 FastAPI 函数:
@router.get("/point/overall", summary="GET Ranking for given location point")
async def get_ranking_for_location_point(inputparams: PointRankReqParams = Depends(),token: str = Depends(oauth2_scheme)):
logger.debug("Here I am")
return {}
现在,当我的 curl 参数h3resolution超出定义范围时,例如http://localhost:9000/rank/point/overall?rat=2G&h3resolution=9&input_srid=4326&bufferdistance=5000&x=21&y=21
在控制台中得到错误实际上是有道理的
py- | File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
py- | pydantic.error_wrappers.ValidationError: 1 validation error for PointRankReqParams
py- | h3resolution
py- | Hexabin size not permitted (type=value_error)
但是 FastAPI 向终端客户端返回 HTTP 500 Internal Server Error。 我应该如何捕捉那些来自验证器的异常?
2. 如何正确使用 Optional[Literal[...]] 构造?
我尝试重新定义上面的示例以在 model 中使用:
class PointRankReqParams(BaseModel):
...
h3resolution: Optional[Literal[4,5,6,7,8]] = 5
But when I curl GET query eg http://localhost:9000/rank/point/overall?rat=2G&h3resolution=7&input_srid=4326&bufferdistance=5000&x=21&y=21
I receive 422 Unprocessable entry as h3resolution is being interpreted as string not integer:
{
"detail": [
{
"loc": [
"query",
"h3resolution"
],
"msg": "unexpected value; permitted: 4, 5, 6, 7, 8",
"type": "value_error.const",
"ctx": {
"given": "7",
"permitted": [
4,
5,
6,
7,
8
]
}
}
]
}
非常感谢!
这是一个非常好的问题,已经讨论了好几年,你可以查看这个github 问题。 不幸的是,对于如何处理它没有达成共识, 文档只显示了一个使用普通 Python 类的简单用例。 它与BaseModel
和dataclass
一起使用,直到您想要自定义验证器或其他东西,FastAPI 的作者说:
具有单个 Pydantic model 用于查询参数可以解释为:
http://somedomain.com/?args={"k1":"v1","k2":"v2"}
或者
http://somedomain.com/?k1=v1&k2=v2
或许多其他选择...
我们甚至没有讨论在 Pydantic 模型(和请求主体)中有效的子模型,但对于非主体参数(查询、路径等),行为将是未定义的。
go 没有明显的方法来解释如何解释它适用于所有情况(包括其他人的用例、未来用例等)。
因此,将它放在 FastAPI 中用于自定义用例并没有什么意义,因为它非常主观并且依赖于团队的约定。
jimcarreer建议使用类似的东西:
class PagingQuery(BaseModel):
page: conint(ge=1)
page_size: conint(ge=1, le=250) = 50
@classmethod
async def depends(cls, page: int = 1, page_size: int = 50):
try:
return cls(page=page, page_size=page_size)
except ValidationError as e:
errors = e.errors()
for error in errors:
error['loc'] = ['query'] + list(error['loc'])
raise HTTPException(422, detail=errors)
@app.get("/example", tags=["basic"])
def example(paging: PagingQuery = Depends(PagingQuery.depends)):
return {"page": paging.page, "page_size": paging.page_size}
但这看起来很老套,我宁愿远离它。
回答你的第二个问题,查询字符串只是一个字符串(如'age=20&name=John'
),键、值对只是字符串; 你已经指定了Literal
类型,所以不会有类型转换,你会得到一个异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.