跳至內容

查詢參數和字串驗證

FastAPI 允許您為參數宣告額外資訊和驗證。

讓我們以這個應用程式為例

from fastapi import FastAPI

app = FastAPI()


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

from fastapi import FastAPI

app = FastAPI()


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

查詢參數 q 的類型為 Union[str, None](或 Python 3.10 中的 str | None),這表示它的類型為 str,但也可能是 None,實際上,預設值為 None,因此 FastAPI 會知道它不是必需的。

注意事項

FastAPI 會因為預設值 = None 而知道 q 的值不是必需的。

Union[str, None] 中的 Union 將允許您的編輯器提供更好的支援並偵測錯誤。

額外驗證

我們將強制執行,即使 q 是可選的,只要提供它,其長度不得超過 50 個字元

匯入 QueryAnnotated

要做到這一點,首先匯入

  • fastapi 匯入 Query
  • typing(或 Python 3.9 以下版本中的 typing_extensions)匯入 Annotated

在 Python 3.9 或更高版本中,Annotated 是標準函式庫的一部分,因此您可以從 typing 匯入它。

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

在 Python 3.9 以下的版本中,您從 typing_extensions 匯入 Annotated

它將與 FastAPI 一起安裝。

from typing import Union

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

資訊

FastAPI 在 0.95.0 版中新增了對 Annotated 的支援(並開始推薦它)。

如果您使用的是舊版本,則嘗試使用 Annotated 時會發生錯誤。

在使用 Annotated 之前,請確保您將 FastAPI 版本升級到至少 0.95.1。

q 參數的類型中使用 Annotated

記得我之前在Python 類型簡介中告訴過您,Annotated 可以用來向您的參數新增中繼資料嗎?

現在是時候將它與 FastAPI 一起使用了。 🚀

我們有這個類型註釋

q: str | None = None
q: Union[str, None] = None

我們要做的是用 Annotated 包括它,所以它變成

q: Annotated[str | None] = None
q: Annotated[Union[str, None]] = None

這兩個版本的意思相同,q 是一個可以是 strNone 的參數,預設情況下,它是 None

現在讓我們跳到有趣的部分。 🎉

q 參數中,將 Query 加入 Annotated

現在我們有了這個 Annotated,可以在其中放入更多資訊(在這個例子中是一些額外的驗證),在 Annotated 內加入 Query,並將參數 max_length 設定為 50

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

請注意,預設值仍然是 None,因此該參數仍然是可選的。

但現在,在 Annotated 中有了 Query(max_length=50),我們告訴 FastAPI 我們希望它對這個值進行額外的驗證,我們希望它的最大長度為 50 個字元。 😎

提示

這裡我們使用 Query(),因為這是一個查詢參數。稍後我們會看到其他像 Path()Body()Header()Cookie(),它們也接受與 Query() 相同的參數。

FastAPI 現在將

  • 驗證數據,確保最大長度為 50 個字元
  • 當數據無效時,向用戶端顯示清晰的錯誤訊息
  • 在 OpenAPI schema 的路徑操作記錄參數(這樣它就會顯示在自動文件 UI 中)

替代方案(舊版):將 Query 作為預設值

早期版本的 FastAPI(0.95.0 之前)要求您使用 Query 作為參數的預設值,而不是將其放在 Annotated 中,您很有可能會看到使用它的程式碼,所以我會向您解釋。

提示

對於新的程式碼,以及在任何可能的情況下,請使用上述的 Annotated。它有多種優點(下文說明),而且沒有缺點。🍰

以下是您如何使用 Query() 作為函式參數的預設值,將參數 max_length 設定為 50

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

由於在這種情況下(不使用 Annotated)我們必須用 Query() 取代函式中的預設值 None,我們現在需要使用參數 Query(default=None) 設定預設值,它的作用與定義該預設值相同(至少對於 FastAPI 而言)。

所以

q: Union[str, None] = Query(default=None)

...使參數成為可選的,預設值為 None,與

q: Union[str, None] = None

以及在 Python 3.10 及更高版本中

q: str | None = Query(default=None)

...使參數成為可選的,預設值為 None,與

q: str | None = None

相同,但 Query 版本明確地將其宣告為查詢參數。

資訊

請記住,使參數成為可選的最重要部分是

= None

= Query(default=None)

部分,因為它會使用 None 作為預設值,這樣使參數非必要

Union[str, None] 部分允許您的編輯器提供更好的支援,但它並不是告訴 FastAPI 這個參數不是必需的。

然後,我們可以將更多參數傳遞給 Query。在這種情況下,max_length 參數適用於字串

q: Union[str, None] = Query(default=None, max_length=50)

這將驗證數據,在數據無效時顯示清晰的錯誤訊息,並在 OpenAPI schema 的路徑操作中記錄參數。

Query 作為預設值或放在 Annotated

請記住,當在 Annotated 中使用 Query 時,您不能使用 Querydefault 參數。

請使用函式參數的實際預設值。否則,它會不一致。

例如,這是不允許的

q: Annotated[str, Query(default="rick")] = "morty"

...因為不清楚預設值應該是 "rick" 還是 "morty"

所以,您應該使用(最好是)

q: Annotated[str, Query()] = "rick"

...或者在較舊的程式碼庫中,您會發現

q: str = Query(default="rick")

Annotated 的優點

建議使用 Annotated,而不是在函式參數中使用預設值,這樣做基於多種原因會**更好**。🤓

**函式參數**的**預設值**是**實際的預設值**,這通常來說在 Python 中更直觀。😌

您可以在 FastAPI 之外的**其他地方**呼叫同一個函式,它會**按預期工作**。如果有一個**必要**參數(沒有預設值),您的**編輯器**會透過錯誤訊息讓您知道,如果您在執行時沒有傳遞必要的參數,**Python** 也會發出錯誤訊息。

當您不使用 Annotated 而是使用**(舊的)預設值樣式**時,如果您在 FastAPI 之外的**其他地方**呼叫該函式,您必須**記住**將參數傳遞給函式才能使其正常工作,否則值會與您的預期不同(例如,會是 QueryInfo 或類似的东西,而不是 str)。而且您的編輯器不會發出錯誤訊息,執行該函式時 Python 也不會發出錯誤訊息,只有在內部操作出錯時才會出現錯誤。

由於 Annotated 可以有多個中繼資料註釋,您現在甚至可以使用其他工具與相同的函式搭配使用,例如 Typer。🚀

新增更多驗證

您也可以新增參數 min_length

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

新增正規表達式

您可以定義參數應該符合的正規表達式 pattern

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

這個特定的正規表達式模式會檢查接收到的參數值

  • ^:以以下字元開頭,前面沒有字元。
  • fixedquery:具有確切值 fixedquery
  • $:在此結束,在 fixedquery 之後沒有任何其他字元。

如果您對所有這些**「正規表達式」**的概念感到困惑,請不要擔心。它們對許多人來說是一個困難的主題。您仍然可以在不需要正規表達式的情況下完成很多工作。

但是,當您需要它們並去學習它們時,請知道您已經可以直接在 **FastAPI** 中使用它們。

Pydantic v1 使用 regex 而不是 pattern

在 Pydantic 版本 2 和 FastAPI 0.100.0 之前,該參數稱為 regex 而不是 pattern,但現在已棄用。

您可能仍然會看到一些使用它的程式碼

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

但要知道,這已被棄用,應該更新為使用新的參數 pattern。🤓

預設值

您當然可以使用 None 以外的預設值。

假設您想要宣告 q 查詢參數的 min_length3,並且預設值為 "fixedquery"

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

注意事項

具有任何類型的預設值,包括 None,都會使參數成為選用(非必要)。

必要參數

當我們不需要宣告更多驗證或中繼資料時,我們可以透過不宣告預設值來使 q 查詢參數成為必要參數,例如

q: str

而不是

q: Union[str, None] = None

但我們現在用 Query 宣告它,例如

q: Annotated[Union[str, None], Query(min_length=3)] = None
q: Union[str, None] = Query(default=None, min_length=3)

因此,當您需要在使用 Query 時將值宣告為必要參數時,您可以簡單地不宣告預設值

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

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

提示

請注意,即使在這種情況下,Query() 被用作函式參數的預設值,我們也不會將 default=None 傳遞給 Query()

儘管如此,使用 Annotated 版本可能還是比較好。 😉

搭配省略號 (...) 使用的必要性

有另一種方法可以明確宣告一個值是必要的。您可以將預設值設定為字面值 ...

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

資訊

如果您以前沒看過 ...:它是一個特殊的單一值,它是 Python 的一部分,稱為「省略號」

Pydantic 和 FastAPI 使用它來明確宣告一個值是必要的。

這會讓 FastAPI 知道這個參數是必要的。

必要,可以是 None

您可以宣告一個參數可以接受 None,但它仍然是必要的。這會強制客戶端傳送一個值,即使該值是 None

要做到這一點,您可以宣告 None 是一個有效的類型,但仍然使用 ... 作為預設值。

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

Pydantic 是 FastAPI 中所有資料驗證和序列化功能的基礎,當您使用沒有預設值的 OptionalUnion[Something, None] 時,它有一個特殊的行為,您可以在 Pydantic 文件中關於 必要欄位 的部分了解更多資訊。

提示

請記住,在大多數情況下,當某個東西是必要的時候,您可以直接省略預設值,所以您通常不需要使用 ...

查詢參數列表 / 多個值

當您使用 Query 明確定義查詢參數時,您也可以宣告它接收值的列表,或者換句話說,接收多個值。

例如,要宣告一個可以在 URL 中出現多次的查詢參數 q,您可以這樣寫:

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Annotated[list[str] | None, Query()] = None):
    query_items = {"q": q}
    return query_items
from typing import Annotated, Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Annotated[Union[list[str], None], Query()] = None):
    query_items = {"q": q}
    return query_items
from typing import List, Union

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import List, Union

from fastapi import FastAPI, Query

app = FastAPI()


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

然後,使用像這樣的 URL:

http://localhost:8000/items/?q=foo&q=bar

您會在您的*路徑操作函式*中,*函式參數* q 中,以 Python list 的形式接收到多個 q *查詢參數*的值(foobar)。

因此,該 URL 的回應將是:

{
  "q": [
    "foo",
    "bar"
  ]
}

提示

要宣告一個類型為 list 的查詢參數,如上例所示,您需要明確使用 Query,否則它會被解釋為請求主體。

互動式 API 文件將會相應更新,允許多個值。

帶有預設值的查詢參數列表 / 多個值

如果沒有提供任何值,您也可以定義一個預設的 list 值。

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import List

from fastapi import FastAPI, Query

app = FastAPI()


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

如果您前往:

http://localhost:8000/items/

q 的預設值將是:["foo", "bar"],您的回應將是:

{
  "q": [
    "foo",
    "bar"
  ]
}

僅使用 list

您也可以直接使用 list,而不是 List[str](或 Python 3.9+ 中的 list[str])。

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Annotated[list, Query()] = []):
    query_items = {"q": q}
    return query_items
from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

注意事項

請記住,在這種情況下,FastAPI 不會檢查列表的內容。

例如,List[int] 會檢查(並記錄)列表的內容是否為整數。但單獨使用 list 則不會。

宣告更多中繼資料

您可以新增更多關於參數的資訊。

這些資訊將包含在產生的 OpenAPI 中,並由文件使用者介面和外部工具使用。

注意事項

請記住,不同的工具可能具有不同程度的 OpenAPI 支援。

其中一些可能尚未顯示所有已宣告的額外資訊,但在大多數情況下,缺少的功能已規劃開發。

您可以新增一個 title(標題)

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

以及一個 description(描述)

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: str | None = Query(
        default=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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=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

像這樣

http://127.0.0.1:8000/items/?item-query=foobaritems

item-query 不是有效的 Python 變數名稱。

最接近的應該是 item_query

但您仍然需要它是 item-query...

那麼您可以宣告一個 alias(別名),該別名將用於查找參數值。

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query

app = FastAPI()


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

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


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

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

棄用參數

現在假設您不再喜歡這個參數了。

您必須將其保留一段時間,因為有客戶正在使用它,但您希望在文件中清楚地將其顯示為已棄用

然後將參數 deprecated=True 傳遞給 Query

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Annotated[
        str | None,
        Query(
            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,
            pattern="^fixedquery$",
            deprecated=True,
        ),
    ] = None,
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
from typing import Annotated, Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Annotated[
        Union[str, None],
        Query(
            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,
            pattern="^fixedquery$",
            deprecated=True,
        ),
    ] = None,
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
from typing import Union

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Annotated[
        Union[str, None],
        Query(
            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,
            pattern="^fixedquery$",
            deprecated=True,
        ),
    ] = None,
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: str | None = Query(
        default=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,
        pattern="^fixedquery$",
        deprecated=True,
    ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=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,
        pattern="^fixedquery$",
        deprecated=True,
    ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

文件將會像這樣顯示

從 OpenAPI 中排除參數

要從產生的 OpenAPI 綱要(以及自動文件系統)中排除查詢參數,請將 Queryinclude_in_schema 參數設定為 False

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None,
):
    if hidden_query:
        return {"hidden_query": hidden_query}
    else:
        return {"hidden_query": "Not found"}
from typing import Annotated, Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None,
):
    if hidden_query:
        return {"hidden_query": hidden_query}
    else:
        return {"hidden_query": "Not found"}
from typing import Union

from fastapi import FastAPI, Query
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/")
async def read_items(
    hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None,
):
    if hidden_query:
        return {"hidden_query": hidden_query}
    else:
        return {"hidden_query": "Not found"}

提示

如果可能,建議使用 Annotated 版本。

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    hidden_query: str | None = Query(default=None, include_in_schema=False),
):
    if hidden_query:
        return {"hidden_query": hidden_query}
    else:
        return {"hidden_query": "Not found"}

提示

如果可能,建議使用 Annotated 版本。

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    hidden_query: Union[str, None] = Query(default=None, include_in_schema=False),
):
    if hidden_query:
        return {"hidden_query": hidden_query}
    else:
        return {"hidden_query": "Not found"}

摘要

您可以為參數宣告額外的驗證和中繼資料。

通用驗證和中繼資料

  • alias(別名)
  • title(標題)
  • description(描述)
  • deprecated(已棄用)

字串特定的驗證

  • min_length(最小長度)
  • max_length(最大長度)
  • pattern(模式)

在這些範例中,您看到了如何宣告 str(字串)值的驗證。

請參閱後續章節,了解如何宣告其他類型的驗證,例如數字。