committed by
GitHub
1 changed files with 352 additions and 0 deletions
@ -0,0 +1,352 @@ |
|||||
|
# Abhängigkeiten |
||||
|
|
||||
|
**FastAPI** hat ein sehr mächtiges, aber intuitives **<abbr title="Dependency Injection – Einbringen von Abhängigkeiten: Auch bekannt als Komponenten, Ressourcen, Provider, Services, Injectables">Dependency Injection</abbr>** System. |
||||
|
|
||||
|
Es ist so konzipiert, sehr einfach zu verwenden zu sein und es jedem Entwickler sehr leicht zu machen, andere Komponenten mit **FastAPI** zu integrieren. |
||||
|
|
||||
|
## Was ist „Dependency Injection“ |
||||
|
|
||||
|
**„Dependency Injection“** bedeutet in der Programmierung, dass es für Ihren Code (in diesem Fall Ihre *Pfadoperation-Funktionen*) eine Möglichkeit gibt, Dinge zu deklarieren, die er verwenden möchte und die er zum Funktionieren benötigt: „Abhängigkeiten“ – „Dependencies“. |
||||
|
|
||||
|
Das System (in diesem Fall **FastAPI**) kümmert sich dann darum, Ihren Code mit den erforderlichen Abhängigkeiten zu versorgen („die Abhängigkeiten einfügen“ – „inject the dependencies“). |
||||
|
|
||||
|
Das ist sehr nützlich, wenn Sie: |
||||
|
|
||||
|
* Eine gemeinsame Logik haben (die gleiche Code-Logik immer und immer wieder). |
||||
|
* Datenbankverbindungen teilen. |
||||
|
* Sicherheit, Authentifizierung, Rollenanforderungen, usw. durchsetzen. |
||||
|
* Und viele andere Dinge ... |
||||
|
|
||||
|
All dies, während Sie Codeverdoppelung minimieren. |
||||
|
|
||||
|
## Erste Schritte |
||||
|
|
||||
|
Sehen wir uns ein sehr einfaches Beispiel an. Es ist so einfach, dass es vorerst nicht sehr nützlich ist. |
||||
|
|
||||
|
Aber so können wir uns besser auf die Funktionsweise des **Dependency Injection** Systems konzentrieren. |
||||
|
|
||||
|
### Erstellen Sie eine Abhängigkeit (<abbr title="Das von dem abhängt, die zu verwendende Abhängigkeit">„Dependable“</abbr>) |
||||
|
|
||||
|
Konzentrieren wir uns zunächst auf die Abhängigkeit - die Dependency. |
||||
|
|
||||
|
Es handelt sich einfach um eine Funktion, die die gleichen Parameter entgegennimmt wie eine *Pfadoperation-Funktion*: |
||||
|
=== "Python 3.10+" |
||||
|
|
||||
|
```Python hl_lines="8-9" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="8-11" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="9-12" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="6-7" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="8-11" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
Das war's schon. |
||||
|
|
||||
|
**Zwei Zeilen**. |
||||
|
|
||||
|
Und sie hat die gleiche Form und Struktur wie alle Ihre *Pfadoperation-Funktionen*. |
||||
|
|
||||
|
Sie können sie sich als *Pfadoperation-Funktion* ohne den „Dekorator“ (ohne `@app.get("/some-path")`) vorstellen. |
||||
|
|
||||
|
Und sie kann alles zurückgeben, was Sie möchten. |
||||
|
|
||||
|
In diesem Fall erwartet diese Abhängigkeit: |
||||
|
|
||||
|
* Einen optionalen Query-Parameter `q`, der ein `str` ist. |
||||
|
* Einen optionalen Query-Parameter `skip`, der ein `int` ist und standardmäßig `0` ist. |
||||
|
* Einen optionalen Query-Parameter `limit`, der ein `int` ist und standardmäßig `100` ist. |
||||
|
|
||||
|
Und dann wird einfach ein `dict` zurückgegeben, welches diese Werte enthält. |
||||
|
|
||||
|
!!! info |
||||
|
FastAPI unterstützt (und empfiehlt die Verwendung von) `Annotated` seit Version 0.95.0. |
||||
|
|
||||
|
Wenn Sie eine ältere Version haben, werden Sie Fehler angezeigt bekommen, wenn Sie versuchen, `Annotated` zu verwenden. |
||||
|
|
||||
|
Bitte [aktualisieren Sie FastAPI](../../deployment/versions.md#upgrade-der-fastapi-versionen){.internal-link target=_blank} daher mindestens zu Version 0.95.1, bevor Sie `Annotated` verwenden. |
||||
|
|
||||
|
### `Depends` importieren |
||||
|
|
||||
|
=== "Python 3.10+" |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Deklarieren der Abhängigkeit im <abbr title="Das Abhängige, der Verwender der Abhängigkeit">„Dependant“</abbr> |
||||
|
|
||||
|
So wie auch `Body`, `Query`, usw., verwenden Sie `Depends` mit den Parametern Ihrer *Pfadoperation-Funktion*: |
||||
|
|
||||
|
=== "Python 3.10+" |
||||
|
|
||||
|
```Python hl_lines="13 18" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="15 20" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="16 21" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="11 16" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="15 20" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
Obwohl Sie `Depends` in den Parametern Ihrer Funktion genauso verwenden wie `Body`, `Query`, usw., funktioniert `Depends` etwas anders. |
||||
|
|
||||
|
Sie übergeben `Depends` nur einen einzigen Parameter. |
||||
|
|
||||
|
Dieser Parameter muss so etwas wie eine Funktion sein. |
||||
|
|
||||
|
Sie **rufen diese nicht direkt auf** (fügen Sie am Ende keine Klammern hinzu), sondern übergeben sie einfach als Parameter an `Depends()`. |
||||
|
|
||||
|
Und diese Funktion akzeptiert Parameter auf die gleiche Weise wie *Pfadoperation-Funktionen*. |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Im nächsten Kapitel erfahren Sie, welche anderen „Dinge“, außer Funktionen, Sie als Abhängigkeiten verwenden können. |
||||
|
|
||||
|
Immer wenn ein neuer Request eintrifft, kümmert sich **FastAPI** darum: |
||||
|
|
||||
|
* Ihre Abhängigkeitsfunktion („Dependable“) mit den richtigen Parametern aufzurufen. |
||||
|
* Sich das Ergebnis von dieser Funktion zu holen. |
||||
|
* Dieses Ergebnis dem Parameter Ihrer *Pfadoperation-Funktion* zuzuweisen. |
||||
|
|
||||
|
```mermaid |
||||
|
graph TB |
||||
|
|
||||
|
common_parameters(["common_parameters"]) |
||||
|
read_items["/items/"] |
||||
|
read_users["/users/"] |
||||
|
|
||||
|
common_parameters --> read_items |
||||
|
common_parameters --> read_users |
||||
|
``` |
||||
|
|
||||
|
Auf diese Weise schreiben Sie gemeinsam genutzten Code nur einmal, und **FastAPI** kümmert sich darum, ihn für Ihre *Pfadoperationen* aufzurufen. |
||||
|
|
||||
|
!!! check |
||||
|
Beachten Sie, dass Sie keine spezielle Klasse erstellen und diese irgendwo an **FastAPI** übergeben müssen, um sie zu „registrieren“ oder so ähnlich. |
||||
|
|
||||
|
Sie übergeben es einfach an `Depends` und **FastAPI** weiß, wie der Rest erledigt wird. |
||||
|
|
||||
|
## `Annotated`-Abhängigkeiten wiederverwenden |
||||
|
|
||||
|
In den Beispielen oben sehen Sie, dass es ein kleines bisschen **Codeverdoppelung** gibt. |
||||
|
|
||||
|
Wenn Sie die Abhängigkeit `common_parameters()` verwenden, müssen Sie den gesamten Parameter mit der Typannotation und `Depends()` schreiben: |
||||
|
|
||||
|
```Python |
||||
|
commons: Annotated[dict, Depends(common_parameters)] |
||||
|
``` |
||||
|
|
||||
|
Da wir jedoch `Annotated` verwenden, können wir diesen `Annotated`-Wert in einer Variablen speichern und an mehreren Stellen verwenden: |
||||
|
|
||||
|
=== "Python 3.10+" |
||||
|
|
||||
|
```Python hl_lines="12 16 21" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_02_an_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="14 18 23" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_02_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="15 19 24" |
||||
|
{!> ../../../docs_src/dependencies/tutorial001_02_an.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Das ist schlicht Standard-Python, es wird als „Typalias“ bezeichnet und ist eigentlich nicht **FastAPI**-spezifisch. |
||||
|
|
||||
|
Da **FastAPI** jedoch auf Standard-Python, einschließlich `Annotated`, basiert, können Sie diesen Trick in Ihrem Code verwenden. 😎 |
||||
|
|
||||
|
Die Abhängigkeiten funktionieren weiterhin wie erwartet, und das **Beste daran** ist, dass die **Typinformationen erhalten bleiben**, was bedeutet, dass Ihr Editor Ihnen weiterhin **automatische Vervollständigung**, **Inline-Fehler**, usw. bieten kann. Das Gleiche gilt für andere Tools wie `mypy`. |
||||
|
|
||||
|
Das ist besonders nützlich, wenn Sie es in einer **großen Codebasis** verwenden, in der Sie in **vielen *Pfadoperationen*** immer wieder **dieselben Abhängigkeiten** verwenden. |
||||
|
|
||||
|
## `async` oder nicht `async` |
||||
|
|
||||
|
Da Abhängigkeiten auch von **FastAPI** aufgerufen werden (so wie Ihre *Pfadoperation-Funktionen*), gelten beim Definieren Ihrer Funktionen die gleichen Regeln. |
||||
|
|
||||
|
Sie können `async def` oder einfach `def` verwenden. |
||||
|
|
||||
|
Und Sie können Abhängigkeiten mit `async def` innerhalb normaler `def`-*Pfadoperation-Funktionen* oder `def`-Abhängigkeiten innerhalb von `async def`-*Pfadoperation-Funktionen*, usw. deklarieren. |
||||
|
|
||||
|
Es spielt keine Rolle. **FastAPI** weiß, was zu tun ist. |
||||
|
|
||||
|
!!! note "Hinweis" |
||||
|
Wenn Ihnen das nichts sagt, lesen Sie den [Async: *„In Eile?“*](../../async.md#in-eile){.internal-link target=_blank}-Abschnitt über `async` und `await` in der Dokumentation. |
||||
|
|
||||
|
## Integriert in OpenAPI |
||||
|
|
||||
|
Alle Requestdeklarationen, -validierungen und -anforderungen Ihrer Abhängigkeiten (und Unterabhängigkeiten) werden in dasselbe OpenAPI-Schema integriert. |
||||
|
|
||||
|
Die interaktive Dokumentation enthält also auch alle Informationen aus diesen Abhängigkeiten: |
||||
|
|
||||
|
<img src="/img/tutorial/dependencies/image01.png"> |
||||
|
|
||||
|
## Einfache Verwendung |
||||
|
|
||||
|
Näher betrachtet, werden *Pfadoperation-Funktionen* deklariert, um verwendet zu werden, wann immer ein *Pfad* und eine *Operation* übereinstimmen, und dann kümmert sich **FastAPI** darum, die Funktion mit den richtigen Parametern aufzurufen, die Daten aus der Anfrage extrahierend. |
||||
|
|
||||
|
Tatsächlich funktionieren alle (oder die meisten) Webframeworks auf die gleiche Weise. |
||||
|
|
||||
|
Sie rufen diese Funktionen niemals direkt auf. Sie werden von Ihrem Framework aufgerufen (in diesem Fall **FastAPI**). |
||||
|
|
||||
|
Mit dem Dependency Injection System können Sie **FastAPI** ebenfalls mitteilen, dass Ihre *Pfadoperation-Funktion* von etwas anderem „abhängt“, das vor Ihrer *Pfadoperation-Funktion* ausgeführt werden soll, und **FastAPI** kümmert sich darum, es auszuführen und die Ergebnisse zu „injizieren“. |
||||
|
|
||||
|
Andere gebräuchliche Begriffe für dieselbe Idee der „Abhängigkeitsinjektion“ sind: |
||||
|
|
||||
|
* Ressourcen |
||||
|
* Provider |
||||
|
* Services |
||||
|
* Injectables |
||||
|
* Komponenten |
||||
|
|
||||
|
## **FastAPI**-Plugins |
||||
|
|
||||
|
Integrationen und „Plugins“ können mit dem **Dependency Injection** System erstellt werden. Aber tatsächlich besteht **keine Notwendigkeit, „Plugins“ zu erstellen**, da es durch die Verwendung von Abhängigkeiten möglich ist, eine unendliche Anzahl von Integrationen und Interaktionen zu deklarieren, die dann für Ihre *Pfadoperation-Funktionen* verfügbar sind. |
||||
|
|
||||
|
Und Abhängigkeiten können auf sehr einfache und intuitive Weise erstellt werden, sodass Sie einfach die benötigten Python-Packages importieren und sie in wenigen Codezeilen, *im wahrsten Sinne des Wortes*, mit Ihren API-Funktionen integrieren. |
||||
|
|
||||
|
Beispiele hierfür finden Sie in den nächsten Kapiteln zu relationalen und NoSQL-Datenbanken, Sicherheit usw. |
||||
|
|
||||
|
## **FastAPI**-Kompatibilität |
||||
|
|
||||
|
Die Einfachheit des Dependency Injection Systems macht **FastAPI** kompatibel mit: |
||||
|
|
||||
|
* allen relationalen Datenbanken |
||||
|
* NoSQL-Datenbanken |
||||
|
* externen Packages |
||||
|
* externen APIs |
||||
|
* Authentifizierungs- und Autorisierungssystemen |
||||
|
* API-Nutzungs-Überwachungssystemen |
||||
|
* Responsedaten-Injektionssystemen |
||||
|
* usw. |
||||
|
|
||||
|
## Einfach und leistungsstark |
||||
|
|
||||
|
Obwohl das hierarchische Dependency Injection System sehr einfach zu definieren und zu verwenden ist, ist es dennoch sehr mächtig. |
||||
|
|
||||
|
Sie können Abhängigkeiten definieren, die selbst wiederum Abhängigkeiten definieren können. |
||||
|
|
||||
|
Am Ende wird ein hierarchischer Baum von Abhängigkeiten erstellt, und das **Dependency Injection** System kümmert sich darum, alle diese Abhängigkeiten (und deren Unterabhängigkeiten) für Sie aufzulösen und die Ergebnisse bei jedem Schritt einzubinden (zu injizieren). |
||||
|
|
||||
|
Nehmen wir zum Beispiel an, Sie haben vier API-Endpunkte (*Pfadoperationen*): |
||||
|
|
||||
|
* `/items/public/` |
||||
|
* `/items/private/` |
||||
|
* `/users/{user_id}/activate` |
||||
|
* `/items/pro/` |
||||
|
|
||||
|
Dann könnten Sie für jeden davon unterschiedliche Berechtigungsanforderungen hinzufügen, nur mit Abhängigkeiten und Unterabhängigkeiten: |
||||
|
|
||||
|
```mermaid |
||||
|
graph TB |
||||
|
|
||||
|
current_user(["current_user"]) |
||||
|
active_user(["active_user"]) |
||||
|
admin_user(["admin_user"]) |
||||
|
paying_user(["paying_user"]) |
||||
|
|
||||
|
public["/items/public/"] |
||||
|
private["/items/private/"] |
||||
|
activate_user["/users/{user_id}/activate"] |
||||
|
pro_items["/items/pro/"] |
||||
|
|
||||
|
current_user --> active_user |
||||
|
active_user --> admin_user |
||||
|
active_user --> paying_user |
||||
|
|
||||
|
current_user --> public |
||||
|
active_user --> private |
||||
|
admin_user --> activate_user |
||||
|
paying_user --> pro_items |
||||
|
``` |
||||
|
|
||||
|
## Integriert mit **OpenAPI** |
||||
|
|
||||
|
Alle diese Abhängigkeiten, während sie ihre Anforderungen deklarieren, fügen auch Parameter, Validierungen, usw. zu Ihren *Pfadoperationen* hinzu. |
||||
|
|
||||
|
**FastAPI** kümmert sich darum, alles zum OpenAPI-Schema hinzuzufügen, damit es in den interaktiven Dokumentationssystemen angezeigt wird. |
Loading…
Reference in new issue