API JSON 使用 Pydantic 对可选元素进行模式验证
API JSON Schema Validation with Optional Element using Pydantic
我正在使用 pydantic 的 fastapi 和 BaseModel 来验证和记录 API return.
的 JSON 模式
这适用于固定的 return 但我有可选参数可以更改 return 所以我想将它包含在验证中但是当参数丢失时它不会失败并且该字段未在 API.
中 returned
例如:我有一个名为 transparency
的可选布尔参数,当它设置为 true 时,我 return 一个名为 search_transparency 的块,带有弹性查询 returned .
{
"info": {
"totalrecords": 52
},
"records": [],
"search_transparency": {"full_query": "blah blah"}
}
如果未设置参数 transparency=true
我希望 return 为:
{
"info": {
"totalrecords": 52
},
"records": []
}
但是,当我在 pydantic 中将该元素设置为可选时,我得到的是 returned:
{
"info": {
"totalrecords": 52
},
"records": [],
"search_transparency": None
}
对于记录下的字段,我有类似的东西。默认是最少 return 个字段,但如果您设置参数 full=true
,那么您会得到更多 return 字段。我想以类似的方式处理这个问题,只是字段不存在而不是显示 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 实践,也许我不应该有变量 returns.
我是否应该创建多个单独的端点来处理这个问题?
例如。 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 只是 return 一个 elasticsearch 响应。
这是我的解析函数:
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
可能排除该字段,如果它 None
可以完成工作。
只需添加一个response_model_exclude_none = True
作为路径参数
@app.get(
"/api/v1/place/search",
response_model=V1PlaceAPI,
tags=["v1_api"],
response_model_exclude_none=True,
)
您可以进一步自定义您的 Response 模型,这里有一个很好的解释 answer 我真的建议您检查一下。
我正在使用 pydantic 的 fastapi 和 BaseModel 来验证和记录 API return.
的 JSON 模式这适用于固定的 return 但我有可选参数可以更改 return 所以我想将它包含在验证中但是当参数丢失时它不会失败并且该字段未在 API.
中 returned例如:我有一个名为 transparency
的可选布尔参数,当它设置为 true 时,我 return 一个名为 search_transparency 的块,带有弹性查询 returned .
{
"info": {
"totalrecords": 52
},
"records": [],
"search_transparency": {"full_query": "blah blah"}
}
如果未设置参数 transparency=true
我希望 return 为:
{
"info": {
"totalrecords": 52
},
"records": []
}
但是,当我在 pydantic 中将该元素设置为可选时,我得到的是 returned:
{
"info": {
"totalrecords": 52
},
"records": [],
"search_transparency": None
}
对于记录下的字段,我有类似的东西。默认是最少 return 个字段,但如果您设置参数 full=true
,那么您会得到更多 return 字段。我想以类似的方式处理这个问题,只是字段不存在而不是显示 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 实践,也许我不应该有变量 returns.
我是否应该创建多个单独的端点来处理这个问题?
例如。 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 只是 return 一个 elasticsearch 响应。 这是我的解析函数:
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
可能排除该字段,如果它 None
可以完成工作。
只需添加一个response_model_exclude_none = True
作为路径参数
@app.get(
"/api/v1/place/search",
response_model=V1PlaceAPI,
tags=["v1_api"],
response_model_exclude_none=True,
)
您可以进一步自定义您的 Response 模型,这里有一个很好的解释 answer 我真的建议您检查一下。