FastAPI学习-4.get 请求 query params 参数校验

2022-03-03 15:39:35 浏览数 (1)

前言

get请求在接收参数的时候,需校验用户传过来的参数是否合法

查询参数和字符串校验

FastAPI 允许你为参数声明额外的信息和校验。让我们以下面的应用程序为例:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
async def read_items(q: Optional[str] = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

查询参数 q 的类型为 str,默认值为 None,因此它是可选的。

额外的校验

我们打算添加约束条件:即使 q 是可选的,但只要提供了该参数,则该参数值不能超过50个字符的长度。 为此,首先从 fastapi 导入 Query:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

使用 Query 作为默认值

现在,将 Query 用作查询参数的默认值,并将它的 max_length 参数设置为 50:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

由于我们必须用 Query(None) 替换默认值 None,Query 的第一个参数同样也是用于定义默认值。所以:

代码语言:javascript复制
q: str = Query(None)

使得参数可选,等同于:

代码语言:javascript复制
q: str = None

但是 Query 显式地将其声明为查询参数。然后,我们可以将更多的参数传递给 Query。在本例中,适用于字符串的 max_length 参数:

代码语言:javascript复制
q: str = Query(None, max_length=50)

将会校验数据,在数据无效时展示清晰的错误信息,并在 OpenAPI 模式的路径操作中记录该参数。

添加更多校验

你还可以添加 min_length 参数:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, min_length=3, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

添加正则表达式

你可以定义一个参数值必须匹配的正则表达式:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

这个指定的正则表达式通过以下规则检查接收到的参数值:

  • ^: 以该符号之后的字符开头,符号之前没有字符。
  • fixedquery: 值精确地等于 fixedquery。
  • $: 到此结束,在 fixedquery 之后没有更多字符。

如果你对所有的这些「正则表达式」概念感到迷茫,请不要担心。对于许多人来说这都是一个困难的主题。你仍然可以在无需正则表达式的情况下做很多事情。 但是,一旦你需要用到并去学习它们时,请了解你已经可以在 FastAPI 中直接使用它们。

默认值

你可以向 Query 的第一个参数传入 None 用作查询参数的默认值,以同样的方式你也可以传递其他默认值。 假设你想要声明查询参数 q,使其 min_length 为 3,并且默认值为 fixedquery:

代码语言:javascript复制
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: str = Query("fixedquery", min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

声明为必需参数

当我们不需要声明额外的校验或元数据时,只需不声明默认值就可以使 q 参数成为必需参数,例如:q: str代替:q: str = None 但是现在我们正在用 Query 声明它,例如:

代码语言:javascript复制
q: str = Query(None, min_length=3)

因此,当你在使用 Query 且需要声明一个值是必需的时,可以将 … 用作第一个参数值:

代码语言:javascript复制
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: str = Query(..., min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

如果你之前没见过 ... 这种用法:它是一个特殊的单独值,它是 Python 的一部分并且被称为「省略号」.这将使 FastAPI 知道此查询参数是必需的。

查询参数列表 / 多个值

当你使用 Query 显式地定义查询参数时,你还可以声明它去接收一组值,或换句话来说,接收多个值。 例如,要声明一个可在 URL 中出现多次的查询参数 q,你可以这样写:

代码语言:javascript复制
from typing import List, Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Optional[List[str]] = Query(None)):
    query_items = {"q": q}
    return query_items

然后,输入如下网址:

代码语言:javascript复制
http://localhost:8000/items/?q=foo&q=bar

你会在路径操作函数的函数参数 q 中以一个 Python list 的形式接收到查询参数 q 的多个值(foo 和 bar)。 因此,该 URL 的响应将会是:

代码语言:javascript复制
{
  "q": [
    "foo",
    "bar"
  ]
}

要声明类型为 list 的查询参数,如上例所示,你需要显式地使用 Query,否则该参数将被解释为请求体。 交互式 API 文档将会相应地进行更新,以允许使用多个值:

具有默认值的查询参数列表 / 多个值

你还可以定义在没有任何给定值时的默认 list 值:

代码语言:javascript复制
from typing import List

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: List[str] = Query(["foo", "bar"])):
    query_items = {"q": q}
    return query_items

如果你访问:

代码语言:javascript复制
http://localhost:8000/items/

q 的默认值将为:[“foo”, “bar”],你的响应会是:

代码语言:javascript复制
{
  "q": [
    "foo",
    "bar"
  ]
}

使用 list

你也可以直接使用 list 代替 List [str]:

代码语言:javascript复制
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: list = Query([])):
    query_items = {"q": q}
    return query_items

请记住,在这种情况下 FastAPI 将不会检查列表的内容。 例如,List[int] 将检查(并记录到文档)列表的内容必须是整数。但是单独的 list 不会。

声明更多元数据

你可以添加更多有关该参数的信息。 这些信息将包含在生成的 OpenAPI 模式中,并由文档用户界面和外部工具所使用。 你可以添加 title:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    q: Optional[str] = Query(None, title="Query string", min_length=3)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

以及 description:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    q: Optional[str] = Query(
        None,
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

别名参数

假设你想要查询参数为 item-query。 像下面这样:

代码语言:javascript复制
http://127.0.0.1:8000/items/?item-query=foobaritems

但是 item-query 不是一个有效的 Python 变量名称。 最接近的有效名称是 item_query。 但是你仍然要求它在 URL 中必须是 item-query… 这时你可以用 alias 参数声明一个别名,该别名将用于在 URL 中查找查询参数值:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, alias="item-query")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

弃用参数

现在假设你不再喜欢此参数。你不得不将其保留一段时间,因为有些客户端正在使用它,但你希望文档清楚地将其展示为已弃用。 那么将参数 deprecated=True 传入 Query:

代码语言:javascript复制
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    q: Optional[str] = Query(
        None,
        alias="item-query",
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
        max_length=50,
        regex="^fixedquery$",
        deprecated=True,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

总结 你可以为查询参数声明额外的校验和元数据。 通用的校验和元数据:

  • alias
  • title
  • description
  • deprecated 特定于字符串的校验:
  • min_length
  • max_length
  • regex 在这些示例中,你了解了如何声明对 str 值的校验。

0 人点赞