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 Dateiapp/__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 wieapp/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
:
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
:
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:
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")
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.
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 erstellteX-Token
-Abhängigkeit.
Anstatt also alles zu jeder Pfadoperation hinzuzufügen, können wir es dem APIRouter
hinzufügen.
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 mitscopes
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:
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 Verzeichnisapp/routers/
) ... - finde das Modul
dependencies
(eine imaginäre Datei unterapp/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 Verzeichnisapp/routers/
) ... - gehe zum übergeordneten Package (das Verzeichnis
app/
) ... - und finde dort das Modul
dependencies
(die Datei unterapp/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 Verzeichnisapp/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 unterapp/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:
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:
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:
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 Verzeichnisapp/
) ... - Suche nach dem Subpackage
routers
(das Verzeichnis unterapp/routers/
) ... - und importiere daraus die Submodule
items
(die Datei unterapp/routers/items.py
) undusers
(die Datei unterapp/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:
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
:
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:
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:
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 🤷:
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.