Query-Parameter und Stringvalidierung¶
FastAPI erlaubt es Ihnen, Ihre Parameter zusätzlich zu validieren, und zusätzliche Informationen hinzuzufügen.
Nehmen wir als Beispiel die folgende Anwendung:
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
Der Query-Parameter q
hat den Typ Union[str, None]
(oder str | None
in Python 3.10), was bedeutet, er ist entweder ein str
oder None
. Der Defaultwert ist None
, also weiß FastAPI, der Parameter ist nicht erforderlich.
Hinweis
FastAPI weiß nur dank des definierten Defaultwertes =None
, dass der Wert von q
nicht erforderlich ist
Union[str, None]
hingegen erlaubt ihren Editor, Sie besser zu unterstützen und Fehler zu erkennen.
Zusätzliche Validierung¶
Wir werden bewirken, dass, obwohl q
optional ist, wenn es gegeben ist, seine Länge 50 Zeichen nicht überschreitet.
Query
und Annotated
importieren¶
Importieren Sie zuerst:
Query
vonfastapi
Annotated
vontyping
(oder vontyping_extensions
in Python unter 3.9)
In Python 3.9 oder darüber, ist Annotated
Teil der Standardbibliothek, also können Sie es von typing
importieren.
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
In Versionen unter Python 3.9 importieren Sie Annotated
von typing_extensions
.
Es wird bereits mit FastAPI installiert sein.
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
Info
FastAPI unterstützt (und empfiehlt die Verwendung von) Annotated
seit Version 0.95.0.
Wenn Sie eine ältere Version haben, werden Sie Fehler angezeigt bekommen, wenn Sie versuchen, Annotated
zu verwenden.
Bitte aktualisieren Sie FastAPI daher mindestens zu Version 0.95.1, bevor Sie Annotated
verwenden.
Annotated
im Typ des q
-Parameters verwenden¶
Erinnern Sie sich, wie ich in Einführung in Python-Typen sagte, dass Sie mittels Annotated
Metadaten zu Ihren Parametern hinzufügen können?
Jetzt ist es an der Zeit, das mit FastAPI auszuprobieren. 🚀
Wir hatten diese Typannotation:
q: str | None = None
q: Union[str, None] = None
Wir wrappen das nun in Annotated
, sodass daraus wird:
q: Annotated[str | None] = None
q: Annotated[Union[str, None]] = None
Beide Versionen bedeuten dasselbe: q
ist ein Parameter, der str
oder None
sein kann. Standardmäßig ist er None
.
Wenden wir uns jetzt den spannenden Dingen zu. 🎉
Query
zu Annotated
im q
-Parameter hinzufügen¶
Jetzt, da wir Annotated
für unsere Metadaten deklariert haben, fügen Sie Query
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
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
Beachten Sie, dass der Defaultwert immer noch None
ist, sodass der Parameter immer noch optional ist.
Aber jetzt, mit Query(max_length=50)
innerhalb von Annotated
, sagen wir FastAPI, dass es diesen Wert aus den Query-Parametern extrahieren soll (das hätte es sowieso gemacht 🤷) und dass wir eine zusätzliche Validierung für diesen Wert haben wollen (darum machen wir das, um die zusätzliche Validierung zu bekommen). 😎
FastAPI wird nun:
- Die Daten validieren und sicherstellen, dass sie nicht länger als 50 Zeichen sind
- Dem Client einen verständlichen Fehler anzeigen, wenn die Daten ungültig sind
- Den Parameter in der OpenAPI-Schema-Pfadoperation dokumentieren (sodass er in der automatischen Dokumentation angezeigt wird)
Alternativ (alt): Query
als Defaultwert¶
Frühere Versionen von FastAPI (vor 0.95.0) benötigten Query
als Defaultwert des Parameters, statt es innerhalb von Annotated
unterzubringen. Die Chance ist groß, dass Sie Quellcode sehen, der das immer noch so macht, darum erkläre ich es Ihnen.
Tipp
Verwenden Sie für neuen Code, und wann immer möglich, Annotated
, wie oben erklärt. Es gibt mehrere Vorteile (unten erläutert) und keine Nachteile. 🍰
So würden Sie Query()
als Defaultwert Ihres Funktionsparameters verwenden, den Parameter max_length
auf 50 gesetzt:
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
Da wir in diesem Fall (ohne die Verwendung von Annotated
) den Parameter-Defaultwert None
mit Query()
ersetzen, müssen wir nun dessen Defaultwert mit dem Parameter Query(default=None)
deklarieren. Das dient demselben Zweck, None
als Defaultwert für den Funktionsparameter zu setzen (zumindest für FastAPI).
Sprich:
q: Union[str, None] = Query(default=None)
... macht den Parameter optional, mit dem Defaultwert None
, genauso wie:
q: Union[str, None] = None
Und in Python 3.10 und darüber macht:
q: str | None = Query(default=None)
... den Parameter optional, mit dem Defaultwert None
, genauso wie:
q: str | None = None
Nur, dass die Query
-Versionen den Parameter explizit als Query-Parameter deklarieren.
Info
Bedenken Sie, dass:
= None
oder:
= Query(default=None)
der wichtigste Teil ist, um einen Parameter optional zu machen, da dieses None
der Defaultwert ist, und das ist es, was diesen Parameter nicht erforderlich macht.
Der Teil mit Union[str, None]
erlaubt es Ihrem Editor, Sie besser zu unterstützen, aber er sagt FastAPI nicht, dass dieser Parameter optional ist.
Jetzt können wir Query
weitere Parameter übergeben. Fangen wir mit dem max_length
Parameter an, der auf Strings angewendet wird:
q: Union[str, None] = Query(default=None, max_length=50)
Das wird die Daten validieren, einen verständlichen Fehler ausgeben, wenn die Daten nicht gültig sind, und den Parameter in der OpenAPI-Schema-Pfadoperation dokumentieren.
Query
als Defaultwert oder in Annotated
¶
Bedenken Sie, dass wenn Sie Query
innerhalb von Annotated
benutzen, Sie den default
-Parameter für Query
nicht verwenden dürfen.
Setzen Sie stattdessen den Defaultwert des Funktionsparameters, sonst wäre es inkonsistent.
Zum Beispiel ist das nicht erlaubt:
q: Annotated[str, Query(default="rick")] = "morty"
... denn es wird nicht klar, ob der Defaultwert "rick"
oder "morty"
sein soll.
Sie würden also (bevorzugt) schreiben:
q: Annotated[str, Query()] = "rick"
In älterem Code werden Sie auch finden:
q: str = Query(default="rick")
Vorzüge von Annotated
¶
Es wird empfohlen, Annotated
zu verwenden, statt des Defaultwertes im Funktionsparameter, das ist aus mehreren Gründen besser: 🤓
Der Defaultwert des Funktionsparameters ist der tatsächliche Defaultwert, das spielt generell intuitiver mit Python zusammen. 😌
Sie können die Funktion ohne FastAPI an anderen Stellen aufrufen, und es wird wie erwartet funktionieren. Wenn es einen erforderlichen Parameter gibt (ohne Defaultwert), und Sie führen die Funktion ohne den benötigten Parameter aus, dann wird Ihr Editor Sie das mit einem Fehler wissen lassen, und Python wird sich auch beschweren.
Wenn Sie aber nicht Annotated
benutzen und stattdessen die (alte) Variante mit einem Defaultwert, dann müssen Sie, wenn Sie die Funktion ohne FastAPI an anderen Stellen aufrufen, sich daran erinnern, die Argumente der Funktion zu übergeben, damit es richtig funktioniert. Ansonsten erhalten Sie unerwartete Werte (z. B. QueryInfo
oder etwas Ähnliches, statt str
). Ihr Editor kann ihnen nicht helfen, und Python wird die Funktion ohne Beschwerden ausführen, es sei denn, die Operationen innerhalb lösen einen Fehler aus.
Da Annotated
mehrere Metadaten haben kann, können Sie dieselbe Funktion auch mit anderen Tools verwenden, wie etwa Typer. 🚀
Mehr Validierungen hinzufügen¶
Sie können auch einen Parameter min_length
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
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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 bestimmte reguläre Suchmuster prüft, ob der erhaltene Parameter-Wert:
^
: mit den nachfolgenden Zeichen startet, keine Zeichen davor hat.fixedquery
: den exakten Textfixedquery
hat.$
: danach endet, keine weiteren Zeichen hat alsfixedquery
.
Wenn Sie sich verloren fühlen bei all diesen „Regulärer Ausdruck“-Konzepten, keine Sorge. Reguläre Ausdrücke sind für viele Menschen ein schwieriges Thema. Sie können auch ohne reguläre Ausdrücke eine ganze Menge machen.
Aber wenn Sie sie brauchen und sie lernen, wissen Sie, dass Sie sie bereits direkt in FastAPI verwenden können.
Pydantic v1 regex
statt pattern
¶
Vor Pydantic Version 2 und vor FastAPI Version 0.100.0, war der Name des Parameters regex
statt pattern
, aber das ist jetzt deprecated.
Sie könnten immer noch Code sehen, der den alten Namen verwendet:
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
Beachten Sie aber, dass das deprecated ist, und zum neuen Namen pattern
geändert werden sollte. 🤓
Defaultwerte¶
Sie können natürlich andere Defaultwerte als None
verwenden.
Beispielsweise könnten Sie den q
Query-Parameter so deklarieren, dass er eine min_length
von 3
hat, und den Defaultwert "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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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 Parameter ist optional (nicht erforderlich), wenn er irgendeinen Defaultwert, auch None
, hat.
Erforderliche Parameter¶
Wenn wir keine Validierungen oder Metadaten haben, können wir den q
Query-Parameter erforderlich machen, indem wir einfach keinen Defaultwert deklarieren, wie in:
q: str
statt:
q: Union[str, None] = None
Aber jetzt deklarieren wir den Parameter mit Query
, wie in:
q: Annotated[Union[str, None], Query(min_length=3)] = None
q: Union[str, None] = Query(default=None, min_length=3)
Wenn Sie einen Parameter erforderlich machen wollen, während Sie Query
verwenden, deklarieren Sie ebenfalls 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
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Beachten Sie, dass, obwohl in diesem Fall Query()
der Funktionsparameter-Defaultwert ist, wir nicht default=None
zu Query()
hinzufügen.
Verwenden Sie bitte trotzdem die Annotated
-Version. 😉
Erforderlich mit Ellipse (...
)¶
Es gibt eine Alternative, die explizit deklariert, dass ein Wert erforderlich ist. Sie können als Default das Literal ...
setzen:
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Info
Falls Sie das ...
bisher noch nicht gesehen haben: Es ist ein spezieller einzelner Wert, Teil von Python und wird „Ellipsis“ genannt (Deutsch: Ellipse).
Es wird von Pydantic und FastAPI verwendet, um explizit zu deklarieren, dass ein Wert erforderlich ist.
Dies wird FastAPI wissen lassen, dass dieser Parameter erforderlich ist.
Erforderlich, kann None
sein¶
Sie können deklarieren, dass ein Parameter None
akzeptiert, aber dennoch erforderlich ist. Das zwingt Clients, den Wert zu senden, selbst wenn er None
ist.
Um das zu machen, deklarieren Sie, dass None
ein gültiger Typ ist, aber verwenden Sie dennoch ...
als Default:
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Pydantic, welches die gesamte Datenvalidierung und Serialisierung in FastAPI antreibt, hat ein spezielles Verhalten, wenn Sie Optional
oder Union[Something, None]
ohne Defaultwert verwenden, Sie können mehr darüber in der Pydantic-Dokumentation unter Required fields erfahren.
Tipp
Denken Sie daran, dass Sie in den meisten Fällen, wenn etwas erforderlich ist, einfach den Defaultwert weglassen können. Sie müssen also normalerweise ...
nicht verwenden.
Query-Parameter-Liste / Mehrere Werte¶
Wenn Sie einen Query-Parameter explizit mit Query
auszeichnen, können Sie ihn auch eine Liste von Werten empfangen lassen, oder anders gesagt, mehrere Werte.
Um zum Beispiel einen Query-Parameter q
zu deklarieren, der mehrere Male 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
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Dann, mit einer URL wie:
http://localhost:8000/items/?q=foo&q=bar
bekommen Sie alle q
-Query-Parameter-Werte (foo
und bar
) in einer Python-Liste – list
– in ihrer Pfadoperation-Funktion, im Funktionsparameter q
, überreicht.
Die Response für diese URL wäre also:
{
"q": [
"foo",
"bar"
]
}
Tipp
Um einen Query-Parameter vom Typ list
zu deklarieren, wie im Beispiel oben, müssen Sie explizit Query
verwenden, sonst würde der Parameter als Requestbody interpretiert werden.
Die interaktive API-Dokumentation wird entsprechend aktualisiert und erlaubt jetzt mehrere Werte.
Query-Parameter-Liste / Mehrere Werte mit Defaults¶
Und Sie können auch eine Default-list
e von Werten definieren, wenn keine übergeben 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
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Wenn Sie auf:
http://localhost:8000/items/
gehen, wird der Default für q
verwendet: ["foo", "bar"]
, und als Response erhalten Sie:
{
"q": [
"foo",
"bar"
]
}
list
alleine verwenden¶
Sie können auch list
direkt verwenden, anstelle von List[str]
(oder list[str]
in Python 3.9+):
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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 die Liste Ganzzahlen enthält. list
alleine macht das nicht.
Deklarieren von mehr Metadaten¶
Sie können mehr Informationen zum Parameter hinzufügen.
Diese Informationen werden zur generierten OpenAPI hinzugefügt, und von den Dokumentations-Oberflächen und von externen Tools verwendet.
Hinweis
Beachten Sie, dass verschiedene Tools OpenAPI möglicherweise unterschiedlich gut unterstützen.
Einige könnten noch nicht alle zusätzlichen Informationen anzeigen, die Sie deklariert haben, obwohl in den meisten Fällen geplant ist, das fehlende Feature zu implementieren.
Sie können einen Titel hinzufügen – 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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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 Beschreibung – 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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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, der Parameter soll item-query
sein.
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.
Am ähnlichsten wäre item_query
.
Aber Sie möchten dennoch exakt item-query
verwenden.
Dann können Sie einen alias
deklarieren, und dieser Alias wird verwendet, um den Parameter-Wert 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
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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 deprecated ausweisen¶
Nehmen wir an, Sie mögen diesen Parameter nicht mehr.
Sie müssen ihn eine Weile dort belassen, weil Clients ihn benutzen, aber Sie möchten, dass die Dokumentation klar anzeigt, dass er deprecated ist.
In diesem Fall fügen Sie den Parameter deprecated=True
zu Query
hinzu.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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 das so anzeigen:
Parameter von OpenAPI ausschließen¶
Um einen Query-Parameter vom generierten OpenAPI-Schema auszuschließen (und daher von automatischen Dokumentations-Systemen), setzen Sie den Parameter include_in_schema
in 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"}
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"}
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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"}
Tipp
Bevorzugen Sie die Annotated
-Version, falls möglich.
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"}
Zusammenfassung¶
Sie können zusätzliche Validierungen und Metadaten zu ihren Parametern hinzufügen.
Allgemeine Validierungen und Metadaten:
alias
title
description
deprecated
Validierungen spezifisch für Strings:
min_length
max_length
pattern
In diesen Beispielen haben Sie gesehen, wie Sie Validierungen für Strings hinzufügen.
In den nächsten Kapiteln sehen wir, wie man Validierungen für andere Typen hinzufügt, etwa für Zahlen.