FastAPI swagger 不喜欢通过查询参数传递的字符串列表,但端点在浏览器中工作

FastAPI swagger doesn't like list of strings passed via query parameter but endpoint works in browser

我在 FastAPI 中的 REST API 端点有问题,它通过单个查询参数接受字符串列表。此端点的用法示例是:

http://127.0.0.1:8000/items/2?short=false&response=this&response=that

此处,名为 'response' 的参数接受 FastAPI 教程中 Query Parameters and String Validation 部分中记录的字符串列表。端点在浏览器中按预期工作。

但是,它在 Swagger 文档中不起作用。单击 'Execute' 以测试端点时,标记为 'Add string item' 的按钮会晃动。 Swagger UI 似乎无法使用嵌入式查询参数创建预期的 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"]}

感谢任何帮助。

here, this happens due to that OpenAPI applies the pattern (as well as minimum and maximum constraints) to the schema of the array itself, not just the individual items in the array. If you checked the OpenAPI schema at 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"
      }

解决方案 1

如前所述 here, you could use a 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...")

解决方案 2

保持 response 参数不变。从 http://127.0.0.1:8000/openapi.json 复制 OpenAPI 架构,从 response (array) 中删除 pattern(以及 minimummaximum 属性)模式并将 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"))

解决方案 3

由于上述解决方案要求您在每次进行更改或添加新内容时都复制和编辑架构 endpoints/parameters,因此您宁愿按照 here 所述修改 OpenAPI 架构。这将使您免于 copying/editing 模式文件。确保在代码末尾添加以下内容(在定义所有路由之后)。

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(即 (query) maxLength: 99 minLength: 3 pattern: ^[a-zA-Z]+$)下显示的约束注释不会出现(因为 Swagger 会从约束应用于 array,而不是 items),但 doesn't seem to be a way to preserve that。但是,在解决方案 2 和 3 中,您可以修改上面 JSON 代码片段中显示的 "in" 属性,以手动添加注释。但是,由于 HTML 元素等由 Swagger 控制,因此整个注释将出现在括号内并且约束之间没有换行符。尽管如此,您仍然可以通过在 Query 参数的 description 中指定它们来告知用户有关 items 的约束。