Zum Inhalt

Query-Parameter und String-Validierungen

FastAPI ermöglicht es Ihnen, zusĂ€tzliche Informationen und Validierungen fĂŒr Ihre Parameter zu deklarieren.

Nehmen wir diese Anwendung als Beispiel:

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
đŸ€“ Other versions and variants
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

Der Query-Parameter q hat den Typ str | None, das bedeutet, dass er vom Typ str sein kann, aber auch None, und tatsĂ€chlich ist der Defaultwert None, sodass FastAPI weiß, dass er nicht erforderlich ist.

Hinweis

FastAPI erkennt, dass der Wert von q nicht erforderlich ist, aufgrund des Defaultwertes = None.

Die Verwendung von str | None ermöglicht es Ihrem Editor, Ihnen bessere UnterstĂŒtzung zu bieten und Fehler zu erkennen.

ZusÀtzliche Validierung

Wir werden sicherstellen, dass, obwohl q optional ist, wann immer es bereitgestellt wird, seine LĂ€nge 50 Zeichen nicht ĂŒberschreitet.

Query und Annotated importieren

Um dies zu erreichen, importieren Sie zuerst:

  • Query von fastapi
  • Annotated von 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
đŸ€“ Other versions and variants
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(max_length=50)] = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Info

FastAPI hat UnterstĂŒtzung fĂŒr Annotated hinzugefĂŒgt (und begonnen, es zu empfehlen) in der Version 0.95.0.

Wenn Sie eine Ă€ltere Version haben, wĂŒrden Sie Fehler erhalten, beim Versuch, Annotated zu verwenden.

Stellen Sie sicher, dass Sie die FastAPI-Version aktualisieren, auf mindestens Version 0.95.1, bevor Sie Annotated verwenden.

Verwenden von Annotated im Typ fĂŒr den q-Parameter

Erinnern Sie sich, dass ich Ihnen zuvor in Python-Typen-Intro gesagt habe, dass Annotated verwendet werden kann, um Metadaten zu Ihren Parametern hinzuzufĂŒgen?

Jetzt ist es soweit, dies mit FastAPI zu verwenden. 🚀

Wir hatten diese Typannotation:

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

Was wir tun werden, ist, dies mit Annotated zu wrappen, sodass es zu:

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

Beide dieser Versionen bedeuten dasselbe: q ist ein Parameter, der ein str oder None sein kann, und standardmĂ€ĂŸig ist er None.

Jetzt springen wir zu den spannenden Dingen. 🎉

Query zu Annotated im q-Parameter hinzufĂŒgen

Da wir nun Annotated haben, in das wir mehr Informationen (in diesem Fall einige zusĂ€tzliche Validierungen) einfĂŒgen können, fĂŒgen Sie Query innerhalb von Annotated hinzu und setzen Sie den Parameter max_length auf 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
đŸ€“ Other versions and variants
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(max_length=50)] = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Beachten Sie, dass der Defaultwert weiterhin None ist, so dass der Parameter weiterhin optional ist.

Aber jetzt, mit Query(max_length=50) innerhalb von Annotated, sagen wir FastAPI, dass wir eine zusĂ€tzliche Validierung fĂŒr diesen Wert wĂŒnschen, wir wollen, dass er maximal 50 Zeichen hat. 😎

Tipp

Hier verwenden wir Query(), weil dies ein Query-Parameter ist. SpÀter werden wir andere wie Path(), Body(), Header(), und Cookie() sehen, die auch dieselben Argumente wie Query() akzeptieren.

FastAPI wird nun:

  • Die Daten validieren, um sicherzustellen, dass die LĂ€nge maximal 50 Zeichen betrĂ€gt
  • Einen klaren Fehler fĂŒr den Client anzeigen, wenn die Daten ungĂŒltig sind
  • Den Parameter in der OpenAPI-Schema-Pfadoperation dokumentieren (sodass er in der automatischen Dokumentation angezeigt wird)

Alternative (alt): Query als Defaultwert

FrĂŒhere Versionen von FastAPI (vor 0.95.0) erforderten, dass Sie Query als den Defaultwert Ihres Parameters verwendeten, anstatt es innerhalb von Annotated zu platzieren. Es besteht eine hohe Wahrscheinlichkeit, dass Sie Code sehen, der es so verwendet, also werde ich es Ihnen erklĂ€ren.

Tipp

FĂŒr neuen Code und wann immer es möglich ist, verwenden Sie Annotated wie oben erklĂ€rt. Es gibt mehrere Vorteile (unten erlĂ€utert) und keine Nachteile. 🍰

So wĂŒrden Sie Query() als den Defaultwert Ihres Funktionsparameters verwenden und den Parameter max_length auf 50 setzen:

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
đŸ€“ Other versions and variants
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 Annotated, Union

from fastapi import FastAPI, Query

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

Tip

Prefer to use the Annotated version if possible.

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

Da wir in diesem Fall (ohne die Verwendung von Annotated) den Defaultwert None in der Funktion durch Query() ersetzen mĂŒssen, mĂŒssen wir nun den Defaultwert mit dem Parameter Query(default=None) setzen, er erfĂŒllt den gleichen Zweck, diesen Defaultwert zu definieren (zumindest fĂŒr FastAPI).

Also:

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

... macht den Parameter optional mit einem Defaultwert von None, genauso wie:

q: str | None = None

Aber die Query-Version deklariert ihn explizit als Query-Parameter.

Dann können wir mehr Parameter an Query ĂŒbergeben. In diesem Fall den max_length-Parameter, der auf Strings angewendet wird:

q: str | None = Query(default=None, max_length=50)

Dies wird die Daten validieren, einen klaren Fehler anzeigen, wenn die Daten nicht gĂŒltig sind, und den Parameter in der OpenAPI-Schema-Pfadoperation dokumentieren.

Query als Defaultwert oder in Annotated

Beachten Sie, dass wenn Sie Query innerhalb von Annotated verwenden, Sie den default-Parameter fĂŒr Query nicht verwenden dĂŒrfen.

Setzen Sie stattdessen den tatsÀchlichen Defaultwert des Funktionsparameters. Andernfalls wÀre es inkonsistent.

Zum Beispiel ist das nicht erlaubt:

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

... denn es ist nicht klar, ob der Defaultwert "rick" oder "morty" sein soll.

Sie wĂŒrden also (bevorzugt) schreiben:

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

... oder in Àlteren Codebasen finden Sie:

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

VorzĂŒge von Annotated

Es wird empfohlen, Annotated zu verwenden, anstelle des Defaultwertes in Funktionsparametern, es ist aus mehreren GrĂŒnden besser. đŸ€“

Der Defaultwert des Funktionsparameters ist der tatsĂ€chliche Defaultwert, das ist in der Regel intuitiver mit Python. 😌

Sie könnten diese gleiche Funktion in anderen Stellen ohne FastAPI aufrufen, und es wĂŒrde wie erwartet funktionieren. Wenn es einen erforderlichen Parameter gibt (ohne Defaultwert), wird Ihr Editor Ihnen dies mit einem Fehler mitteilen, außerdem wird Python sich beschweren, wenn Sie es ausfĂŒhren, ohne den erforderlichen Parameter zu ĂŒbergeben.

Wenn Sie Annotated nicht verwenden und stattdessen die (alte) Defaultwert-Stilform verwenden, mĂŒssen Sie sich daran erinnern, die Argumente der Funktion zu ĂŒbergeben, wenn Sie diese Funktion ohne FastAPI in anderen Stellen aufrufen. Ansonsten sind die Werte anders als erwartet (z. B. QueryInfo oder etwas Ähnliches statt str). Ihr Editor kann Ihnen nicht helfen, und Python wird die Funktion ohne Klagen ausfĂŒhren und sich nur beschweren wenn die Operationen innerhalb auf einen Fehler stoßen.

Da Annotated mehr als eine Metadaten-Annotation haben kann, könnten Sie dieselbe Funktion sogar mit anderen Tools verwenden, wie z. B. Typer. 🚀

Mehr Validierungen hinzufĂŒgen

Sie können auch einen min_length-Parameter hinzufĂŒgen:

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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

RegulĂ€re AusdrĂŒcke hinzufĂŒgen

Sie können einen regulĂ€ren Ausdruck pattern definieren, mit dem der Parameter ĂŒbereinstimmen muss:

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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Dieses spezielle Suchmuster im regulĂ€ren Ausdruck ĂŒberprĂŒft, dass der erhaltene Parameterwert:

  • ^: mit den nachfolgenden Zeichen beginnt, keine Zeichen davor hat.
  • fixedquery: den exakten Text fixedquery hat.
  • $: dort endet, keine weiteren Zeichen nach fixedquery hat.

Wenn Sie sich mit all diesen „regulĂ€rer Ausdruck“-Ideen verloren fĂŒhlen, keine Sorge. Sie sind ein schwieriges Thema fĂŒr viele Menschen. Sie können noch viele Dinge tun, ohne regulĂ€re AusdrĂŒcke direkt zu benötigen.

Aber nun wissen Sie, dass Sie sie in FastAPI immer dann verwenden können, wenn Sie sie brauchen.

Defaultwerte

NatĂŒrlich können Sie Defaultwerte verwenden, die nicht None sind.

Nehmen wir an, Sie möchten, dass der q Query-Parameter eine min_length von 3 hat und einen Defaultwert von "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
đŸ€“ Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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

Hinweis

Ein Defaultwert irgendeines Typs, einschließlich None, macht den Parameter optional (nicht erforderlich).

Erforderliche Parameter

Wenn wir keine weiteren Validierungen oder Metadaten deklarieren mĂŒssen, können wir den q Query-Parameter erforderlich machen, indem wir einfach keinen Defaultwert deklarieren, wie:

q: str

statt:

q: str | None = None

Aber jetzt deklarieren wir es mit Query, zum Beispiel so:

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

Wenn Sie einen Wert als erforderlich deklarieren mĂŒssen, wĂ€hrend Sie Query verwenden, deklarieren Sie einfach keinen Defaultwert:

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
đŸ€“ Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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

Erforderlich, kann None sein

Sie können deklarieren, dass ein Parameter None akzeptieren kann, aber trotzdem erforderlich ist. Dadurch mĂŒssten Clients den Wert senden, selbst wenn der Wert None ist.

Um das zu tun, können Sie deklarieren, dass None ein gĂŒltiger Typ ist, einfach indem Sie keinen Defaultwert deklarieren:

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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, Query

app = FastAPI()


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

Tip

Prefer to use the Annotated version if possible.

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


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

Query-Parameter-Liste / Mehrere Werte

Wenn Sie einen Query-Parameter explizit mit Query definieren, können Sie ihn auch so deklarieren, dass er eine Liste von Werten empfÀngt, oder anders gesagt, dass er mehrere Werte empfangen kann.

Um zum Beispiel einen Query-Parameter q zu deklarieren, der mehrmals in der URL vorkommen kann, schreiben Sie:

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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Dann, mit einer URL wie:

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

wĂŒrden Sie die mehreren q-Query-Parameter-Werte (foo und bar) in einer Python-list in Ihrer Pfadoperation-Funktion im Funktionsparameter q erhalten.

So wÀre die Response zu dieser URL:

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

Tipp

Um einen Query-Parameter mit einem Typ list zu deklarieren, wie im obigen Beispiel, mĂŒssen Sie explizit Query verwenden, da er andernfalls als Requestbody interpretiert wĂŒrde.

Die interaktive API-Dokumentation wird entsprechend aktualisiert, um mehrere Werte zu erlauben:

Query-Parameter-Liste / Mehrere Werte mit Defaults

Sie können auch eine Default-list von Werten definieren, wenn keine bereitgestellt werden:

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
đŸ€“ Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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

Wenn Sie zu:

http://localhost:8000/items/

gehen, wird der Default fĂŒr q sein: ["foo", "bar"], und Ihre Response wird sein:

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

Nur list verwenden

Sie können auch list direkt verwenden, anstelle von 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
đŸ€“ Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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

Hinweis

Beachten Sie, dass FastAPI in diesem Fall den Inhalt der Liste nicht ĂŒberprĂŒft.

Zum Beispiel wĂŒrde list[int] ĂŒberprĂŒfen (und dokumentieren), dass der Inhalt der Liste Ganzzahlen sind. Aber list alleine wĂŒrde das nicht.

Mehr Metadaten deklarieren

Sie können mehr Informationen ĂŒber den Parameter hinzufĂŒgen.

Diese Informationen werden in das generierte OpenAPI aufgenommen und von den DokumentationsoberflÀchen und externen Tools verwendet.

Hinweis

Beachten Sie, dass verschiedene Tools möglicherweise unterschiedliche UnterstĂŒtzungslevels fĂŒr OpenAPI haben.

Einige davon könnten noch nicht alle zusÀtzlichen Informationen anzuzeigen, die Sie erklÀrten, obwohl in den meisten FÀllen die fehlende FunktionalitÀt bereits in der Entwicklung geplant ist.

Sie können einen title hinzufĂŒgen:

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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Und eine 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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Alias-Parameter

Stellen Sie sich vor, Sie möchten, dass der Parameter item-query ist.

Wie in:

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

Aber item-query ist kein gĂŒltiger Name fĂŒr eine Variable in Python.

Der am Àhnlichsten wÀre item_query.

Aber Sie benötigen dennoch, dass er genau item-query ist ...

Dann können Sie ein alias deklarieren, und dieser Alias wird verwendet, um den Parameterwert zu finden:

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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Parameter als deprecatet ausweisen

Nehmen wir an, Ihnen gefÀllt dieser Parameter nicht mehr.

Sie mĂŒssen ihn eine Weile dort belassen, da es Clients gibt, die ihn verwenden, aber Sie möchten, dass die Dokumentation ihn klar als deprecatet anzeigt.

Dann ĂŒbergeben Sie den Parameter deprecated=True an 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
đŸ€“ Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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

Die Dokumentation wird es so anzeigen:

Parameter von OpenAPI ausschließen

Um einen Query-Parameter aus dem generierten OpenAPI-Schema auszuschließen (und somit aus den automatischen Dokumentationssystemen), setzen Sie den Parameter include_in_schema von Query auf 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"}
đŸ€“ Other versions and variants
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"}

Tip

Prefer to use the Annotated version if possible.

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"}

Tip

Prefer to use the Annotated version if possible.

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"}

Benutzerdefinierte Validierung

Es kann FĂ€lle geben, in denen Sie eine benutzerdefinierte Validierung durchfĂŒhren mĂŒssen, die nicht mit den oben gezeigten Parametern durchgefĂŒhrt werden kann.

In diesen FÀllen können Sie eine benutzerdefinierte Validierungsfunktion verwenden, die nach der normalen Validierung angewendet wird (z. B. nach der Validierung, dass der Wert ein str ist).

Sie können dies mit Pydantic's AfterValidator innerhalb von Annotated erreichen.

Tipp

Pydantic unterstĂŒtzt auch BeforeValidator und andere. đŸ€“

Zum Beispiel ĂŒberprĂŒft dieser benutzerdefinierte Validator, ob die Artikel-ID mit isbn- fĂŒr eine ISBN-Buchnummer oder mit imdb- fĂŒr eine IMDB-Film-URL-ID beginnt:

import random
from typing import Annotated

from fastapi import FastAPI
from pydantic import AfterValidator

app = FastAPI()

data = {
    "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
    "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
    "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
}


def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id


@app.get("/items/")
async def read_items(
    id: Annotated[str | None, AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}
đŸ€“ Other versions and variants
import random
from typing import Annotated, Union

from fastapi import FastAPI
from pydantic import AfterValidator

app = FastAPI()

data = {
    "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
    "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
    "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
}


def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id


@app.get("/items/")
async def read_items(
    id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}

Info

Dies ist verfĂŒgbar seit Pydantic Version 2 oder höher. 😎

Tipp

Wenn Sie irgendeine Art von Validierung durchfĂŒhren mĂŒssen, die eine Kommunikation mit einer externen Komponente erfordert, wie z. B. einer Datenbank oder einer anderen API, sollten Sie stattdessen FastAPI-AbhĂ€ngigkeiten verwenden. Sie werden diese spĂ€ter kennenlernen.

Diese benutzerdefinierten Validatoren sind fĂŒr Dinge gedacht, die einfach mit denselben Daten ĂŒberprĂŒft werden können, die im Request bereitgestellt werden.

Dieses Codebeispiel verstehen

Der wichtige Punkt ist einfach die Verwendung von AfterValidator mit einer Funktion innerhalb von Annotated. FĂŒhlen Sie sich frei, diesen Teil zu ĂŒberspringen. đŸ€ž


Aber wenn Sie neugierig auf dieses spezielle Codebeispiel sind und immer noch Spaß haben, hier sind einige zusĂ€tzliche Details.

Zeichenkette mit value.startswith()

Haben Sie bemerkt? Eine Zeichenkette mit value.startswith() kann ein Tuple ĂŒbernehmen, und es wird jeden Wert im Tuple ĂŒberprĂŒfen:

# Code above omitted 👆

def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id

# Code below omitted 👇
👀 Full file preview
import random
from typing import Annotated

from fastapi import FastAPI
from pydantic import AfterValidator

app = FastAPI()

data = {
    "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
    "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
    "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
}


def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id


@app.get("/items/")
async def read_items(
    id: Annotated[str | None, AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}
đŸ€“ Other versions and variants
import random
from typing import Annotated, Union

from fastapi import FastAPI
from pydantic import AfterValidator

app = FastAPI()

data = {
    "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
    "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
    "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
}


def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id


@app.get("/items/")
async def read_items(
    id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}

Ein zufÀlliges Item

Mit data.items() erhalten wir ein iterierbares Objekt mit Tupeln, die SchlĂŒssel und Wert fĂŒr jedes Dictionary-Element enthalten.

Wir konvertieren dieses iterierbare Objekt mit list(data.items()) in eine richtige list.

Dann können wir mit random.choice() einen zufÀlligen Wert aus der Liste erhalten, also bekommen wir ein Tuple mit (id, name). Es wird etwas wie ("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy") sein.

Dann weisen wir diese beiden Werte des Tupels den Variablen id und name zu.

Wenn der Benutzer also keine Artikel-ID bereitgestellt hat, erhÀlt er trotzdem einen zufÀlligen Vorschlag.

... wir tun all dies in einer einzelnen einfachen Zeile. đŸ€Ż Lieben Sie nicht auch Python? 🐍

# Code above omitted 👆

@app.get("/items/")
async def read_items(
    id: Annotated[str | None, AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}
👀 Full file preview
import random
from typing import Annotated

from fastapi import FastAPI
from pydantic import AfterValidator

app = FastAPI()

data = {
    "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
    "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
    "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
}


def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id


@app.get("/items/")
async def read_items(
    id: Annotated[str | None, AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}
đŸ€“ Other versions and variants
import random
from typing import Annotated, Union

from fastapi import FastAPI
from pydantic import AfterValidator

app = FastAPI()

data = {
    "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
    "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
    "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
}


def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
    return id


@app.get("/items/")
async def read_items(
    id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None,
):
    if id:
        item = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}

Zusammenfassung

Sie können zusĂ€tzliche Validierungen und Metadaten fĂŒr Ihre Parameter deklarieren.

Allgemeine Validierungen und Metadaten:

  • alias
  • title
  • description
  • deprecated

Validierungen, die spezifisch fĂŒr Strings sind:

  • min_length
  • max_length
  • pattern

Benutzerdefinierte Validierungen mit AfterValidator.

In diesen Beispielen haben Sie gesehen, wie Sie Validierungen fĂŒr str-Werte deklarieren.

Sehen Sie sich die nĂ€chsten Kapitel an, um zu erfahren, wie Sie Validierungen fĂŒr andere Typen, wie z. B. Zahlen, deklarieren.