如何使用 FastAPI 和 Swagger 允许任意查询参数?

Ste*_*veJ 9 python swagger fastapi

注意:这个问题与这里的问题不同,因为我需要它与 Swagger 一起工作。

给定一个 FastAPIGET端点,我希望允许任意一组 URL 参数,同时保持 Swagger 支持。

我的用例是我想要支持一组类似于 JSON API 的查询参数,如下所示:

/api/books/?include=author&sort=name,zip&sort[author]=-lname&fields=name,phone,street
Run Code Online (Sandbox Code Playgroud)

使用方括号使我无法使用传统的类来对查询参数进行建模,因此我直接使用该Request对象。但是,我想使用 Swagger 来测试端点。我找不到提供任意 URL 参数的方法。我很高兴将它们作为单个字符串输入。

人们可能会这样想:

def books(**params): 
    ....
Run Code Online (Sandbox Code Playgroud)

这给出了一个curl语句:

api/books?params=sort%5Bone%5D%3Dtwo'
Run Code Online (Sandbox Code Playgroud)

我真正想要的是:

api/books?sort&one%5D%3Dtwo'
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 2

您可以使用可选字符串参数(book_params在下面的情况中)通过 OpenAPI (Swagger UI) 将查询参数作为单个字符串传递,例如include=author&sort=name,zip&sort[author]=-lname&fields=name,phone,street. 然后,您可以解析查询数据(使用urllib.parse.parse_qs)来获取字典,如下所示。

下面的示例也利用此处描述的方法,以修复parse_qs将单个值解析为列表的部分(例如,'foo=bar'将解析为foo = ['bar']),同时还保留用户传递列表的键的所有值。例如,如果用户在 URL 中多次传递相同的键(例如 )'foo=2&bar=7&foo=10',则使用dict(request.query_params)检索查询参数将导致{"foo":"10","bar":"7"}而不是{"foo":["2","10"],"bar":"7"}。然而,下面的示例中演示的方法(使用上述方法)也通过解析查询字符串(可以使用 检索request.url.query)来解决这个问题,并确保保留实际列表。

您可以检查该可选参数是否book_params为空,以决定是使用book_params(即通过 Swagger 发送请求)还是Request直接使用对象(即通过键入 URL 发送请求)来读取查询参数进入浏览器的地址栏,例如,http://127.0.0.1:8000/api/books?include=author&sort=name,zip&sort[author]=-lname&fields=name,phone,street或使用其他客户端应用程序)。请确保将该可选参数(即book_params)命名为唯一的名称,该参数也不会成为实际参数的一部分。

from fastapi import FastAPI, Request
from typing import Optional
from urllib.parse import parse_qs

app = FastAPI()

@app.get("/api/books")
def books(request: Request, book_params: Optional[str] = None):
    q_params = {}
    
    if book_params is not None:
        q_params = parse_qs(book_params, keep_blank_values=True)
    else:   
        q_params = parse_qs(request.url.query, keep_blank_values=True)
        
    d = dict((k, v if len(v)>1 else v[0]) 
                for k, v in q_params.items())

    return d
Run Code Online (Sandbox Code Playgroud)