【发布时间】:2021-01-15 23:04:27
【问题描述】:
我正在使用 pydantic 的 fastapi 和 BaseModel 来验证和记录 API 返回的 JSON 模式。
这适用于固定返回,但我有更改返回的可选参数,因此我想将其包含在验证中,但当参数丢失且 API 中未返回该字段时它不会失败。
例如:我有一个名为 transparency 的可选布尔参数,当它设置为 true 时,我会返回一个名为 search_transparency 的块,并返回弹性查询。
{
"info": {
"totalrecords": 52
},
"records": [],
"search_transparency": {"full_query": "blah blah"}
}
如果没有设置参数transparency=true 我希望返回为:
{
"info": {
"totalrecords": 52
},
"records": []
}
但是,当我在 pydantic 中将该元素设置为 Optional 时,我得到的是返回:
{
"info": {
"totalrecords": 52
},
"records": [],
"search_transparency": None
}
我对记录下的字段有类似的东西。默认是最小的字段返回,但是如果您设置参数full=true,那么您会返回更多字段。我想以类似的方式处理这个问题,只是字段不存在而不是显示为None。
这就是我使用 pydantic 处理它的方式:
class Info(BaseModel):
totalrecords: int
class Transparency(BaseModel):
full_query: str
class V1Place(BaseModel):
name: str
class V1PlaceAPI(BaseModel):
info: Info
records: List[V1Place] = []
search_transparency: Optional[Transparency]
这就是我使用 fastapi 执行验证的方式:
@app.get("/api/v1/place/search", response_model=V1PlaceAPI, tags=["v1_api"])
我怀疑也许我想要实现的是糟糕的 API 实践,也许我不应该有可变回报。
我是否应该创建多个单独的端点来处理这个问题?
例如。 api/v1/place/search?q=test 与 api/v1/place/full/transparent/search?q=test
编辑
我的 API 函数的更多细节:
@app.get("/api/v1/place/search", response_model=V1PlaceAPI, tags=["v1_api"])
def v1_place_search(q: str = Query(None, min_length=3, max_length=500, title="search through all place fields"),
transparency: Optional[bool] = None,
offset: Optional[int] = Query(0),
limit: Optional[int] = Query(15)):
search_limit = offset + limit
results, transparency_query = ESQuery(client=es_client,
index='places',
transparency=transparency,
track_hits=True,
offset=offset,
limit=search_limit)
return v1_place_parse(results.to_dict(),
show_transparency=transparency_query)
其中 ESQuery 只返回一个弹性搜索响应。 这是我的解析函数:
def v1_place_parse(resp, show_transparency=None):
"""This takes a response from elasticsearch and parses it for our legacy V1 elasticapi
Args:
resp (dict): This is the response from Search.execute after passing to_dict()
Returns:
dict: A dictionary that is passed to API
"""
new_resp = {}
total_records = resp['hits']['total']['value']
query_records = len(resp.get('hits', {}).get('hits', []))
new_resp['info'] = {'totalrecords': total_records,
'totalrecords_relation': resp['hits']['total']['relation'],
'totalrecordsperquery': query_records,
}
if show_transparency is not None:
search_string = show_transparency.get('query', '')
new_resp['search_transparency'] = {'full_query': str(search_string),
'components': {}}
new_resp['records'] = []
for hit in resp.get('hits', {}).get('hits', []):
new_record = hit['_source']
new_resp['records'].append(new_record)
return new_resp
【问题讨论】:
-
您可以返回两个类的联合,其中一个是透明的,而另一个不是。您介意展示您正在使用的端点功能吗?所以我可以提供一个接近您需求的示例
-
谢谢 - 我已经添加了详细信息
标签: rest jsonschema fastapi pydantic