Python Framework

FastAPI

FastAPI ist das async Python-Framework, das auf Type Hints aufbaut. Pydantic validiert Ihre Daten, Starlette übernimmt das HTTP und die OpenAPI-Dokumentation schreibt sich von selbst.

intermediate15 min readUpdated 16. Sept. 2026
main.py
python
# main.py
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    price: float


@app.post("/items", status_code=201)
async def create_item(item: Item) -> Item:
    return item
Veröffentlicht
2018
Sprache
Python
Basiert auf
Starlette + Pydantic
Kernidee
Type Hints als Vertrag
Dokumentation
OpenAPI und Swagger UI
Aktuelle Version
0.11x

Warum es wichtig ist

Warum FastAPI wie Magie wirkt (aber keine ist)

Types sind die API

Deklarieren Sie einen Parameter oder ein Modell mit Type Hints und FastAPI validiert Requests, serialisiert Responses und dokumentiert den Endpunkt aus derselben Deklaration.

Async, wenn benötigt

Aufgebaut auf dem ASGI-Toolkit von Starlette, sodass async Endpunkte gleichzeitige I/O-Operationen verarbeiten, ohne den Event Loop zu blockieren.

Dokumentation inklusive

Jeder Endpunkt erscheint in der interaktiven Swagger UI und in ReDoc, generiert aus dem OpenAPI-Schema, das FastAPI beim Start erstellt.

Das Gesamtbild

Types, Pydantic, Dependencies

Type Hints beschreiben den Vertrag, Pydantic erzwingt ihn und Dependencies injizieren die gemeinsamen Komponenten, die ein Request benötigt.

Type hints

Beschreiben

Die Annotation von Parametern teilt FastAPI mit, woher ein Wert kommt und welche Form er hat, sodass die Validierung erfolgt, bevor Ihre Funktion ausgeführt wird.

Pydantic models

Validieren

BaseModel-Klassen parsen, konvertieren und lehnen Daten ab; sie dienen gleichzeitig als Response-Vertrag und als generiertes Schema.

Dependencies

Injizieren

Depends() setzt gemeinsame Logik wie Sessions, Auth und Einstellungen zusammen, löst den Graphen pro Request auf und verwendet gecachte Ergebnisse wieder.

HTML5 auf einen Blick

Die FastAPI-Toolbox

Path operations

@app.get und @app.post binden eine URL an eine Funktion, mit typisierten Path- und Query-Parametern.

Pydantic models

BaseModel-Klassen validieren Request-Bodies und formen die Responses.

Automatische Dokumentation

Swagger UI unter /docs und ReDoc unter /redoc, generiert direkt aus Ihrem Code.

Dependencies

Depends() injiziert Sessions, Benutzer, Pagination und Konfigurationen.

Async-Support

async def Endpunkte laufen auf ASGI und erwarten I/O-Operationen gleichzeitig.

Background tasks

Führen Sie Aufgaben nach dem Senden der Response aus, ohne eine Queue hinzufügen zu müssen.

Der vollständige Leitfaden

FastAPI: Alles was Sie wissen müssen

Was ist FastAPI?

FastAPI ist ein modernes Python-Web-Framework zum Erstellen von APIs. Die Kernidee ist, dass Ihre Type Hints den Vertrag bilden. Deklarieren Sie einen Parameter als int, einen Body als Pydantic-Modell oder einen Rückgabetyp als ItemOut, und das Framework validiert die Anfrage, serialisiert die Antwort und schreibt die Dokumentation – alles basierend auf dieser einen Deklaration.

Es basiert auf zwei Bibliotheken, deren Namen Sie kennen sollten. Starlette stellt das ASGI-Toolkit bereit: Routing, middleware und den Request/Response-Zyklus. Pydantic übernimmt die Validierung und Serialisierung. FastAPI ist die Schicht, die beides kombiniert, Dependency Injection hinzufügt und beim Start ein OpenAPI-Schema generiert.

Das Ergebnis ist, dass eine kleine, lesbare Funktion Ihnen einen validierten Endpunkt mit interaktiver Dokumentation liefert. Die Magie ist echt, aber sie ist mechanisch – und genau darum geht es in diesem Guide: die Mechanik dahinter zu verstehen.

Path-Operationen

Eine Path-Operation ist eine Funktion, die an eine HTTP-Methode und eine URL gebunden ist. Der Decorator benennt die Methode, und die Funktionssignatur teilt FastAPI mit, was zu erwarten ist.

# main.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello, world"}


@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}

Das Segment {item_id} ist ein Path-Parameter, und die Annotation int bedeutet, dass FastAPI den String automatisch konvertiert und bei einem Fehler einen 422-Statuscode zurückgibt. Alles, was nicht im Pfad enthalten ist, wird als Query-Parameter behandelt, wobei ein Standardwert von None ihn optional macht. Es ist kein manuelles Parsing und kein request.args erforderlich.

Gruppieren Sie zusammengehörige Operationen mit einem APIRouter, der ein Präfix und Tags für die Dokumentation enthalten kann.

from fastapi import APIRouter

router = APIRouter(prefix="/items", tags=["items"])


@router.get("")
async def list_items():
    return []


@router.post("", status_code=201)
async def create_item():
    return {}

Binden Sie den Router anschließend in die App ein: app.include_router(router). Auf diese Weise bleibt ein FastAPI-Projekt modular.

Pydantic-Models

Ein Pydantic-Model ist eine Klasse, die von BaseModel erbt. Es parst den Input, erzwingt kompatible Typen, wendet Constraints an und wirft einen präzisen Validierungsfehler, wenn etwas nicht stimmt.

# app/schemas.py
from datetime import datetime

from pydantic import BaseModel, Field


class ItemBase(BaseModel):
    name: str = Field(min_length=1, max_length=120)
    price: float = Field(gt=0)
    tags: list[str] = []


class ItemCreate(ItemBase):
    pass


class ItemOut(ItemBase):
    id: int
    created_at: datetime

    model_config = {"from_attributes": True}

Field fügt Constraints und Metadaten hinzu. model_config = {"from_attributes": True} ermöglicht es Pydantic, Attribute aus einem ORM-Objekt zu lesen, sodass Sie eine Datenbankzeile direkt zurückgeben und serialisieren lassen können. Die Trennung von ItemCreate und ItemOut ist beabsichtigt: Das Input-Model hat keine id, und das Output-Model kann Felder exponieren, die der Client nicht setzen darf.

Verwenden Sie ein Pydantic-Model als Body-Typ, und FastAPI parst, validiert und überreicht Ihnen ein typisiertes Objekt.

@app.post("/items", response_model=ItemOut, status_code=201)
async def create_item(item: ItemCreate):
    return await repo.create(item)

Wenn der Body ungültig ist, gibt FastAPI einen 422-Fehler mit einer Liste der exakten Felder zurück, die die Validierung nicht bestanden haben. Sie mussten dafür keine einzige Zeile Validierungslogik schreiben.

Request-Bodies und Validierung

FastAPI unterscheidet die Datenquellen anhand von Position und Typ:

  • Path-Parameter kommen aus der URL.
  • Query-Parameter sind alles andere in der Signatur.
  • Ein Pydantic-Modell stellt den Request-Body dar.
  • Header, Cookie, Form und File markieren diese speziellen Inputs.
from fastapi import Header, Query


@app.get("/search")
async def search(
    q: str = Query(min_length=1, max_length=50),
    limit: int = Query(default=20, ge=1, le=100),
    user_agent: str | None = Header(default=None),
):
    return {"q": q, "limit": limit, "user_agent": user_agent}

Constraints für Query-Parameter werden auf die gleiche Weise erzwungen wie bei Modellen, und die generierte Dokumentation zeigt die entsprechenden Limits an. Diese Konsistenz ist der Grund, warum FastAPI-Code so kompakt geschrieben ist.

Automatische Dokumentation

Da das Schema direkt aus dem Code generiert wird, ist die Dokumentation niemals veraltet. Starte die App und öffne /docs für das Swagger UI, wo du Endpunkte direkt aufrufen kannst, oder /redoc für eine übersichtlichere Referenz.

app = FastAPI(
    title="Inventory API",
    version="1.0.0",
    description="Items, stock levels and orders.",
)

Du kannst Zusammenfassungen, Beschreibungen und Beispiele zu Path Operations und Feldern hinzufügen, die dann automatisch in der Dokumentation erscheinen. Für Frontend-Teams kann dasselbe Schema typisierte Clients generieren, sodass die API und ihre Konsumenten synchron bleiben. Das ist der große Vorteil dabei, Typen als Vertrag (Contract) zu betrachten.

Abhängigkeiten

Eine Dependency ist eine Funktion, die FastAPI vor deinem Endpoint aufruft und deren Rückgabewert injiziert wird. Depends() ist der zugrunde liegende Mechanismus, und er ist komponierbar.

from fastapi import Depends, HTTPException


async def get_session() -> AsyncSession:
    async with SessionLocal() as session:
        yield session


async def get_current_user(
    token: str = Depends(get_token),
    session: AsyncSession = Depends(get_session),
) -> User:
    user = await authenticate(session, token)
    if user is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    return user
@app.get("/me", response_model=UserOut)
async def read_me(user: User = Depends(get_current_user)):
    return user

Dependencies können synchron oder asynchron sein, können yield nutzen, um nach der Antwort ein Cleanup durchzuführen, und werden innerhalb eines Requests gecacht, sodass get_session nur einmal aufgerufen wird, selbst wenn mehrere Dependencies darauf zugreifen. Sie sind der idiomatische Ort für Datenbank-Sessions, Authentifizierung, Pagination und Feature-Flags.

Async versus sync

FastAPI unterstützt sowohl def als auch async def Endpunkte, und die Wahl hat einen entscheidenden Einfluss.

  • Ein async def Endpunkt wird auf dem Event Loop ausgeführt. Jeder I/O-Aufruf darin muss über eine async-Library mit await aufgerufen werden, andernfalls wird der Loop für alle anderen Anfragen blockiert.
  • Ein einfacher def Endpunkt wird in einem Thread Pool ausgeführt. Blockierende Aufrufe sind hier also sicher, allerdings belegt jede Anfrage einen eigenen Thread.
# Async: use an async driver and await it
@app.get("/items")
async def list_items(session: AsyncSession = Depends(get_session)):
    result = await session.execute(select(Item))
    return result.scalars().all()


# Sync: blocking code is fine; FastAPI offloads it
@app.get("/report")
def build_report():
    return generate_report()  # CPU or blocking I/O

Die Regel ist simpel: Entweder konsequent async oder konsequent sync. Das Mischen von blockierenden Aufrufen in einem async def Endpunkt ist der häufigste Performance-Bug in FastAPI – und er bleibt unsichtbar, bis die ersten Nutzer auf die Seite kommen.

Fehler und Statuscodes

Werfen Sie HTTPException, um einen Fehler mit einem Statuscode und JSON-Details zurückzugeben. FastAPI wandelt dies in eine Antwort um und dokumentiert den Statuscode.

from fastapi import HTTPException, status


@app.get("/items/{item_id}", response_model=ItemOut)
async def read_item(item_id: int):
    item = await repo.get(item_id)
    if item is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Item not found",
        )
    return item

Um eine konsistente Fehlerstruktur über die gesamte API hinweg zu gewährleisten, sollten Sie Exception-Handler registrieren, die Framework- und Domain-Fehler in ein einheitliches Format (Envelope) überführen. Halten Sie das Feld detail stabil, da die Clients dieses parsen werden.

Hintergrundaufgaben

BackgroundTasks führt Aufgaben im selben Prozess aus, nachdem die Antwort gesendet wurde. Dies ist die leichtgewichtige Option, um beispielsweise eine E-Mail zu versenden oder einen Audit-Eintrag zu schreiben.

from fastapi import BackgroundTasks


def send_receipt(email: str) -> None:
    ...


@app.post("/orders", status_code=201)
async def create_order(
    order: OrderCreate,
    tasks: BackgroundTasks,
):
    saved = await repo.create(order)
    tasks.add_task(send_receipt, saved.email)
    return saved

Hintergrundaufgaben sind keine Job-Queue. Sie laufen im selben Prozess (in-process), weshalb sie bei einem Neustart des Workers verloren gehen und mit der Verarbeitung von Anfragen konkurrieren. Für alles, was dauerhaft (durable) sein muss, nutzen Sie stattdessen Celery, RQ oder eine managed Queue.

Datenbanken

FastAPI besitzt keinen eigenen Datenbank-Layer, daher müssen Sie diesen selbst wählen. Die gängigsten Optionen sind SQLAlchemy mit einer async engine oder SQLModel, welches SQLAlchemy mit Pydantic kombiniert. Das Dependency-Pattern stellt die Session bereit und schließt diese nach dem Request wieder.

# app/db.py
from collections.abc import AsyncIterator

from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine

engine = create_async_engine(settings.database_url, pool_pre_ping=True)
SessionLocal = async_sessionmaker(engine, expire_on_commit=False)


async def get_session() -> AsyncIterator[AsyncSession]:
    async with SessionLocal() as session:
        yield session
@router.post("", response_model=ItemOut, status_code=201)
async def create_item(
    payload: ItemCreate,
    session: AsyncSession = Depends(get_session),
):
    item = Item(**payload.model_dump())
    session.add(item)
    await session.commit()
    await session.refresh(item)
    return item

Verwenden Sie expire_on_commit=False, damit Objekte nach dem Commit nutzbar bleiben, und halten Sie Transaktionen innerhalb des Requests. Wenn Sie einen synchronen Treiber bevorzugen, nutzen Sie einfache def Endpunkte, damit FastAPI diese in den Thread-Pool auslagern kann.

Sicherheit

FastAPI liefert die Bausteine für OAuth2 und JWT, ohne ein vollständiges Authentifizierungssystem vorzuschreiben. OAuth2PasswordBearer extrahiert den Token, und python-jose oder pyjwt verifiziert ihn.

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


@app.get("/users/me", response_model=UserOut)
async def read_me(
    token: str = Depends(oauth2_scheme),
    session: AsyncSession = Depends(get_session),
):
    user = await get_user_from_token(session, token)
    if user is None:
        raise HTTPException(status_code=401, detail="Invalid token")
    return user

Speichere Passwort-Hashes mit passlib oder argon2-cffi, niemals im Klartext. Führe das Hashen und Verifizieren außerhalb des Endpunkts aus, bewahre Secrets in den Einstellungen auf und implementiere Rate Limiting sowie CORS bewusst. FastAPI stellt dir die Werkzeuge bereit; die Richtlinien musst du selbst definieren.

Konfiguration und Einstellungen

Verwalten Sie die Konfiguration in einem einzigen typisierten Objekt, anstatt Umgebungsvariablen im gesamten Code zu lesen. pydantic-settings validiert die Umgebung beim Start und bietet Ihnen dieselbe Typsicherheit wie Ihre Modelle.

# app/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_")

    database_url: str
    secret_key: str
    access_token_minutes: int = 30


settings = Settings()
from functools import lru_cache

from app.config import Settings


@lru_cache
def get_settings() -> Settings:
    return Settings()
@app.get("/info")
async def info(settings: Settings = Depends(get_settings)):
    return {"token_minutes": settings.access_token_minutes}

Da die Einstellungen wie jede andere Abhängigkeit injiziert werden, können Tests diese mit app.dependency_overrides[get_settings] überschreiben. Fehlende erforderliche Variablen führen bereits beim Start zu einem Fehler und nicht erst bei der ersten Anfrage – genau dann, wenn man es wissen möchte.

Testing

TestClient kapselt die App in einen WSGI-ähnlichen Client und führt echte Anfragen im selben Prozess aus, einschließlich Validierung und Dependency Overrides.

# tests/test_items.py
from fastapi.testclient import TestClient

from app.main import app

client = TestClient(app)


def test_create_item():
    response = client.post("/items", json={"name": "Cup", "price": 9.5})
    assert response.status_code == 201
    assert response.json()["name"] == "Cup"


def test_invalid_price():
    response = client.post("/items", json={"name": "Cup", "price": -1})
    assert response.status_code == 422

Verwenden Sie app.dependency_overrides, um die Datenbank-Session gegen eine Test-Session auszutauschen, und schreiben Sie asynchrone Tests mit httpx.AsyncClient, wenn Sie asynchrone Endpunkte direkt testen müssen. Da Dependencies explizit definiert sind, ist deren Ersetzung in Tests unkompliziert.

Best Practices

  • Deklarieren Sie Request- und Response-Modelle explizit; akzeptieren oder geben Sie niemals einfache Dictionaries zurück.
  • Halten Sie async def-Endpoints vollständig async oder verwenden Sie def, damit FastAPI blockierende Aufgaben auslagert.
  • Platzieren Sie gemeinsam genutzte Logik in Depends()-Dependencies, anstatt sie in jeder Route zu wiederholen.
  • Strukturieren Sie die App mit APIRouter und weisen Sie jedem Router ein Prefix sowie Tags zu.
  • Fügen Sie Constraints mit Field und Query hinzu, anstatt die Validierung manuell durchzuführen.
  • Werfen Sie HTTPException mit dem passenden Statuscode und einem stabilen detail.
  • Überschreiben Sie Dependencies in Tests, anstatt interne Funktionen zu patchen.
  • Speichern Sie Secrets in Settings-Objekten, die aus der Umgebung ausgelesen werden.

Häufige Fehler

  • Aufruf von blockierendem Code innerhalb eines async def-Endpoints, wodurch der Event Loop blockiert wird.
  • Rückgabe von ORM-Objekten ohne response_model, wodurch interne Spalten offengelegt werden.
  • Vergessen von from_attributes = True und anschließendes Rätseln, warum die Serialisierung fehlschlägt.
  • Schreiben eines einzigen riesigen main.py anstelle von Routern und Modulen.
  • Verwendung von BackgroundTasks als dauerhafte Job-Queue.
  • Teilen einer einzigen Session über mehrere Requests oder asynchrone Tasks hinweg.
  • Zweifache Validierung desselben Inputs, weil das Pydantic-Modell ignoriert wurde.
  • Abfangen jeder Exception und Rückgabe eines 200-Status mit einem Error-Body.

Wie geht es weiter?

FastAPI verwandelt Type Hints in eine validierte und dokumentierte API, weshalb es zum Standard für neue Python-Services geworden ist. Um die Vor- und Nachteile abzuwägen, lesen Sie den Flask-Guide für den minimalen synchronen Ansatz und den zu Django für ein vollständiges Framework mit ORM und Admin-Bereich. Vertiefen Sie anschließend Ihr Wissen über API-Kontrakte mit OpenAPI und die Design-Regeln in REST APIs. Stellen Sie zudem sicher, dass Ihre Endpunkte eine Dokumentation wert sind, indem Sie das Ressourcenmodell korrekt aufsetzen.

In der Praxis

Ein Endpunkt, vier Ebenen

Das Modell definiert die Form, die Path Operation stellt sie bereit, Dependencies liefern den Kontext und der Datenbankaufruf erledigt die Arbeit.

app/main.py
from fastapi import FastAPI, HTTPException

from app.schemas import ItemOut

app = FastAPI(title="Inventory API")


@app.get("/items/{item_id}", response_model=ItemOut)
async def read_item(item_id: int):
    item = await db.items.get(item_id)
    if item is None:
        raise HTTPException(status_code=404, detail="Item not found")
    return item

Async und blockierendes I/O

Ein async Endpunkt läuft auf dem Event Loop; ein blockierender Aufruf stoppt daher jeden anderen Request. Verwenden Sie einen async Treiber mit async def oder einen einfachen def Endpunkt, den FastAPI in einem Thread Pool ausführt.

Bevorzugt
@app.get("/items")
async def list_items(session: AsyncSession = Depends(get_session)):
    result = await session.execute(select(Item))
    return result.scalars().all()
Vermeiden
@app.get("/items")
async def list_items():
    # blocks the event loop for the whole query
    return session.query(Item).all()

Response-Formung

Ein response_model filtert die Ausgabe auf die deklarierten Felder und dokumentiert diese, sodass interne Spalten niemals an Clients gelangen.

Bevorzugt
@app.get("/users/{user_id}", response_model=UserOut)
async def get_user(user_id: int):
    return await repo.get(user_id)
Vermeiden
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # returns password_hash and every other column
    return await repo.get(user_id)

Abwägungen

Ist FastAPI der richtige Standard?

FastAPI ist auf typisierte APIs und async Durchsatz optimiert. Das ist exzellent für Services, aber unpraktisch, wenn die App hauptsächlich aus server-gerenderten Seiten besteht.

Strengths

  • Weniger Code, weniger Bugs

    Validierung, Serialisierung und Dokumentation basieren alle auf denselben Type Hints, sodass es kein zweites Schema gibt, das synchron gehalten werden muss.

  • Automatische Dokumentation

    Ein Live-OpenAPI-Schema und interaktive Docs machen die API für Frontend- und Client-Teams vom ersten Tag an explorierbar.

  • Für modernes Python gebaut

    Async Endpunkte, Dependency Injection und Pydantic v2 machen es schnell und angenehm, ohne ein schwerfälliges Framework zu sein.

Trade-offs

  • Async hat Tücken

    Ein einziger blockierender Aufruf innerhalb eines async Endpunkts kann den gesamten Worker aufhalten. Man muss wissen, welche Bibliotheken wirklich async sind.

  • Es ist ein API-Framework

    FastAPI liefert keine Templates, kein Admin-Panel und kein ORM mit. Server-gerenderte Apps benötigen eine weitere Ebene oder ein anderes Framework.

  • Das Ökosystem ist jünger

    Pydantic- und SQLAlchemy-Versionen entwickeln sich schnell und Patterns ändern sich. Rechnen Sie damit, Dependencies aktuell zu halten.

Häufig gestellte Fragen

Häufig gestellte Fragen

Keep learning

Related topics from the roadmap.

$ Lernen Sie jetzt

Bereit, FastAPI zu lernen?

Unser interaktives Tutorial führt Sie Schritt für Schritt durch FastAPI — mit Quizzen und echtem Code, den Sie im Browser ausführen können.