Start / Seminare / FastAPI Architektur in der Praxis

Modul

Abhängigkeitsgraphen komponieren

4 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Abhängigkeitsgraphen komponieren

0:00 Dependency Injection wird meistens als Bequemlichkeit erklärt: ein Weg, nicht überall dieselben Parameter durchzureichen. Das stimmt, greift aber viel zu kurz. In FastAPI ist dieses Werkzeug die Stelle, an der die gesamte Anwendung zusammengesetzt wird — jedes Teil erklärt, was es braucht, und das Framework baut daraus einen Graphen in der richtigen Reihenfolge.

0:21 Der Unterschied ist nicht akademisch. Er entscheidet darüber, ob eine Änderung an der Sessionverwaltung eine Zeile kostet oder zwanzig, und ob Ihre Fachlogik ohne Server und ohne Datenbank testbar ist. In diesem Modul bauen wir diesen Graphen Schicht für Schicht auf.

Depends als Bauplan lesen

0:37 Bevor wir die erste Dependency schreiben, lohnt sich ein Blick auf den Ist-Zustand. Unsere Handler bauen sich nämlich alles selbst zusammen, was sie brauchen — sie öffnen ihre Session, sie holen sich ihre Daten, sie schreiben ihre Logik daneben. Das ist die Gewohnheit, die wir in diesem Kapitel aufbrechen. Und dafür müssen wir zuerst sortieren, was da eigentlich alles zusammenkommt.

0:59 Ein Bild dafür: Denken Sie an eine Küche im Restaurant. Der Koch am Herd bestellt nicht selbst beim Großhandel und geht auch nicht ins Lager. Er sagt, was er braucht, und es steht bereit. Wer es besorgt hat und woher, muss ihn nicht interessieren — und genau deshalb kann er sich aufs Kochen konzentrieren. Bei uns ist der Handler der Koch. Er erklärt in seiner Signatur, was er braucht, und bekommt es fertig geliefert.

1:24 Die Frage, woher es kommt, wird an genau einer anderen Stelle beantwortet. Drei Schichten, und das Wichtigste steht in der Fußnote: Sie hängen alle im selben Graphen. Das ist keine Ordnungsliebe, das hat eine handfeste Folge — sie sehen dieselbe Session und arbeiten damit in derselben Transaktion. Wenn ein Service etwas ändert und ein zweiter im selben Aufruf etwas anderes, gehören beide Änderungen zusammen und werden gemeinsam gültig oder gemeinsam verworfen.

1:52 Hätte jeder Service seine eigene Session, wären es zwei unabhängige Transaktionen, und der Halbzustand aus dem zweiten Modul wäre zurück. Warum das automatisch funktioniert, sehen wir im vierten Kapitel. Der zweite Punkt ist der, den man im Alltag spürt. Heute steht die Sessionbehandlung in jedem Handler, der eine Datenbank braucht — also in einem Dutzend.

2:13 Angenommen, Sie wollen künftig bei jedem Fehler zusätzlich etwas protokollieren. Dann ändern Sie zwölf Stellen und übersehen eine. Die übersehene fällt nicht auf, weil dort ja weiterhin alles funktioniert, nur eben ohne Protokoll. Mit dem Graphen ändern Sie eine Funktion, und alle zwölf ziehen mit. Das ist der eigentliche Ertrag: nicht weniger Tippen, sondern weniger Stellen, an denen etwas auseinanderlaufen kann.

Sessions als Yield-Dependency

2:39 Fangen wir mit der untersten Schicht an, der Datenbanksession. Sie ist ein gutes erstes Beispiel, weil sie etwas braucht, was viele Dependencies nicht brauchen: einen Abbau. Eine Session muss nicht nur geöffnet, sondern auch wieder geschlossen werden. Und je nachdem, ob der Handler erfolgreich war oder nicht, muss dabei Verschiedenes passieren — speichern oder zurückrollen.

3:00 Genau diese Fallunterscheidung stand bisher in jedem einzelnen Handler. Jetzt zieht sie an eine Stelle. Das Muster dahinter ist erstaunlich elegant. Eine Dependency, die eine bestimmte Sprachkonstruktion verwendet, kann sich mitten in der Ausführung anhalten. Alles davor ist Aufbau und läuft vor dem Handler. An der Haltestelle übergibt sie ihr Ergebnis und wartet. Und alles danach ist Abbau und läuft, sobald die Antwort erzeugt ist.

3:27 Denken Sie an einen Garderobenschein: Beim Hineingehen bekommen Sie ihn, beim Herausgehen wird er eingelöst — und was dazwischen passiert, ist Ihre Sache. Nur dass hier die Garderobe auch dann aufräumt, wenn Sie stolpern. Worauf es hier ankommt, sind die drei Zweige nach der Haltestelle. Läuft alles gut, wird gespeichert.

3:46 Wirft der Handler eine Ausnahme, dann — und das ist der elegante Teil — schlägt diese Ausnahme genau an der Haltestelle wieder ein, als wäre sie dort entstanden. Der Fehlerzweig fängt sie, rollt zurück und reicht sie weiter. Und der letzte Zweig läuft in jedem Fall und gibt die Verbindung frei. Achten Sie auf das Weiterreichen: Fehlt es, verschluckt die Dependency den Fehler, und der Aufrufer bekommt eine Erfolgsmeldung für etwas, das nie passiert ist.

4:13 Der rote Faden hier ist: umstellen, dann beweisen. Die ersten drei Schritte sind unspektakulär — Sie nehmen den Block aus dem Handler heraus und schreiben stattdessen einen Parameter hin. Der Handler wird dabei sichtbar schlanker. Der vierte Schritt ist der, den man gern überspringt und der sich trotzdem lohnt: Bauen Sie absichtlich einen Fehler ein und schauen Sie zu, wie der Abbau läuft.

4:35 Ohne diesen Nachweis bleibt es eine Behauptung, dass zurückgerollt und geschlossen wird. Mit ihm haben Sie es einmal gesehen und vertrauen dem Muster danach zu Recht. Der zweite Punkt ist der, der zu falschen Erwartungen führt. Der Abbau läuft nicht am Ende des Handlerkörpers, sondern erst, wenn die Antwort fertig erzeugt ist.

4:54 Meistens ist das egal. Es wird wichtig, sobald Sie etwas zurückgeben, das erst später ausgewertet wird — einen Generator zum Beispiel. Dann ist die Session längst zu, wenn die Daten gebraucht werden. Genau dieser Fall begegnet uns im sechsten Modul beim Streamen wieder, und dort ist er keine Randnotiz, sondern der Grund für eine ganz bestimmte Bauweise.

Services und Logging als Baum

5:15 Die Session hängt jetzt sauber im Graphen. Aber unsere Handler rufen immer noch direkt die Datenbankfunktionen auf, und das heißt im Klartext: Die Fachlogik lebt im Endpunkt. Solange sie dort liegt, ist sie an HTTP gebunden und ohne Server nicht zu prüfen. Das ändern wir jetzt. Dabei entsteht die zweite Schicht — und nebenbei die Erkenntnis, dass eine Dependency selbst wieder Dependencies haben darf. Aus der flachen Liste wird ein Baum.

5:42 Konstruktor-Injektion klingt sperriger, als sie ist. Es bedeutet schlicht: Ein Service holt sich nichts, er bekommt alles. Session und Protokollierer werden ihm beim Bauen übergeben. Der Unterschied zeigt sich, wenn Sie ihn testen wollen. Ein Service, der sich seine Datenbankverbindung selbst aus einer globalen Variable greift, braucht zum Testen eine echte Datenbank.

6:03 Ein Service, der sie entgegennimmt, braucht nur irgendetwas, das sich wie eine Datenbank verhält. Das ist der ganze Trick, und er kostet nichts außer der Disziplin, nie nach einer Globalen zu greifen. Das Muster hier ist die Verschachtelung. Diese Funktion baut einen Service — und um das zu können, braucht sie selbst zwei Dinge, die wiederum von Funktionen gebaut werden.

6:26 Sie deklariert das genauso, wie ein Handler es tun würde. Damit entsteht eine Kette, die FastAPI von hinten aufrollt: erst die Blätter, dann die Zweige, zuletzt der Stamm. Was Sie hier sehen, ist also nicht nur ein Provider, sondern ein Stück Bauplan. Und der interessante Teil kommt im nächsten Kapitel — die Frage, was passiert, wenn zwei solcher Ketten dasselbe brauchen.

6:48 Der zweite und dritte Punkt gehören zusammen und ergeben einen praktischen Gewinn, den man erst im Fehlerfall zu schätzen weiß. Jede Anfrage bekommt eine eigene Kennung, und die reicht der Graph an alle Beteiligten durch. Steht morgens im Protokoll ein Fehler, können Sie sich damit alle Zeilen dieser einen Anfrage herausfiltern — quer über Middleware, Handler, Service und Audit-Eintrag.

7:10 Ohne diese Kennung haben Sie einen Fehler und tausend Zeilen Kontext von anderen Anfragen dazwischen. Der Unterschied bei der Fehlersuche ist erheblich. Die Aufgabe klingt klein und zeigt etwas Grundsätzliches. Sie sollen dafür sorgen, dass jede Protokollzeile einer Anfrage dieselbe Kennung trägt — auch die aus dem Service, der von der Middleware nichts weiß.

7:31 Der naheliegende Weg wäre, die Kennung als Parameter durch alle Aufrufe zu reichen. Machen Sie das nicht. Der Punkt der Übung ist gerade, dass der Graph diesen Transport übernimmt: Der Service erklärt, dass er den Anfragekontext braucht, und bekommt ihn. Keine Signatur dazwischen muss davon wissen.

Auflösung zur Anfragezeit

7:50 Bis hierhin haben wir FastAPI vertraut, dass es den Graphen schon richtig zusammensetzt. Jetzt schauen wir genau hin und verfolgen eine einzelne Anfrage durch die Auflösung. Denn zwei Dinge, auf die wir uns bisher stillschweigend verlassen haben, sind alles andere als selbstverständlich: dass jeder Service dieselbe Session sieht, und dass die Teile in der richtigen Reihenfolge entstehen.

8:11 Beides folgt aus einer Regel, die man kennen sollte. FastAPI liest die Signatur, findet dort weitere Dependencies, liest deren Signaturen und arbeitet sich so nach unten, bis nichts mehr kommt. Dann baut es von unten nach oben zusammen. Entscheidend ist: Die Reihenfolge ergibt sich allein aus den Signaturen. Nicht daraus, in welcher Reihenfolge Sie die Funktionen in die Datei geschrieben haben.

8:35 Das klingt selbstverständlich, hat aber eine angenehme Folge — Sie können Ihre Provider sortieren, wie Sie möchten, ohne irgendetwas kaputtzumachen. Der Bauplan steht in den Typen, nicht in der Dateireihenfolge. Die Faustregel steht in der Fußnote, und sie ist eine der nützlichsten dieses Seminars: Dürfen zwei gleichzeitige Anfragen sich das gefahrlos teilen?

8:57 Ein Verbindungspool — ja, natürlich, dafür ist er da. Eine laufende Transaktion — auf keinen Fall, das wäre ein Datenleck zwischen zwei Nutzern. Diese eine Frage beantwortet die meisten Zweifelsfälle. Und beachten Sie: Anfragebezogen ist die einzige Lebensdauer, die FastAPI für Sie verwaltet. Alles, was länger leben soll, gehört in den Startvorgang der Anwendung — dort liegen bei uns Engine und Schema.

9:23 Hier ist die Antwort auf die Frage vom Kapitelanfang. Innerhalb einer Anfrage läuft jede Dependency-Funktion genau einmal, und alle, die sie brauchen, bekommen dasselbe Ergebnis. Ohne diesen Mechanismus bekämen unser Angebotsservice und unser Freigabeservice je eine eigene Session — und damit zwei getrennte Transaktionen in derselben Anfrage.

9:43 Was der eine schreibt, sähe der andere nicht. Und wenn der zweite scheitert, bliebe die Änderung des ersten trotzdem stehen. Der Cache ist also kein Performance-Trick, sondern die Grundlage dafür, dass eine Anfrage eine Einheit bleibt. Die ersten beiden Punkte betreffen eine Wahl, die man beiläufig trifft und die Folgen hat.

10:02 Für einen Provider, der nur ein Objekt zusammenbaut, brauchen Sie kein asynchrones Schlüsselwort — FastAPI schiebt eine gewöhnliche Funktion in einen Threadpool, wo sie nichts blockieren kann. Umgekehrt ist es gefährlicher: Eine asynchrone Funktion, die intern eine blockierende Bibliothek aufruft, legt den Event Loop lahm. Sie sieht dabei völlig korrekt aus.

10:22 Merken Sie sich die einfache Regel: asynchron nur dort, wo tatsächlich gewartet wird — sonst gewöhnlich. Diese Aufgabe ist eine Beweisführung. Lassen Sie zwei Services derselben Anfrage die Identität ihrer Session melden — die eingebaute Objekt-Identitätsfunktion reicht dafür völlig. Es muss zweimal dieselbe Zahl herauskommen. Und dann drehen Sie den Cache für einen Versuch ab und schauen noch einmal: Jetzt sind es zwei verschiedene.

10:48 Damit haben Sie den Mechanismus nicht geglaubt, sondern gesehen. Das lohnt sich, weil dieser eine Mechanismus im Hintergrund darüber entscheidet, ob Ihre Anfragen transaktional sauber sind — und weil man ihn sonst nie zu Gesicht bekommt.

Was jetzt trägt

11:02 Der Graph steht. Die Sessionbehandlung liegt an genau einer Stelle, die Services bekommen ihre Mitarbeiter übergeben, und eine Anfrage bedeutet eine Session, eine Transaktion und eine Kennung. Was noch fehlt, sind zwei Dinge: Die Handler tragen ihre Verdrahtung immer noch sichtbar mit sich herum, und niemand prüft, wer da eigentlich ruft.

11:21 Beides nehmen wir uns im nächsten Modul vor — und ganz nebenbei fällt dabei die Testbarkeit ab, ohne dass wir dafür etwas Zusätzliches bauen müssten.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →