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.
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-Pfadoperationdokumentieren (sodass er in der automatischen Dokumentation angezeigt wird)
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:
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:
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.
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. 🚀
Dieses bestimmte reguläre Suchmuster prüft, ob der erhaltene Parameter-Wert:
^: mit den nachfolgenden Zeichen startet, keine Zeichen davor hat.
fixedquery: den exakten Text fixedquery hat.
$: danach endet, keine weiteren Zeichen hat als fixedquery.
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.
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:
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:
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.
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:
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-liste von Werten definieren, wenn keine übergeben werden:
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.
fromtypingimportAnnotatedfromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
fromtypingimportAnnotated,UnionfromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
fromtypingimportUnionfromfastapiimportFastAPI,Queryfromtyping_extensionsimportAnnotatedapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
Tipp
Bevorzugen Sie die Annotated-Version, falls möglich.
fromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
Tipp
Bevorzugen Sie die Annotated-Version, falls möglich.
fromtypingimportUnionfromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
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.
fromtypingimportAnnotatedfromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
fromtypingimportAnnotated,UnionfromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
fromtypingimportUnionfromfastapiimportFastAPI,Queryfromtyping_extensionsimportAnnotatedapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
Tipp
Bevorzugen Sie die Annotated-Version, falls möglich.
fromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
Tipp
Bevorzugen Sie die Annotated-Version, falls möglich.
fromtypingimportUnionfromfastapiimportFastAPI,Queryapp=FastAPI()@app.get("/items/")asyncdefread_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"}]}ifq:results.update({"q":q})returnresults
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.