繁体   English   中英

使用 pydantic @validator 装饰器捕获错误以进行 fastapi 输入查询

[英]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 类的简单用例。 它与BaseModeldataclass一起使用,直到您想要自定义验证器或其他东西,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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM