Zum Inhalt

Größere Anwendungen – mehrere Dateien

Wenn Sie eine Anwendung oder eine Web-API erstellen, ist es selten der Fall, dass Sie alles in einer einzigen Datei unterbringen können.

FastAPI bietet ein praktisches Werkzeug zur Strukturierung Ihrer Anwendung bei gleichzeitiger Wahrung der Flexibilität.

Info

Wenn Sie von Flask kommen, wäre dies das Äquivalent zu Flasks Blueprints.

Eine Beispiel-Dateistruktur

Nehmen wir an, Sie haben eine Dateistruktur wie diese:

.
├── app
│   ├── __init__.py
│   ├── main.py
│   ├── dependencies.py
│   └── routers
│   │   ├── __init__.py
│   │   ├── items.py
│   │   └── users.py
│   └── internal
│       ├── __init__.py
│       └── admin.py

Tipp

Es gibt mehrere __init__.py-Dateien: eine in jedem Verzeichnis oder Unterverzeichnis.

Das ermöglicht den Import von Code aus einer Datei in eine andere.

In app/main.py könnten Sie beispielsweise eine Zeile wie diese haben:

from app.routers import items
  • Das Verzeichnis app enthält alles. Und es hat eine leere Datei app/__init__.py, es handelt sich also um ein „Python-Package“ (eine Sammlung von „Python-Modulen“): app.
  • Es enthält eine Datei app/main.py. Da sie sich in einem Python-Package (einem Verzeichnis mit einer Datei __init__.py) befindet, ist sie ein „Modul“ dieses Packages: app.main.
  • Es gibt auch eine Datei app/dependencies.py, genau wie app/main.py ist sie ein „Modul“: app.dependencies.
  • Es gibt ein Unterverzeichnis app/routers/ mit einer weiteren Datei __init__.py, es handelt sich also um ein „Python-Subpackage“: app.routers.
  • Die Datei app/routers/items.py befindet sich in einem Package, app/routers/, also ist sie ein Submodul: app.routers.items.
  • Das Gleiche gilt für app/routers/users.py, es ist ein weiteres Submodul: app.routers.users.
  • Es gibt auch ein Unterverzeichnis app/internal/ mit einer weiteren Datei __init__.py, es handelt sich also um ein weiteres „Python-Subpackage“: app.internal.
  • Und die Datei app/internal/admin.py ist ein weiteres Submodul: app.internal.admin.

Die gleiche Dateistruktur mit Kommentaren:

.
├── app                  # „app“ ist ein Python-Package
│   ├── __init__.py      # diese Datei macht „app“ zu einem „Python-Package“
│   ├── main.py          # „main“-Modul, z. B. import app.main
│   ├── dependencies.py  # „dependencies“-Modul, z. B. import app.dependencies
│   └── routers          # „routers“ ist ein „Python-Subpackage“
│   │   ├── __init__.py  # macht „routers“ zu einem „Python-Subpackage“
│   │   ├── items.py     # „items“-Submodul, z. B. import app.routers.items
│   │   └── users.py     # „users“-Submodul, z. B. import app.routers.users
│   └── internal         # „internal“ ist ein „Python-Subpackage“
│       ├── __init__.py  # macht „internal“ zu einem „Python-Subpackage“
│       └── admin.py     # „admin“-Submodul, z. B. import app.internal.admin

APIRouter

Nehmen wir an, die Datei, die nur für die Verwaltung von Benutzern zuständig ist, ist das Submodul unter /app/routers/users.py.

Sie möchten die Pfadoperationen für Ihre Benutzer vom Rest des Codes trennen, um ihn organisiert zu halten.

Aber es ist immer noch Teil derselben FastAPI-Anwendung/Web-API (es ist Teil desselben „Python-Packages“).

Sie können die Pfadoperationen für dieses Modul mit APIRouter erstellen.

APIRouter importieren

Sie importieren ihn und erstellen eine „Instanz“ auf die gleiche Weise wie mit der Klasse FastAPI:

app/routers/users.py
from fastapi import APIRouter

router = APIRouter()


@router.get("/users/", tags=["users"])
async def read_users():
    return [{"username": "Rick"}, {"username": "Morty"}]


@router.get("/users/me", tags=["users"])
async def read_user_me():
    return {"username": "fakecurrentuser"}


@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
    return {"username": username}

Pfadoperationen mit APIRouter

Und dann verwenden Sie ihn, um Ihre Pfadoperationen zu deklarieren.

Verwenden Sie ihn auf die gleiche Weise wie die Klasse FastAPI:

app/routers/users.py
from fastapi import APIRouter

router = APIRouter()


@router.get("/users/", tags=["users"])
async def read_users():
    return [{"username": "Rick"}, {"username": "Morty"}]


@router.get("/users/me", tags=["users"])
async def read_user_me():
    return {"username": "fakecurrentuser"}


@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
    return {"username": username}

Sie können sich APIRouter als eine „Mini-FastAPI“-Klasse vorstellen.

Alle die gleichen Optionen werden unterstützt.

Alle die gleichen parameters, responses, dependencies, tags, usw.

Tipp

In diesem Beispiel heißt die Variable router, aber Sie können ihr einen beliebigen Namen geben.

Wir werden diesen APIRouter in die Hauptanwendung FastAPI einbinden, aber zuerst kümmern wir uns um die Abhängigkeiten und einen anderen APIRouter.

Abhängigkeiten

Wir sehen, dass wir einige Abhängigkeiten benötigen, die an mehreren Stellen der Anwendung verwendet werden.

Also fügen wir sie in ihr eigenes dependencies-Modul (app/dependencies.py) ein.

Wir werden nun eine einfache Abhängigkeit verwenden, um einen benutzerdefinierten X-Token-Header zu lesen:

app/dependencies.py
from typing import Annotated

from fastapi import Header, HTTPException


async def get_token_header(x_token: Annotated[str, Header()]):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


async def get_query_token(token: str):
    if token != "jessica":
        raise HTTPException(status_code=400, detail="No Jessica token provided")
app/dependencies.py
from fastapi import Header, HTTPException
from typing_extensions import Annotated


async def get_token_header(x_token: Annotated[str, Header()]):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


async def get_query_token(token: str):
    if token != "jessica":
        raise HTTPException(status_code=400, detail="No Jessica token provided")

Tipp

Bevorzugen Sie die Annotated-Version, falls möglich.

app/dependencies.py
from fastapi import Header, HTTPException


async def get_token_header(x_token: str = Header()):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


async def get_query_token(token: str):
    if token != "jessica":
        raise HTTPException(status_code=400, detail="No Jessica token provided")

Tipp

Um dieses Beispiel zu vereinfachen, verwenden wir einen erfundenen Header.

Aber in der Praxis werden Sie mit den integrierten Sicherheits-Werkzeugen bessere Ergebnisse erzielen.

Ein weiteres Modul mit APIRouter.

Nehmen wir an, Sie haben im Modul unter app/routers/items.py auch die Endpunkte, die für die Verarbeitung von Artikeln („Items“) aus Ihrer Anwendung vorgesehen sind.

Sie haben Pfadoperationen für:

  • /items/
  • /items/{item_id}

Es ist alles die gleiche Struktur wie bei app/routers/users.py.

Aber wir wollen schlauer sein und den Code etwas vereinfachen.

Wir wissen, dass alle Pfadoperationen in diesem Modul folgendes haben:

  • Pfad-prefix: /items.
  • tags: (nur ein Tag: items).
  • Zusätzliche responses.
  • dependencies: Sie alle benötigen die von uns erstellte X-Token-Abhängigkeit.

Anstatt also alles zu jeder Pfadoperation hinzuzufügen, können wir es dem APIRouter hinzufügen.

app/routers/items.py
from fastapi import APIRouter, Depends, HTTPException

from ..dependencies import get_token_header

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)


fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}


@router.get("/")
async def read_items():
    return fake_items_db


@router.get("/{item_id}")
async def read_item(item_id: str):
    if item_id not in fake_items_db:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"name": fake_items_db[item_id]["name"], "item_id": item_id}


@router.put(
    "/{item_id}",
    tags=["custom"],
    responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
    if item_id != "plumbus":
        raise HTTPException(
            status_code=403, detail="You can only update the item: plumbus"
        )
    return {"item_id": item_id, "name": "The great Plumbus"}

Da der Pfad jeder Pfadoperation mit / beginnen muss, wie in:

@router.get("/{item_id}")
async def read_item(item_id: str):
    ...

... darf das Präfix kein abschließendes / enthalten.

Das Präfix lautet in diesem Fall also /items.

Wir können auch eine Liste von tags und zusätzliche responses hinzufügen, die auf alle in diesem Router enthaltenen Pfadoperationen angewendet werden.

Und wir können eine Liste von dependencies hinzufügen, die allen Pfadoperationen im Router hinzugefügt und für jeden an sie gerichteten Request ausgeführt/aufgelöst werden.

Tipp

Beachten Sie, dass ähnlich wie bei Abhängigkeiten in Pfadoperation-Dekoratoren kein Wert an Ihre Pfadoperation-Funktion übergeben wird.

Das Endergebnis ist, dass die Pfade für diese Artikel jetzt wie folgt lauten:

  • /items/
  • /items/{item_id}

... wie wir es beabsichtigt hatten.

  • Sie werden mit einer Liste von Tags gekennzeichnet, die einen einzelnen String "items" enthält.
    • Diese „Tags“ sind besonders nützlich für die automatischen interaktiven Dokumentationssysteme (unter Verwendung von OpenAPI).
  • Alle enthalten die vordefinierten responses.
  • Für alle diese Pfadoperationen wird die Liste der dependencies ausgewertet/ausgeführt, bevor sie selbst ausgeführt werden.
    • Wenn Sie außerdem Abhängigkeiten in einer bestimmten Pfadoperation deklarieren, werden diese ebenfalls ausgeführt.
    • Zuerst werden die Router-Abhängigkeiten ausgeführt, dann die dependencies im Dekorator und dann die normalen Parameterabhängigkeiten.
    • Sie können auch Security-Abhängigkeiten mit scopes hinzufügen.

Tipp

dependencies im APIRouter können beispielsweise verwendet werden, um eine Authentifizierung für eine ganze Gruppe von Pfadoperationen zu erfordern. Selbst wenn die Abhängigkeiten nicht jeder einzeln hinzugefügt werden.

Check

Die Parameter prefix, tags, responses und dependencies sind (wie in vielen anderen Fällen) nur ein Feature von FastAPI, um Ihnen dabei zu helfen, Codeverdoppelung zu vermeiden.

Die Abhängigkeiten importieren

Der folgende Code befindet sich im Modul app.routers.items, also in der Datei app/routers/items.py.

Und wir müssen die Abhängigkeitsfunktion aus dem Modul app.dependencies importieren, also aus der Datei app/dependencies.py.

Daher verwenden wir einen relativen Import mit .. für die Abhängigkeiten:

app/routers/items.py
from fastapi import APIRouter, Depends, HTTPException

from ..dependencies import get_token_header

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)


fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}


@router.get("/")
async def read_items():
    return fake_items_db


@router.get("/{item_id}")
async def read_item(item_id: str):
    if item_id not in fake_items_db:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"name": fake_items_db[item_id]["name"], "item_id": item_id}


@router.put(
    "/{item_id}",
    tags=["custom"],
    responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
    if item_id != "plumbus":
        raise HTTPException(
            status_code=403, detail="You can only update the item: plumbus"
        )
    return {"item_id": item_id, "name": "The great Plumbus"}

Wie relative Importe funktionieren

Tipp

Wenn Sie genau wissen, wie Importe funktionieren, fahren Sie mit dem nächsten Abschnitt unten fort.

Ein einzelner Punkt ., wie in:

from .dependencies import get_token_header

würde bedeuten:

  • Beginnend im selben Package, in dem sich dieses Modul (die Datei app/routers/items.py) befindet (das Verzeichnis app/routers/) ...
  • finde das Modul dependencies (eine imaginäre Datei unter app/routers/dependencies.py) ...
  • und importiere daraus die Funktion get_token_header.

Aber diese Datei existiert nicht, unsere Abhängigkeiten befinden sich in einer Datei unter app/dependencies.py.

Erinnern Sie sich, wie unsere Anwendungs-/Dateistruktur aussieht:


Die beiden Punkte .., wie in:

from ..dependencies import get_token_header

bedeuten:

  • Beginnend im selben Package, in dem sich dieses Modul (die Datei app/routers/items.py) befindet (das Verzeichnis app/routers/) ...
  • gehe zum übergeordneten Package (das Verzeichnis app/) ...
  • und finde dort das Modul dependencies (die Datei unter app/dependencies.py) ...
  • und importiere daraus die Funktion get_token_header.

Das funktioniert korrekt! 🎉


Das Gleiche gilt, wenn wir drei Punkte ... verwendet hätten, wie in:

from ...dependencies import get_token_header

Das würde bedeuten:

  • Beginnend im selben Package, in dem sich dieses Modul (die Datei app/routers/items.py) befindet (das Verzeichnis app/routers/) ...
  • gehe zum übergeordneten Package (das Verzeichnis app/) ...
  • gehe dann zum übergeordneten Package dieses Packages (es gibt kein übergeordnetes Package, app ist die oberste Ebene 😱) ...
  • und finde dort das Modul dependencies (die Datei unter app/dependencies.py) ...
  • und importiere daraus die Funktion get_token_header.

Das würde sich auf ein Paket oberhalb von app/ beziehen, mit seiner eigenen Datei __init__.py, usw. Aber das haben wir nicht. Das würde in unserem Beispiel also einen Fehler auslösen. 🚨

Aber jetzt wissen Sie, wie es funktioniert, sodass Sie relative Importe in Ihren eigenen Anwendungen verwenden können, egal wie komplex diese sind. 🤓

Einige benutzerdefinierte tags, responses, und dependencies hinzufügen

Wir fügen weder das Präfix /items noch tags=["items"] zu jeder Pfadoperation hinzu, da wir sie zum APIRouter hinzugefügt haben.

Aber wir können immer noch mehr tags hinzufügen, die auf eine bestimmte Pfadoperation angewendet werden, sowie einige zusätzliche responses, die speziell für diese Pfadoperation gelten:

app/routers/items.py
from fastapi import APIRouter, Depends, HTTPException

from ..dependencies import get_token_header

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)


fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}


@router.get("/")
async def read_items():
    return fake_items_db


@router.get("/{item_id}")
async def read_item(item_id: str):
    if item_id not in fake_items_db:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"name": fake_items_db[item_id]["name"], "item_id": item_id}


@router.put(
    "/{item_id}",
    tags=["custom"],
    responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
    if item_id != "plumbus":
        raise HTTPException(
            status_code=403, detail="You can only update the item: plumbus"
        )
    return {"item_id": item_id, "name": "The great Plumbus"}

Tipp

Diese letzte Pfadoperation wird eine Kombination von Tags haben: ["items", "custom"].

Und sie wird auch beide Responses in der Dokumentation haben, eine für 404 und eine für 403.

Das Haupt-FastAPI.

Sehen wir uns nun das Modul unter app/main.py an.

Hier importieren und verwenden Sie die Klasse FastAPI.

Dies ist die Hauptdatei Ihrer Anwendung, die alles zusammen bindet.

Und da sich der Großteil Ihrer Logik jetzt in seinem eigenen spezifischen Modul befindet, wird die Hauptdatei recht einfach sein.

FastAPI importieren

Sie importieren und erstellen wie gewohnt eine FastAPI-Klasse.

Und wir können sogar globale Abhängigkeiten deklarieren, die mit den Abhängigkeiten für jeden APIRouter kombiniert werden:

app/main.py
from fastapi import Depends, FastAPI

from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

app = FastAPI(dependencies=[Depends(get_query_token)])


app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Den APIRouter importieren

Jetzt importieren wir die anderen Submodule, die APIRouter haben:

app/main.py
from fastapi import Depends, FastAPI

from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

app = FastAPI(dependencies=[Depends(get_query_token)])


app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Da es sich bei den Dateien app/routers/users.py und app/routers/items.py um Submodule handelt, die Teil desselben Python-Packages app sind, können wir einen einzelnen Punkt . verwenden, um sie mit „relativen Imports“ zu importieren.

Wie das Importieren funktioniert

Die Sektion:

from .routers import items, users

bedeutet:

  • Beginnend im selben Package, in dem sich dieses Modul (die Datei app/main.py) befindet (das Verzeichnis app/) ...
  • Suche nach dem Subpackage routers (das Verzeichnis unter app/routers/) ...
  • und importiere daraus die Submodule items (die Datei unter app/routers/items.py) und users (die Datei unter app/routers/users.py) ...

Das Modul items verfügt über eine Variable router (items.router). Das ist dieselbe, die wir in der Datei app/routers/items.py erstellt haben, es ist ein APIRouter-Objekt.

Und dann machen wir das gleiche für das Modul users.

Wir könnten sie auch wie folgt importieren:

from app.routers import items, users

Info

Die erste Version ist ein „relativer Import“:

from .routers import items, users

Die zweite Version ist ein „absoluter Import“:

from app.routers import items, users

Um mehr über Python-Packages und -Module zu erfahren, lesen Sie die offizielle Python-Dokumentation über Module.

Namenskollisionen vermeiden

Wir importieren das Submodul items direkt, anstatt nur seine Variable router zu importieren.

Das liegt daran, dass wir im Submodul users auch eine weitere Variable namens router haben.

Wenn wir eine nach der anderen importiert hätten, etwa:

from .routers.items import router
from .routers.users import router

würde der router von users den von items überschreiben und wir könnten sie nicht gleichzeitig verwenden.

Um also beide in derselben Datei verwenden zu können, importieren wir die Submodule direkt:

app/main.py
from fastapi import Depends, FastAPI

from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

app = FastAPI(dependencies=[Depends(get_query_token)])


app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Die APIRouter für users und items inkludieren

Inkludieren wir nun die router aus diesen Submodulen users und items:

app/main.py
from fastapi import Depends, FastAPI

from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

app = FastAPI(dependencies=[Depends(get_query_token)])


app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Info

users.router enthält den APIRouter in der Datei app/routers/users.py.

Und items.router enthält den APIRouter in der Datei app/routers/items.py.

Mit app.include_router() können wir jeden APIRouter zur Hauptanwendung FastAPI hinzufügen.

Es wird alle Routen von diesem Router als Teil von dieser inkludieren.

Technische Details

Tatsächlich wird intern eine Pfadoperation für jede Pfadoperation erstellt, die im APIRouter deklariert wurde.

Hinter den Kulissen wird es also tatsächlich so funktionieren, als ob alles dieselbe einzige Anwendung wäre.

Check

Bei der Einbindung von Routern müssen Sie sich keine Gedanken über die Performanz machen.

Dies dauert Mikrosekunden und geschieht nur beim Start.

Es hat also keinen Einfluss auf die Leistung. ⚡

Einen APIRouter mit benutzerdefinierten prefix, tags, responses und dependencies einfügen

Stellen wir uns nun vor, dass Ihre Organisation Ihnen die Datei app/internal/admin.py gegeben hat.

Sie enthält einen APIRouter mit einigen administrativen Pfadoperationen, die Ihre Organisation zwischen mehreren Projekten teilt.

In diesem Beispiel wird es ganz einfach sein. Nehmen wir jedoch an, dass wir, da sie mit anderen Projekten in der Organisation geteilt wird, sie nicht ändern und kein prefix, dependencies, tags, usw. direkt zum APIRouter hinzufügen können:

app/internal/admin.py
from fastapi import APIRouter

router = APIRouter()


@router.post("/")
async def update_admin():
    return {"message": "Admin getting schwifty"}

Aber wir möchten immer noch ein benutzerdefiniertes prefix festlegen, wenn wir den APIRouter einbinden, sodass alle seine Pfadoperationen mit /admin beginnen, wir möchten es mit den dependencies sichern, die wir bereits für dieses Projekt haben, und wir möchten tags und responses hinzufügen.

Wir können das alles deklarieren, ohne den ursprünglichen APIRouter ändern zu müssen, indem wir diese Parameter an app.include_router() übergeben:

app/main.py
from fastapi import Depends, FastAPI

from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

app = FastAPI(dependencies=[Depends(get_query_token)])


app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

Auf diese Weise bleibt der ursprüngliche APIRouter unverändert, sodass wir dieselbe app/internal/admin.py-Datei weiterhin mit anderen Projekten in der Organisation teilen können.

Das Ergebnis ist, dass in unserer Anwendung jede der Pfadoperationen aus dem Modul admin Folgendes haben wird:

  • Das Präfix /admin.
  • Den Tag admin.
  • Die Abhängigkeit get_token_header.
  • Die Response 418. 🍵

Dies wirkt sich jedoch nur auf diesen APIRouter in unserer Anwendung aus, nicht auf anderen Code, der ihn verwendet.

So könnten beispielsweise andere Projekte denselben APIRouter mit einer anderen Authentifizierungsmethode verwenden.

Eine Pfadoperation hinzufügen

Wir können Pfadoperationen auch direkt zur FastAPI-App hinzufügen.

Hier machen wir es ... nur um zu zeigen, dass wir es können 🤷:

app/main.py
from fastapi import Depends, FastAPI

from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users

app = FastAPI(dependencies=[Depends(get_query_token)])


app.include_router(users.router)
app.include_router(items.router)
app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)


@app.get("/")
async def root():
    return {"message": "Hello Bigger Applications!"}

und es wird korrekt funktionieren, zusammen mit allen anderen Pfadoperationen, die mit app.include_router() hinzugefügt wurden.

Sehr technische Details

Hinweis: Dies ist ein sehr technisches Detail, das Sie wahrscheinlich einfach überspringen können.


Die APIRouter sind nicht „gemountet“, sie sind nicht vom Rest der Anwendung isoliert.

Das liegt daran, dass wir deren Pfadoperationen in das OpenAPI-Schema und die Benutzeroberflächen einbinden möchten.

Da wir sie nicht einfach isolieren und unabhängig vom Rest „mounten“ können, werden die Pfadoperationen „geklont“ (neu erstellt) und nicht direkt einbezogen.

Es in der automatischen API-Dokumentation ansehen

Führen Sie nun uvicorn aus, indem Sie das Modul app.main und die Variable app verwenden:

$ uvicorn app.main:app --reload

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

und öffnen Sie die Dokumentation unter http://127.0.0.1:8000/docs.

Sie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags:

Den gleichen Router mehrmals mit unterschiedlichem prefix inkludieren

Sie können .include_router() auch mehrmals mit demselben Router und unterschiedlichen Präfixen verwenden.

Dies könnte beispielsweise nützlich sein, um dieselbe API unter verschiedenen Präfixen verfügbar zu machen, z. B. /api/v1 und /api/latest.

Dies ist eine fortgeschrittene Verwendung, die Sie möglicherweise nicht wirklich benötigen, aber für den Fall, dass Sie sie benötigen, ist sie vorhanden.

Einen APIRouter in einen anderen einfügen

Auf die gleiche Weise, wie Sie einen APIRouter in eine FastAPI-Anwendung einbinden können, können Sie einen APIRouter in einen anderen APIRouter einbinden, indem Sie Folgendes verwenden:

router.include_router(other_router)

Stellen Sie sicher, dass Sie dies tun, bevor Sie router in die FastAPI-App einbinden, damit auch die Pfadoperationen von other_router inkludiert werden.