У меня проблема с конечной точкой REST API в FastAPI, которая принимает список строк через один параметр запроса. Пример использования этой конечной точки:
http://127.0.0.1:8000/items/2?short=false&response=this&response=that
Здесь параметр с именем «ответ» принимает список строк, как описано в руководстве по FastAPI, раздел Параметры запроса и проверка строки. Конечная точка работает в браузере должным образом.
Однако это не работает в документах Swagger. Кнопка с надписью «Добавить строковый элемент» дрожит при нажатии «Выполнить», чтобы проверить конечную точку. Пользовательский интерфейс Swagger, похоже, не может создать ожидаемый URL-адрес со встроенными параметрами запроса (как показано на рис. 1).
Код для конечной точки выглядит следующим образом. Пробовал с проверкой и без.
@app.get("/items/{item_ID}")
async def getQuestion_byID(item_ID: int = Path(
...,
title = "Numeric ID of the question",
description = "Specify a number between 1 and 999",
ge = 1,
le = 999
), response: Optional[List[str]] = Query(
[],
title = "Furnish an answer",
description = "Answer can only have letters of the alphabet and is case-insensitive",
min_length=3,
max_length=99,
regex = "^[a-zA-Z]+$"
), short: bool = Query(
False,
title = "Set flag for short result",
description = "Acceptable values are 1, True, true, on, yes"
)):
"""
Returns the quiz question or the result.
Accepts item ID as path parameter and
optionally response as query parameter.
Returns result when the response is passed with the item ID.
Otherwise, returns the quiz question.
"""
item = question_bank.get(item_ID, None)
if not item:
return {"question": None}
if response:
return evaluate_response(item_ID, response, short)
else:
return {"question": item["question"]}
Благодарен за любую помощь.
Возможно связано: github.com/tiangolo/fastapi/issues/4345. См. также github.com/tiangolo/fastapi/issues/1021#issuecomment-590353181
@Helen привет! Когда я навожу курсор на кнопку, всплывающая подсказка говорит: «Значение должно соответствовать шаблону..». Но сопоставление с образцом работает, как и ожидалось, когда я вызываю конечную точку через браузер.
Как описано в здесь, это происходит из-за того, что OpenAPI применяет pattern
(а также ограничения minimum
и maximum
) к схеме самого array
, а не только к отдельным items
в массиве. Если вы нажмете проверил схему OpenAPI на http://127.0.0.1:8000/openapi.json, вы увидите, что схема для параметра response
выглядит так, как показано ниже (т. е. проверки применяются и к самому array
):
{
"description": "Answer can only have letters of the alphabet and is case-insensitive",
"required": false,
"schema": {
"title": "Furnish an answer",
"maxLength": 99,
"minLength": 3,
"pattern": "^[a-zA-Z]+$",
"type": "array",
"items": {
"maxLength": 99,
"minLength": 3,
"pattern": "^[a-zA-Z]+$",
"type": "string"
},
"description": "Answer can only have letters of the alphabet and is case-insensitive",
"default": []
},
"name": "response",
"in": "query"
}
Как упоминалось здесь, вместо этого вы можете использовать Pydantic constr
, чтобы указать items
с этим ограничением:
my_constr = constr(regex = "^[a-zA-Z]+$", min_length=3, max_length=99)
response: Optional[List[my_constr]] = Query([], title = "Furnish an...", description = "Answer can...")
Оставьте параметр response
как есть. Скопируйте схему OpenAPI из http://127.0.0.1:8000/openapi.json, удалите pattern
(а также атрибуты minimum
и maximum
) из схемы response
(array
) и сохраните схему OpenAPI в новый файл (например, my_openapi.json
). Это должно выглядеть так:
...
{
"description": "Answer can only have letters of the alphabet and is case-insensitive",
"required": false,
"schema": {
"title": "Furnish an answer",
"type": "array",
"items": {
"maxLength": 99,
"minLength": 3,
"pattern": "^[a-zA-Z]+$",
"type": "string"
},
"description": "Answer can only have letters of the alphabet and is case-insensitive",
"default": []
},
"name": "response",
"in": "query"
},
...
Затем в своем приложении укажите FastAPI использовать эту схему:
import json
app.openapi_schema = json.load(open("my_openapi.json"))
Поскольку приведенное выше решение потребует от вас копирования и редактирования схемы каждый раз, когда вы вносите изменения или добавляете новые конечные точки/параметры, вам лучше изменить схему OpenAPI, как описано здесь. Это избавит вас от копирования/редактирования файла схемы. Обязательно добавьте приведенное ниже в конец вашего кода (после определения всех маршрутов).
from fastapi.openapi.utils import get_openapi
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title = "FastAPI",
version = "0.1.0",
description = "This is a very custom OpenAPI schema",
routes=app.routes,
)
del openapi_schema["paths"]["/items/{item_ID}"]["get"]["parameters"][1]["schema"]["maxLength"]
del openapi_schema["paths"]["/items/{item_ID}"]["get"]["parameters"][1]["schema"]["minLength"]
del openapi_schema["paths"]["/items/{item_ID}"]["get"]["parameters"][1]["schema"]["pattern"]
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
Во всех приведенных выше решениях аннотация ограничений, которая обычно отображается в OpenAPI под response
(т. похоже, это не способ сохранить это. Однако в решениях 2 и 3 вы можете изменить атрибут (query) maxLength: 99 minLength: 3 pattern: ^[a-zA-Z]+$
, показанный во фрагменте кода array
выше, чтобы добавить аннотацию вручную. Но, поскольку элементы items
и т. д. контролируются Swagger, вся аннотация будет отображаться внутри круглых скобок и без разрывов строк между ограничениями. Тем не менее, вы все равно можете информировать пользователей об ограничениях, применяемых к "in"
, указав их в JSON
вашего параметра HTML
.
1) Если навести курсор на кнопку «Добавить строковый элемент», когда она красная, что скажет всплывающая подсказка? 2) Можете ли вы экспортировать определение OpenAPI из пользовательского интерфейса Swagger и опубликовать часть с параметром
response
? Я подозреваю, что аннотации кода FastAPI немного неверны.