Benutzerdefinierte Response – HTML, Stream, Datei, andere¶
Standardmäßig gibt FastAPI die Responses mittels JSONResponse
zurück.
Sie können das überschreiben, indem Sie direkt eine Response
zurückgeben, wie in Eine Response direkt zurückgeben gezeigt.
Wenn Sie jedoch direkt eine Response
zurückgeben, werden die Daten nicht automatisch konvertiert und die Dokumentation wird nicht automatisch generiert (zum Beispiel wird der spezifische „Medientyp“, der im HTTP-Header Content-Type
angegeben ist, nicht Teil der generierten OpenAPI).
Sie können aber auch die Response
, die Sie verwenden möchten, im Pfadoperation-Dekorator deklarieren.
Der Inhalt, den Sie von Ihrer Pfadoperation-Funktion zurückgeben, wird in diese Response
eingefügt.
Und wenn diese Response
einen JSON-Medientyp (application/json
) hat, wie es bei JSONResponse
und UJSONResponse
der Fall ist, werden die von Ihnen zurückgegebenen Daten automatisch mit jedem Pydantic response_model
konvertiert (und gefiltert), das Sie im Pfadoperation-Dekorator deklariert haben.
Hinweis
Wenn Sie eine Response-Klasse ohne Medientyp verwenden, erwartet FastAPI, dass Ihre Response keinen Inhalt hat, und dokumentiert daher das Format der Response nicht in deren generierter OpenAPI-Dokumentation.
ORJSONResponse
verwenden¶
Um beispielsweise noch etwas Leistung herauszuholen, können Sie orjson
installieren und verwenden, und die Response als ORJSONResponse
deklarieren.
Importieren Sie die Response
-Klasse (-Unterklasse), die Sie verwenden möchten, und deklarieren Sie sie im Pfadoperation-Dekorator.
Bei umfangreichen Responses ist die direkte Rückgabe einer Response
viel schneller als ein Dictionary zurückzugeben.
Das liegt daran, dass FastAPI standardmäßig jedes enthaltene Element überprüft und sicherstellt, dass es als JSON serialisierbar ist, und zwar unter Verwendung desselben JSON-kompatiblen Encoders, der im Tutorial erläutert wurde. Dadurch können Sie beliebige Objekte zurückgeben, zum Beispiel Datenbankmodelle.
Wenn Sie jedoch sicher sind, dass der von Ihnen zurückgegebene Inhalt mit JSON serialisierbar ist, können Sie ihn direkt an die Response-Klasse übergeben und die zusätzliche Arbeit vermeiden, die FastAPI hätte, indem es Ihren zurückgegebenen Inhalt durch den jsonable_encoder
leitet, bevor es ihn an die Response-Klasse übergibt.
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI()
@app.get("/items/", response_class=ORJSONResponse)
async def read_items():
return ORJSONResponse([{"item_id": "Foo"}])
Info
Der Parameter response_class
wird auch verwendet, um den „Medientyp“ der Response zu definieren.
In diesem Fall wird der HTTP-Header Content-Type
auf application/json
gesetzt.
Und er wird als solcher in OpenAPI dokumentiert.
Tipp
Die ORJSONResponse
ist derzeit nur in FastAPI verfügbar, nicht in Starlette.
HTML-Response¶
Um eine Response mit HTML direkt von FastAPI zurückzugeben, verwenden Sie HTMLResponse
.
- Importieren Sie
HTMLResponse
. - Übergeben Sie
HTMLResponse
als den Parameterresponse_class
Ihres Pfadoperation-Dekorators.
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
Info
Der Parameter response_class
wird auch verwendet, um den „Medientyp“ der Response zu definieren.
In diesem Fall wird der HTTP-Header Content-Type
auf text/html
gesetzt.
Und er wird als solcher in OpenAPI dokumentiert.
Eine Response
zurückgeben¶
Wie in Eine Response direkt zurückgeben gezeigt, können Sie die Response auch direkt in Ihrer Pfadoperation überschreiben, indem Sie diese zurückgeben.
Das gleiche Beispiel von oben, das eine HTMLResponse
zurückgibt, könnte so aussehen:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/items/")
async def read_items():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
Achtung
Eine Response
, die direkt von Ihrer Pfadoperation-Funktion zurückgegeben wird, wird in OpenAPI nicht dokumentiert (zum Beispiel wird der Content-Type
nicht dokumentiert) und ist in der automatischen interaktiven Dokumentation nicht sichtbar.
Info
Natürlich stammen der eigentliche Content-Type
-Header, der Statuscode, usw., aus dem Response
-Objekt, das Sie zurückgegeben haben.
In OpenAPI dokumentieren und Response
überschreiben¶
Wenn Sie die Response innerhalb der Funktion überschreiben und gleichzeitig den „Medientyp“ in OpenAPI dokumentieren möchten, können Sie den response_class
-Parameter verwenden UND ein Response
-Objekt zurückgeben.
Die response_class
wird dann nur zur Dokumentation der OpenAPI-Pfadoperation* verwendet, Ihre Response
wird jedoch unverändert verwendet.
Eine HTMLResponse
direkt zurückgeben¶
Es könnte zum Beispiel so etwas sein:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
def generate_html_response():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return generate_html_response()
In diesem Beispiel generiert die Funktion generate_html_response()
bereits eine Response
und gibt sie zurück, anstatt das HTML in einem str
zurückzugeben.
Indem Sie das Ergebnis des Aufrufs von generate_html_response()
zurückgeben, geben Sie bereits eine Response
zurück, die das Standardverhalten von FastAPI überschreibt.
Aber da Sie die HTMLResponse
auch in der response_class
übergeben haben, weiß FastAPI, dass sie in OpenAPI und der interaktiven Dokumentation als HTML mit text/html
zu dokumentieren ist:
Verfügbare Responses¶
Hier sind einige der verfügbaren Responses.
Bedenken Sie, dass Sie Response
verwenden können, um alles andere zurückzugeben, oder sogar eine benutzerdefinierte Unterklasse zu erstellen.
Technische Details
Sie können auch from starlette.responses import HTMLResponse
verwenden.
FastAPI bietet dieselben starlette.responses
auch via fastapi.responses
an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette.
Response
¶
Die Hauptklasse Response
, alle anderen Responses erben von ihr.
Sie können sie direkt zurückgeben.
Sie akzeptiert die folgenden Parameter:
content
– Einstr
oderbytes
.status_code
– Einint
-HTTP-Statuscode.headers
– Eindict
von Strings.media_type
– Einstr
, der den Medientyp angibt. Z. B."text/html"
.
FastAPI (eigentlich Starlette) fügt automatisch einen Content-Length-Header ein. Außerdem wird es einen Content-Type-Header einfügen, der auf dem media_type basiert, und für Texttypen einen Zeichensatz (charset) anfügen.
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/legacy/")
def get_legacy_data():
data = """<?xml version="1.0"?>
<shampoo>
<Header>
Apply shampoo here.
</Header>
<Body>
You'll have to use soap here.
</Body>
</shampoo>
"""
return Response(content=data, media_type="application/xml")
HTMLResponse
¶
Nimmt Text oder Bytes entgegen und gibt eine HTML-Response zurück, wie Sie oben gelesen haben.
PlainTextResponse
¶
Nimmt Text oder Bytes entgegen und gibt eine Plain-Text-Response zurück.
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get("/", response_class=PlainTextResponse)
async def main():
return "Hello World"
JSONResponse
¶
Nimmt einige Daten entgegen und gibt eine application/json
-codierte Response zurück.
Dies ist die Standard-Response, die in FastAPI verwendet wird, wie Sie oben gelesen haben.
ORJSONResponse
¶
Eine schnelle alternative JSON-Response mit orjson
, wie Sie oben gelesen haben.
UJSONResponse
¶
Eine alternative JSON-Response mit ujson
.
Achtung
ujson
ist bei der Behandlung einiger Sonderfälle weniger sorgfältig als Pythons eingebaute Implementierung.
from fastapi import FastAPI
from fastapi.responses import UJSONResponse
app = FastAPI()
@app.get("/items/", response_class=UJSONResponse)
async def read_items():
return [{"item_id": "Foo"}]
Tipp
Möglicherweise ist ORJSONResponse
eine schnellere Alternative.
RedirectResponse
¶
Gibt eine HTTP-Weiterleitung (HTTP-Redirect) zurück. Verwendet standardmäßig den Statuscode 307 – Temporäre Weiterleitung (Temporary Redirect).
Sie können eine RedirectResponse
direkt zurückgeben:
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/typer")
async def redirect_typer():
return RedirectResponse("https://typer.tiangolo.com")
Oder Sie können sie im Parameter response_class
verwenden:
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/fastapi", response_class=RedirectResponse)
async def redirect_fastapi():
return "https://fastapi.tiangolo.com"
Wenn Sie das tun, können Sie die URL direkt von Ihrer Pfadoperation-Funktion zurückgeben.
In diesem Fall ist der verwendete status_code
der Standardcode für die RedirectResponse
, also 307
.
Sie können den Parameter status_code
auch in Kombination mit dem Parameter response_class
verwenden:
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/pydantic", response_class=RedirectResponse, status_code=302)
async def redirect_pydantic():
return "https://pydantic-docs.helpmanual.io/"
StreamingResponse
¶
Nimmt einen asynchronen Generator oder einen normalen Generator/Iterator und streamt den Responsebody.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def fake_video_streamer():
for i in range(10):
yield b"some fake video bytes"
@app.get("/")
async def main():
return StreamingResponse(fake_video_streamer())
Verwendung von StreamingResponse
mit dateiähnlichen Objekten¶
Wenn Sie ein dateiähnliches (file-like) Objekt haben (z. B. das von open()
zurückgegebene Objekt), können Sie eine Generatorfunktion erstellen, um über dieses dateiähnliche Objekt zu iterieren.
Auf diese Weise müssen Sie nicht alles zuerst in den Arbeitsspeicher lesen und können diese Generatorfunktion an StreamingResponse
übergeben und zurückgeben.
Das umfasst viele Bibliotheken zur Interaktion mit Cloud-Speicher, Videoverarbeitung und anderen.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
def main():
def iterfile(): # (1)
with open(some_file_path, mode="rb") as file_like: # (2)
yield from file_like # (3)
return StreamingResponse(iterfile(), media_type="video/mp4")
- Das ist die Generatorfunktion. Es handelt sich um eine „Generatorfunktion“, da sie
yield
-Anweisungen enthält. - Durch die Verwendung eines
with
-Blocks stellen wir sicher, dass das dateiähnliche Objekt geschlossen wird, nachdem die Generatorfunktion fertig ist. Also, nachdem sie mit dem Senden der Response fertig ist. -
Dieses
yield from
weist die Funktion an, über das Ding namensfile_like
zu iterieren. Und dann für jeden iterierten Teil, diesen Teil so zurückzugeben, als wenn er aus dieser Generatorfunktion (iterfile
) stammen würde.Es handelt sich also hier um eine Generatorfunktion, die die „generierende“ Arbeit intern auf etwas anderes überträgt.
Auf diese Weise können wir das Ganze in einen
with
-Block einfügen und so sicherstellen, dass das dateiartige Objekt nach Abschluss geschlossen wird.
Tipp
Beachten Sie, dass wir, da wir Standard-open()
verwenden, welches async
und await
nicht unterstützt, hier die Pfadoperation mit normalen def
deklarieren.
FileResponse
¶
Streamt eine Datei asynchron als Response.
Nimmt zur Instanziierung einen anderen Satz von Argumenten entgegen als die anderen Response-Typen:
path
– Der Dateipfad zur Datei, die gestreamt werden soll.headers
– Alle benutzerdefinierten Header, die inkludiert werden sollen, als Dictionary.media_type
– Ein String, der den Medientyp angibt. Wenn nicht gesetzt, wird der Dateiname oder Pfad verwendet, um auf einen Medientyp zu schließen.filename
– Wenn gesetzt, wird das in derContent-Disposition
der Response eingefügt.
Datei-Responses enthalten die entsprechenden Content-Length
-, Last-Modified
- und ETag
-Header.
from fastapi import FastAPI
from fastapi.responses import FileResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
async def main():
return FileResponse(some_file_path)
Sie können auch den Parameter response_class
verwenden:
from fastapi import FastAPI
from fastapi.responses import FileResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/", response_class=FileResponse)
async def main():
return some_file_path
In diesem Fall können Sie den Dateipfad direkt von Ihrer Pfadoperation-Funktion zurückgeben.
Benutzerdefinierte Response-Klasse¶
Sie können Ihre eigene benutzerdefinierte Response-Klasse erstellen, die von Response
erbt und diese verwendet.
Nehmen wir zum Beispiel an, dass Sie orjson
verwenden möchten, aber mit einigen benutzerdefinierten Einstellungen, die in der enthaltenen ORJSONResponse
-Klasse nicht verwendet werden.
Sie möchten etwa, dass Ihre Response eingerücktes und formatiertes JSON zurückgibt. Dafür möchten Sie die orjson-Option orjson.OPT_INDENT_2
verwenden.
Sie könnten eine CustomORJSONResponse
erstellen. Das Wichtigste, was Sie tun müssen, ist, eine Response.render(content)
-Methode zu erstellen, die den Inhalt als bytes
zurückgibt:
from typing import Any
import orjson
from fastapi import FastAPI, Response
app = FastAPI()
class CustomORJSONResponse(Response):
media_type = "application/json"
def render(self, content: Any) -> bytes:
assert orjson is not None, "orjson must be installed"
return orjson.dumps(content, option=orjson.OPT_INDENT_2)
@app.get("/", response_class=CustomORJSONResponse)
async def main():
return {"message": "Hello World"}
Statt:
{"message": "Hello World"}
... wird die Response jetzt Folgendes zurückgeben:
{
"message": "Hello World"
}
Natürlich werden Sie wahrscheinlich viel bessere Möglichkeiten finden, Vorteil daraus zu ziehen, als JSON zu formatieren. 😉
Standard-Response-Klasse¶
Beim Erstellen einer FastAPI-Klasseninstanz oder eines APIRouter
s können Sie angeben, welche Response-Klasse standardmäßig verwendet werden soll.
Der Parameter, der das definiert, ist default_response_class
.
Im folgenden Beispiel verwendet FastAPI standardmäßig ORJSONResponse
in allen Pfadoperationen, anstelle von JSONResponse
.
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI(default_response_class=ORJSONResponse)
@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
Tipp
Sie können dennoch weiterhin response_class
in Pfadoperationen überschreiben, wie bisher.
Zusätzliche Dokumentation¶
Sie können auch den Medientyp und viele andere Details in OpenAPI mit responses
deklarieren: Zusätzliche Responses in OpenAPI.