Kapitel 1. Das moderne Web

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Das Web, wie ich es mir vorgestellt habe, haben wir noch nicht gesehen. Die Zukunft ist noch so viel größer als die Vergangenheit.

Tim Berners-Lee

Vorschau

Es war einmal eine Zeit, in der das Web klein und einfach war. Entwickler hatten so viel Spaß daran, PHP-, HTML- und MySQL-Aufrufe in einzelne Dateien zu packen und jedem stolz zu erzählen, dass er sich ihre Website ansehen soll. Aber das Web wuchs mit der Zeit auf Zillionen, nein, Squilliarden von Seiten an - und der frühe Spielplatz wurde zu einem Metaverse von Themenparks.

In diesem Kapitel weise ich auf einige Bereiche hin, die für das moderne Web immer wichtiger geworden sind:

  • Dienste und APIs

  • Gleichzeitigkeit

  • Lagen

  • Daten

Das nächste Kapitel wird zeigen, was Python in diesen Bereichen bietet. Danach tauchen wir in das FastAPI-Webframework ein und sehen, was es zu bieten hat.

Dienste und APIs

Das Web ist ein großartiges Verbindungsgeflecht. Obwohl viele Aktivitäten immer noch auf derInhaltsseite stattfinden - HTML, JavaScript, Bilder usw. - liegt der Schwerpunkt zunehmend auf den Anwendungsprogrammierschnittstellen (APIs), die die Dinge miteinander verbinden.

Üblicherweise kümmert sich ein Webservice um den Low-Level-Datenbankzugriff und die Middle-Level-Geschäftslogik (oft als Backend zusammengefasst), während JavaScript oder mobile Apps ein reichhaltigesFrontend(interaktive Benutzeroberfläche) auf der obersten Ebene bereitstellen. Diese Vorder- und Hinterwelten sind komplexer und divergenter geworden, so dass sich Entwickler in der Regel auf das eine oder das andere spezialisieren müssen. Es ist schwieriger, ein Full-Stack-Entwickler zu sein, als es früher war.1

Diese beiden Welten kommunizieren über APIs miteinander. Im modernen Web ist das API-Design genauso wichtig wie das Design der Websites selbst. Eine API ist ein Vertrag, ähnlich wie ein Datenbankschema. Die Definition und Änderung von APIs ist heute eine wichtige Aufgabe.

Arten von APIs

Jede API definiert die folgenden Punkte:

Protokoll

Die Kontrollstruktur

Format

Die inhaltliche Struktur

Im Zuge der technologischen Entwicklung von Einzelrechnern über Multitasking-Systeme bis hin zu vernetzten Servern haben sich verschiedene API-Methoden entwickelt. Wahrscheinlich wirst du irgendwann auf eine oder mehrere davon stoßen, daher hier eine kurze Zusammenfassung, bevor wir uns mitHTTP und seinen Freunden beschäftigen, die in diesem Buch vorgestellt werden:

  • Vor der Vernetzung bedeutete eine API in der Regel eine sehr enge Verbindung, wie ein Funktionsaufruf zu einer Bibliothek in derselben Sprache wie deine Anwendung - z. B. die Berechnung einer Quadratwurzel in einer Mathematikbibliothek.

  • Remote Procedure Calls (RPCs) wurden erfunden, um Funktionen in anderen Prozessen, auf demselben Rechner oder anderen, so aufzurufen, als ob sie in der aufrufenden Anwendung wären. Ein beliebtes aktuelles Beispiel ist gRPC.

  • Messaging sendet kleine Datenpakete in Pipelines zwischen Prozessen. Nachrichten können verbähnliche Befehle sein oder auch nur substantivähnliche Ereignisse von Interesse anzeigen. Zu den derzeit beliebten Messaging-Lösungen, die von Toolkits bis hin zu vollständigen Servern reichen, gehörenApache Kafka,RabbitMQ,NATS undZeroMQ. Die Kommunikation kann nach unterschiedlichen Mustern erfolgen:

    Anfrage/Antwort

    Eins: Eins, wie ein Webbrowser, der einen Webserver aufruft.

    Veröffentlichen-abonnieren, oder pub-sub

    Ein Verleger sendet Nachrichten aus, und die Abonnenten reagieren auf jede Nachricht entsprechend einiger Daten in der Nachricht, z. B. einem Betreff.

    Warteschlangen

    Wie pub-sub, aber nur einer aus einem Pool von Abonnenten nimmt die Nachricht auf und handelt danach.

Jeder dieser Dienste kann neben einem Webservice verwendet werden, z.B. um eine langsame Backend-Aufgabe wie das Versenden einer E-Mail oder das Erstellen eines Miniaturbildes auszuführen.

HTTP

Berners-Lee schlug drei Komponenten für sein World Wide Web vor:

HTML

Eine Sprache zur Anzeige von Daten

HTTP

Ein Client-Server-Protokoll

URLs

Ein Adressierungsschema für Webressourcen

Obwohl dies im Nachhinein offensichtlich erscheint, erwies es sich als lächerlich nützliche Kombination. Als sich das Web entwickelte, experimentierten die Menschen, und einige Ideen, wie der IMG Tag, überlebten den darwinistischen Kampf. Und als die Bedürfnisse klarer wurden, machten sich die Menschen daran, Standards zu definieren.

REST(ful)

Ein Kapitel in Roy FieldingsDoktorarbeit definiert Representational State Transfer (REST)- einenArchitekturstil für die Nutzung von HTTP.2 Obwohl er oft erwähnt wird, ist er weitgehendmissverstanden worden.

Es hat sich eine grob geteilte Anpassung entwickelt, die das moderne Web dominiert. Sie heißt RESTful und hat diese Eigenschaften:

  • Verwendet HTTP und das Client-Server-Protokoll

  • Zustandslos (jede Verbindung ist unabhängig)

  • Cachefähig

  • Ressourcenbasierte

Eine Ressource sind Daten, die du unterscheiden und mit denen du Operationen durchführen kannst. Ein Webservice bietet einen Endpunkt - eine eindeutige URL und ein HTTP-Verb (Aktion) - für jede Funktion, die er zur Verfügung stellen will. Ein Endpunkt wird auch als Route bezeichnet, weil er die URL zu einer Funktion weiterleitet.

Datenbankbenutzer sind mit dem CRUD-Akronymder Prozeduren vertraut: create, read, update, delete. Die HTTP-Verben sind ziemlich CRUDdy:

POST

Erstellen (schreiben)

PUT

Vollständig ändern (ersetzen)

PATCH

Teilweise ändern (aktualisieren)

GET

Um, get (lesen, abrufen)

DELETE

Äh, löschen

Ein Client sendet eine Anfrage an einen RESTful-Endpunkt mit Daten in einem der folgenden Bereiche einer HTTP-Nachricht:

  • Kopfzeilen

  • Die URL-Zeichenfolge

  • Abfrage-Parameter

  • Körperwerte

Eine HTTP-Antwort wiederum gibt diese zurück:

  • Ein ganzzahligerStatuscode, der Folgendes angibt:

    100s

    Info, weitermachen

    200s

    Erfolg

    300s

    Umleitung

    400s

    Kundenfehler

    500s

    Server-Fehler

  • Verschiedene Kopfzeilen

  • Ein Körper, der leer, einzeln oder gechunked (in aufeinanderfolgenden Teilen) sein kann

Mindestens ein Statuscode ist ein Osterei:418 (I'm a teapot) soll von einer mit dem Internet verbundenen Teekanne zurückgegeben werden, wenn sie aufgefordert wird, Kaffee zu brühen.

fapi 01in01

Es gibt viele Websites und Bücher zum Thema RESTful API-Design, die alle nützliche Faustregeln enthalten. Dieses Buch gibt einige davon auf dem Weg weiter.

JSON- und API-Datenformate

Frontend-Anwendungen können einfachen ASCII-Text mit Backend-Webdiensten austauschen, aber wie kannst du Datenstrukturen wie Listen von Dingen ausdrücken?

Gerade als wir sie wirklich brauchten, kam die JavaScript Object Notation (JSON)auf - eine weitere einfache Idee, die ein wichtiges Problem löst und im Nachhinein offensichtlich erscheint. Obwohl das J für JavaScript steht, sieht die Syntax auch sehr nach Python aus.

JSON hat ältere Ansätze wie XML und SOAP weitgehend ersetzt. Im weiteren Verlauf dieses Buches wirst du sehen, dass JSON das Standardformat für die Ein- und Ausgabe von Webservices ist.

JSON:API

Die Kombination aus RESTful-Design und JSON-Datenformaten ist inzwischen weit verbreitet, aber es bleibt immer noch ein gewisser Spielraum für Unklarheiten und Nerds. Der jüngste JSON:API-Vorschlag zielt darauf ab, die Spezifikationen etwas zu verschärfen. In diesem Buch wird der lockere RESTful-Ansatz verwendet, aber JSON:API oder etwas ähnlich Strenges kann nützlich sein, wenn du erhebliche Probleme hast.

GraphQL

RESTful-Schnittstellen können für manche Zwecke umständlich sein. Facebook (jetzt Meta) hat dieGraph Query Language (GraphQL)entwickelt, um flexiblere Dienstabfragen zu spezifizieren. Ich werde in diesem Buch nicht auf GraphQL eingehen, aber du solltest dich damit befassen, wenn du das RESTful-Design für deine Anwendung als unzureichend empfindest.

Gleichzeitigkeit

Neben der zunehmenden Serviceorientierung erfordert die rasante Zunahme der Zahl der Verbindungen zu Webdiensten eine immer bessere Effizienz und Skalierung.

Wir wollen die folgenden Punkte reduzieren:

Latenz

Die Wartezeit im Vorfeld

Durchsatz

Die Anzahl der Bytes pro Sekunde zwischen dem Dienst und seinen Anrufern

In den alten Tagen des Internets3 träumte man davon, Hunderte von gleichzeitigen Verbindungen zu unterstützen, dann ärgerte man sich über das "10K-Problem", und jetzt geht man von Millionen gleichzeitig aus.

Der Begriff Gleichzeitigkeit bedeutet nicht, dass mehrere Prozesse in derselben Nanosekunde in einer einzigen CPU ablaufen. Stattdessen vermeidet Gleichzeitigkeit vor allem beschäftigtes Warten (Leerlauf der CPU, bis eine Antwort geliefert wird). CPUs sind schnell, aber Netzwerke und Festplatten sind tausend- bis millionenfach langsamer. Wenn wir also mit einem Netzwerk oder einer Festplatte sprechen, wollen wir nicht einfach mit leerem Blick dasitzen, bis es antwortet.

Die normale Python-Ausführung ist synchron: eine Sache nach der anderen, in der vom Code vorgegebenen Reihenfolge. Manchmal wollen wir asynchron sein: ein bisschen von einer Sache machen, dann ein bisschen von einer anderen Sache, zurück zur ersten Sache usw. Wenn unser gesamter Code die CPU zum Berechnen von Dingen benutzt(CPU-gebunden), haben wir eigentlich keine Zeit, um asynchron zu sein. Wenn wir aber etwas ausführen, das die CPU auf die Fertigstellung einer externen Sache warten lässt (I/O-gebunden), können wir asynchron sein.

Asynchrone Systeme bieten eine Ereignisschleife: Anfragen für langsame Operationen werden gesendet und notiert, aber wir halten die CPU nicht auf, indem wir auf die Antworten warten. Stattdessen wird bei jedem Durchlauf der Schleife eine unmittelbare Verarbeitung durchgeführt, und alle Antworten, die in dieser Zeit eingegangen sind, werden im nächsten Durchlauf bearbeitet.

Später in diesem Buch wirst du sehen, wie FastAPI durch die Unterstützung von asynchroner Verarbeitung viel schneller ist als typische Web-Frameworks.

Asynchrone Verarbeitung ist keine Zauberei. Du musst immer noch darauf achten, dass du während der Ereignisschleife nicht zu viel rechenintensive Arbeit erledigst, denn das verlangsamt alles. Später in diesem Buch wirst du sehen, wozu Python die Schlüsselwörterasync und await verwendet und wie du mit FastAPI synchrone und asynchrone Verarbeitung mischen kannst.

Lagen

Shrek-Fans erinnern sich vielleicht daran, dass er auf seine vielschichtige Persönlichkeit hinwies, woraufhin Esel antwortete: "Wie eine Zwiebel?"

fapi 01in02

Nun, wenn Oger und weinendes Gemüse Schichten haben können, dann kann das auch Software. Um Größe und Komplexität zu bewältigen, verwenden viele Anwendungen seit langem ein sogenanntesDrei-Schichten-Modell.4 Das ist nicht sonderlich neu. Die Begriffe sind unterschiedlich,5 aber für dieses Buch verwende ich die folgende einfache Trennung der Begriffe (siehe Abbildung 1-1):

Web

Eingabe-/Ausgabeschicht über HTTP, die Client-Anfragen zusammenstellt, den Service Layer aufruft und Antworten zurückgibt

Service

Die Geschäftslogik, die bei Bedarf die Datenschicht aufruft

Daten

Zugang zu Datenspeichern und anderen Diensten

Modell

Gemeinsame Datendefinitionen für alle Ebenen

Web-Client

Webbrowser oder andere HTTP-Client-seitige Software

Datenbank

Der Datenspeicher, oft ein SQL- oder NoSQL-Server

fapi 0101
Abbildung 1-1. Vertikale Schichten

Diese Komponenten helfen dir, deine Website zu skalieren, ohne bei Null anfangen zu müssen. Sie sind keine Gesetze der Quantenmechanik, also betrachte sie als Richtlinien für die Darstellung in diesem Buch.

Die Schichten kommunizieren miteinander über APIs. Das können einfache Funktionsaufrufe zu separaten Python-Modulen sein, aber auch der Zugriff auf externen Code über eine beliebige Methode. Wie ich bereits gezeigt habe, kann dies RPCs, Nachrichten usw. umfassen. In diesem Buch gehe ich von einem einzigen Webserver aus, dessen Python-Code andere Python-Module importiert. Die Trennung und das Verbergen von Informationen wird von den Modulen übernommen.

Die Webebene ist diejenige, die die Nutzer über Client-Anwendungen und APIs sehen. Normalerweise sprechen wir von einer RESTful-Weboberfläche mit URLs und JSON-kodierten Anfragen und Antworten. Aber auch alternative Textclients (oder Befehlszeilenschnittstellen, CLI) können neben der Webebene erstellt werden. Python-Webcode kann Module der Serviceebene importieren, sollte aber keine Datenmodule importieren.

Die Service-Schicht enthält die eigentlichen Details dessen, was diese Website anbietet. Diese Schicht sieht im Wesentlichen wie eine Bibliothek aus. Sie importiert Datenmodule, um auf Datenbanken und externe Dienste zuzugreifen, sollte aber die Details nicht kennen.

DieDatenschicht ermöglicht der Dienstebene den Zugang zu Daten über Dateien oder Client-Aufrufe zu anderen Diensten. Es kann auch alternative Datenschichten geben, die mit einer einzigen Dienstebene kommunizieren.

DasFeld Model ist keine eigentliche Ebene, sondern eine Quelle für Datendefinitionen, die von den Ebenen gemeinsam genutzt werden. Dies ist nicht nötig, wenn du integrierte Python-Datenstrukturen zwischen den Ebenen weitergibst. Wie du sehen wirst, ermöglicht die Einbindung von Pydantic in FastAPI die Definition von Datenstrukturen mit vielen nützlichen Funktionen.

Warum diese Unterteilungen? Neben vielen anderen Gründen kann jede Schicht sein:

  • Geschrieben von Spezialisten.

  • Getestet in Isolation.

  • Ersetzt oder ergänzt: Du könntest eine zweite Webebene hinzufügen, die eine andere API wie gRPC verwendet, neben einer Webebene.

Befolge eine Regel aus Ghostbusters: Kreuze nicht die Ströme, d.h. lass keine Webdetails aus der Webschicht oder Datenbankdetails aus der Datenschicht durchsickern.

Du kannst dir dieSchichten als einen vertikalen Stapel vorstellen, wie einen Kuchen im Great British Bake Off.6

fapi 01in03

Hier sind einige Gründe für Trennung der Schichten:

  • Wenn du die Schichten nicht trennst, erwartest du ein geheiligtes Web-Mem: Jetzt hast du zwei Probleme.

  • Wenn die Schichten einmal vermischt sind, ist eine spätere Trennung sehr schwierig.

  • Du musst zwei oder mehr Fachgebiete kennen, um Tests zu verstehen und zu schreiben, wenn die Logik des Codes durcheinander gerät.

Übrigens: Auch wenn ich sie Schichten nenne, musst du nicht davon ausgehen, dass eine Schicht "über" oder "unter" einer anderen liegt und dass die Befehle mit der Schwerkraft fließen. Vertikaler Chauvinismus! Du könntest die Schichten auch als seitwärts kommunizierende Boxen betrachten(Abbildung 1-2).

fapi 0102
Abbildung 1-2. Seitlich kommunizierende Boxen

Wie auch immer du sie visualisierst, die einzigen Kommunikationswege zwischen den Boxen/Layern sind die Pfeile (APIs). Das ist wichtig für das Testen und Debuggen. Wenn es in einer Fabrik undokumentierte Türen gibt, wird der Nachtwächter unweigerlich überrascht sein.

Die Pfeile zwischen dem Webclient und der Webschicht verwenden HTTP oder HTTPS, um hauptsächlich JSON-Text zu transportieren. Die Pfeile zwischen der Datenschicht und der Datenbank verwenden ein datenbankspezifisches Protokoll und transportieren SQL- (oder anderen) Text. Die Pfeile zwischen den Schichten selbst sind Funktionsaufrufe, die Datenmodelle transportieren.

Außerdem werden die folgenden Datenformate empfohlen, die durch die Pfeile fließen:

Kunde ⇔ Web

RESTful HTTP mit JSON

Web ⇔ Service

Modelle

Dienst ⇔ Daten

Modelle

Daten ⇔ Datenbanken und Dienste

Spezifische APIs

Aufgrund meiner eigenen Erfahrungen habe ich mich entschieden, die Themen in diesem Buch so zu strukturieren. Es ist praktikabel und hat sich für ziemlich komplexe Websites bewährt, aber es ist nicht heilig. Vielleicht hast du ein besseres Design! Wie auch immer du es machst, das sind die wichtigsten Punkte:

  • Trenne die domänenspezifischen Details.

  • Definiere Standard-APIs zwischen den Schichten.

  • Schummle nicht; lass nichts durchsickern.

Manchmal ist es eine Herausforderung zu entscheiden, auf welcher Schicht der Code am besten aufgehoben ist. In Kapitel 11 geht es zum Beispiel um Authentifizierungs- und Autorisierungsanforderungen und wie man sie implementiert - als zusätzliche Schicht zwischen Web und Service oder innerhalb einer von beiden. Softwareentwicklung ist manchmal genauso viel Kunst wie Wissenschaft.

Daten

Das Web wurde oft als Frontend für relationale Datenbanken genutzt, obwohl sich viele andere Möglichkeiten der Datenspeicherung und des Datenzugriffs entwickelt haben, wie zum Beispiel NoSQL- oder NewSQL-Datenbanken.

Aber nicht nur Datenbanken, sondern auchmaschinelles Lernen (ML)-oder Deep Learning oder einfach nur KI- verändert die Technologielandschaft grundlegend. Die Entwicklung großer Modelle erfordert vielArbeit mit Daten, die traditionell als Extrahieren, Transformieren, Laden (ETL) bezeichnet wird.

Als universelle Service-Architektur kann das Web bei vielen der kniffligen Aufgaben von ML-Systemen helfen.

Überprüfung

Im Web werden viele APIs verwendet, vor allem aber RESTful. Asynchrone Aufrufe ermöglichen eine bessere Gleichzeitigkeit, was den Gesamtprozess beschleunigt. Webservice-Anwendungen sind oft groß genug, um sie in Schichten aufzuteilen. Daten sind zu einem eigenen wichtigen Bereich geworden. All diese Konzepte werden in der Programmiersprache Python behandelt, die im nächsten Kapitel vorgestellt wird.

1 Ich habe den Versuch vor ein paar Jahren aufgegeben.

2 Stil bedeutet eher ein übergeordnetes Muster, wie Client-Server, als ein bestimmtes Design.

3 Als die Höhlenmenschen Hacky-Sack mit riesigen Faultieren spielten.

4 Wähle deinen eigenen Dialekt: tier/layer, tomato/tomahto/arigato.

5 Du wirst oft den Begriff Model-View-Controller (MVC) und Varianten sehen. Das wird oft von Religionskriegen begleitet, denen ich nicht zustimme.

6 Wie die Zuschauer wissen, darfst du in der nächsten Woche nicht ins Zelt zurückkehren, wenn deine Schichten schlampig werden.

Get FastAPI now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.