Zum Inhalt

Benutzerdefinierte Response – HTML, Stream, Datei, andere

🌐 Übersetzung durch KI und Menschen

Diese Übersetzung wurde von KI erstellt, angeleitet von Menschen. 🤝

Sie könnte Fehler enthalten, etwa Missverständnisse des ursprünglichen Sinns oder unnatürliche Formulierungen, usw. 🤖

Sie können diese Übersetzung verbessern, indem Sie uns helfen, die KI-LLM besser anzuleiten.

Englische Version

Standardmäßig gibt FastAPI JSON-Responses zurück.

Sie können dies überschreiben, indem Sie direkt eine Response zurückgeben, wie in Eine Response direkt zurückgeben gezeigt.

Wenn Sie jedoch direkt eine Response (oder eine Unterklasse wie JSONResponse) zurückgeben, werden die Daten nicht automatisch konvertiert (selbst wenn Sie ein response_model deklarieren), und die Dokumentation wird nicht automatisch generiert (zum Beispiel einschließlich des spezifischen „Medientyps“ im HTTP-Header Content-Type als Teil der generierten OpenAPI).

Sie können jedoch auch die Response, die Sie verwenden möchten (z. B. jede Response-Unterklasse), im Pfadoperation-Dekorator mit dem response_class-Parameter deklarieren.

Der Inhalt, den Sie von Ihrer Pfadoperation-Funktion zurückgeben, wird in diese Response eingefügt.

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.

JSON-Responses

Standardmäßig gibt FastAPI JSON-Responses zurück.

Wenn Sie ein Responsemodell deklarieren, verwendet FastAPI Pydantic, um die Daten zu JSON zu serialisieren.

Wenn Sie kein Responsemodell deklarieren, verwendet FastAPI den jsonable_encoder, wie in JSON-kompatibler Encoder erklärt, und packt das Ergebnis in eine JSONResponse.

Wenn Sie eine response_class mit einem JSON-Medientyp (application/json) deklarieren, wie es bei JSONResponse der Fall ist, werden die von Ihnen zurückgegebenen Daten automatisch mit jedem Pydantic-response_model (das Sie im Pfadoperation-Dekorator deklariert haben) konvertiert (und gefiltert). Aber die Daten werden nicht mit Pydantic zu JSON-Bytes serialisiert, stattdessen werden sie mit dem jsonable_encoder konvertiert und anschließend an die JSONResponse-Klasse übergeben, die sie dann mit der Standard-JSON-Bibliothek in Python in Bytes serialisiert.

JSON-Leistung

Kurz gesagt: Wenn Sie die maximale Leistung möchten, verwenden Sie ein Responsemodell und deklarieren Sie keine response_class im Pfadoperation-Dekorator.

# Code above omitted 👆

@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item

# Code below omitted 👇
👀 Full file preview
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

HTML-Response

Um eine Response mit HTML direkt von FastAPI zurückzugeben, verwenden Sie HTMLResponse.

  • Importieren Sie HTMLResponse.
  • Übergeben Sie HTMLResponse als den Parameter response_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 – Ein str oder bytes.
  • status_code – Ein int-HTTP-Statuscode.
  • headers – Ein dict von Strings.
  • media_type – Ein str, 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.

Technische Details

Wenn Sie jedoch ein Responsemodell oder einen Rückgabetyp deklarieren, wird dieser direkt verwendet, um die Daten zu JSON zu serialisieren, und eine Response mit dem richtigen Medientyp für JSON wird direkt zurückgegeben, ohne die JSONResponse-Klasse zu verwenden.

Dies ist der ideale Weg, um die beste Leistung zu erzielen.

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://docs.pydantic.dev/"

StreamingResponse

Nimmt einen asynchronen Generator oder einen normalen Generator/Iterator (eine Funktion mit yield) und streamt den Responsebody.

import anyio
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"
        await anyio.sleep(0)


@app.get("/")
async def main():
    return StreamingResponse(fake_video_streamer())

Technische Details

Ein async-Task kann nur abgebrochen werden, wenn er ein await erreicht. Wenn es kein await gibt, kann der Generator (Funktion mit yield) nicht ordnungsgemäß abgebrochen werden und könnte weiterlaufen, selbst nachdem der Abbruch angefordert wurde.

Da dieses kleine Beispiel keine await-Anweisungen benötigt, fügen wir ein await anyio.sleep(0) hinzu, um dem Event Loop die Chance zu geben, den Abbruch zu verarbeiten.

Dies wäre bei großen oder unendlichen Streams noch wichtiger.

Tipp

Anstatt eine StreamingResponse direkt zurückzugeben, sollten Sie wahrscheinlich dem Stil in Daten streamen folgen. Das ist wesentlich bequemer und behandelt den Abbruch im Hintergrund für Sie.

Wenn Sie JSON Lines streamen, folgen Sie dem Tutorial JSON Lines streamen.

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 der Content-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 mit einigen Einstellungen verwenden möchten.

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

Anstatt Folgendes zurückzugeben:

{"message": "Hello World"}

... wird diese Response Folgendes zurückgeben:

{
  "message": "Hello World"
}

Natürlich werden Sie wahrscheinlich viel bessere Möglichkeiten finden, Vorteil daraus zu ziehen, als JSON zu formatieren. 😉

orjson oder Responsemodell

Wenn es Ihnen um Leistung geht, sind Sie wahrscheinlich mit einem Responsemodell besser beraten als mit einer orjson-Response.

Mit einem Responsemodell verwendet FastAPI Pydantic, um die Daten ohne Zwischenschritte zu JSON zu serialisieren, also ohne sie z. B. erst mit jsonable_encoder zu konvertieren, was sonst der Fall wäre.

Und unter der Haube verwendet Pydantic dieselben Rust-Mechanismen wie orjson, um nach JSON zu serialisieren. Sie erhalten mit einem Responsemodell also ohnehin die beste Leistung.

Standard-Response-Klasse

Beim Erstellen einer FastAPI-Klasseninstanz oder eines APIRouters 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 HTMLResponse in allen Pfadoperationen, anstelle von JSON.

from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI(default_response_class=HTMLResponse)


@app.get("/items/")
async def read_items():
    return "<h1>Items</h1><p>This is a list of items.</p>"

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.