基于这个API定义,我的API支持如下查询:
GET http://my.api.url/posts?sort=["title","ASC"]&range=[0, 24]&filter={"q":"bar"}
,其中需要的一些检查是
sort[1]
为"asc"
或"desc"
(大小写不重要)filter
的键为"q"
。filter
可以有其他密钥range
是一个包含两个整数的列表。range[0]
小于或等于range[1]
在fastapi路径定义中,我目前将filter
,sort
和range
定义为字符串,如下面的代码所示,使用json转换它们。加载,并执行检查。
@r.get(
"/users",
response_model=List[User],
response_model_exclude_none=True,
)
async def list_users(
filter: Optional[str] = None,
sort: Optional[str] = None,
range: Optional[str] = None,
...
):
...
我如何使用pydantic定义检查和API定义,而不是仅仅使用str
,这样检查是pydantic完成的,而openapi模式定义更具描述性?
有一些方法可以做你想做的事情。但是FastAPI只允许序列结构(列表,元组,集合,序列)的查询和头参数,使&filter={"q":"bar"}
它不会工作在FastAPI至少0.0.75版本,我正在工作。
如果你希望支持字典,你应该使用带有Body参数的POST方法。然后,您可以将您的值包装在Pydantic模型中以支持验证。
下面有两种方法可以在FastAPI中实现。
解决方案1:
class FilterModel(BaseModel):
filter: dict
@router.post(
"/posts"
)
async def list_users(
filters: FilterModel,
sort: Tuple[str, Literal["DESC", "ASC", "desc", "asc"]] = Query(("title", "ASC")),
ranges: Tuple[int, int] = Query((0, 24))
) -> None:
print(filters)
print(sort)
print(ranges)
model = MyModel(sort=sort, range=ranges)
print(model)
这将允许你调用这样的api:
POST http://my.api.url/posts?sort=title&sort=ASC&ranges=0&ranges=24
与身体:
{
"filter"={"q":"bar"}
}
解决方案2:
class MyModel(BaseModel):
sortBy: Optional[str]
sortOrder: Optional[Literal["DESC", "ASC", "desc", "asc"]]
min_range: Optional[int]
max_range: Optional[int]
class FilterModel(BaseModel):
filter: dict
@router.post(
"/posts"
)
async def list_users(
filters: FilterModel,
model: MyModel = Depends()
) -> None:
print(filters)
print(model)
这将允许你调用这样的api:
POST http://my.api.url/posts?sortBy="title"&sortOrder="ASC"&min_range=0&max_range=24
与身体:
{
"filter"={"q":"bar"}
}
如果你想使用GET方法和filter
,你必须做一些hack的事情。