Transcript

API-Stile

Wie und womit baut man ein gutes API?

„Es ist einfach schwieriger, ein gutes REST API zu bauen, als ein mittelgutes HTTP Web API!” Eins ist klar: eine reine Technologie-Entscheidung für RPC, REST oder GraphQL bringt noch lange kein gutes API hervor. Was man beachten sollte, wo die Fallstricke liegen und warum Stefan sich oft über den Einsatz von GraphQL ärgert: darum geht’s in dieser Folge.

Back to episode

Transcript

Lucas:

Hallo und herzlich willkommen zu einer neuen Folge des INNOQ Podcast. Heute habe ich wieder den Stefan eingeladen. Hallo Stefan!

Stefan:

Hallo Lucas!

Lucas:

Und wir wollen heute mal über verschiedene API Stile reden. Viele Leute bauen APIs und haben vielleicht schon eine Idee, wie man die heute baut. Und wir wollen die einfach noch mal gegenüberstellen und überlegen, welcher wann vielleicht gut geeignet ist. Aber bevor wir da reingehen. Bald wird es eine Folge 100 von diesem Podcast geben. Wir haben tatsächlich jetzt schon einige Folgen aufgenommen und haben wir uns überlegt: Da wollen wir vielleicht noch mal auf eure Fragen eingehen. Also wenn ihr irgendwelche Fragen habt, egal ob das jetzt irgendwas Technisches ist oder ob ihr irgendwelche Fragen zum Podcast selbst habt oder was auch immer euch einfällt, dann meldet euch gerne bei uns und wir werden dann versuchen, die in der Folge 100 zu beantworten. Wir haben uns auch noch was anderes ausgedacht, aber das ist eine Überraschung. Und die Fragen könnt ihr uns entweder per Twitter schicken, entweder an den INNOQ Account oder an meinen Account, in den Show Notes, oder ihr schickt uns einfach eine Mail an [email protected]. Das kommt auch noch mal in die Show Notes. Wir freuen uns und wir freuen uns auch immer über Ideen. Wir hatten jetzt in letzter Zeit einige Mails zu Ideen für Folgen, was ihr gerne hören wollt, da gehen wir immer gerne darauf ein. Gut, dann kommen wir jetzt zu API Stilen. Ich fange jetzt erst mal mit einer Frage an, die vielleicht etwas komisch klingt, aber wozu brauche ich eigentlich so eine API in einer Web Anwendung?

Stefan [00:01:39] Da steckt schon einiges an, wie soll ich sagen, an Annahmen drin. Ich habe von Webanwendung noch gar nichts gesagt, ich habe noch gar nichts gestimmt. Also reden wir von der Webanwendung oder von irgendwas anderem, was meinen wir überhaupt mit API? Vielleicht fokussieren wir erst mal und sagen wir meinen mit API jetzt nicht allgemeine Application Programming Interfaces. Es geht also nicht um die API Gestaltung für irgendeine Bibliothek, obwohl das auch ein spannendes Thema wäre, sondern wir konzentrieren uns auf APIs für den Remote Zugriff auf irgendwas. Ich habe irgendeine Form von Anwendung, die irgendwelche interessanten Dinge macht und andere Leute sollen diese interessanten Dinge nutzen und konsumieren können und brauchen dazu irgendeine programmatische Schnittstelle, die sie über ein Netzwerk benutzen können, um auf diesen Service, auf diese Anwendung, auf dieses Ding, diesen Provider zuzugreifen, um die Funktion aufzurufen und vielleicht ein Ergebnis zurückzubekommen oder irgendeine Verarbeitung anzustoßen. Und Gründe dafür können alle möglichen sein. Der vielleicht wichtigste Grund ist, dass ich diese Logik entweder nur an dieser einen Stelle erbringen kann oder will. Also vielleicht ist das ein Zugriff auf irgendwelche Daten, die ich lokal gespeichert habe. Vielleicht ist das ein Zugriff auf irgendeine Hardware, die bei mir zur Verfügung ist. Vielleicht ist es eine tolle Geschäftslogik, die ich in einem Software as a Service Angebot zur Verfügung stellen möchte. Vielleicht ist es etwas Tolles, was ich mache, wo ich meinen Code nicht herausgeben möchte, damit jemand anderes den sehen kann. Aber es gibt viele Gründe, warum ich so etwas machen wollen würde und das kann natürlich auch in meiner eigenen Anwendung intern sein, wo ich vielleicht im Sinne von Separation of Concerns, die eine Gruppe habe, die sich um die Implementierung dieser Dienste kümmert und eine andere Gruppe, die diese Dienste nur benutzen soll. Immer wenn ich so eine Trennung zwischen Fraktionen habe, nennen wir sie auf der einen Seite Provider und auf der anderen Seite Consumer, dann brauche ich irgendwas dazwischen. Und an dieser Schnittstelle, oder das, was diese Schnittstelle sozusagen kennzeichnet, ist das Interface, die Schnittstelle, für diejenigen, die das Ganze benutzen, die Programmierschnittstelle, die sich daraus ergibt. Und das brauche ich in vielen unterschiedlichen Fällen. Und wie ich das machen kann, darüber sprechen wir dann vermutlich gleich.

Lucas:

Und ein Sonderfall davon wäre jetzt auch, wenn ich beispielsweise eine Webanwendung baue, bei der ich im Frontend so was wie AngularJS oder React benutze und dann ein Backend habe, das wäre dann auch so eine Service Provider Sache, ein spezieller Fall davon.

Stefan:

Ja, man kann diskutieren, ob das ein gutes Beispiel ist. Das machen wir vielleicht am Ende noch mal, aber vom Grundsatz her, ja. Ich habe in diesem Beispiel, das du gerade genannt hast, habe ich vielleicht ein Frontend Team und ein Backend Team. Das Backend Team implementiert irgendwelche Geschäftslogik, die auf Legacy Anwendung oder auf irgendwelche Datenbanken zugreift oder irgendwelche Sachen integriert. Und dieses Backend Team stellt diese Logik sozusagen in einer schmalen Fassade in einem speziell dafür ausgestatteten Interface, dem Frontend Team zur Verfügung, so dass das Frontend Team das dann benutzen kann, um seine Client Logik zusammenzubauen. Es ist auf jeden Fall ein sehr üblicher Fall, der sehr häufig vorkommt. Aber es könnte auch sein, dass ich zum Beispiel zwei Anwendungen habe, die einen unterschiedlichen Fokus haben. Die eine Anwendung kümmert sich um Content Management und Redaktionssystem und die andere Anwendung kümmert sich um Accounting und Billing. Das sind vielleicht zwei Funktionsbereiche, zwei Domänen, die ich nicht miteinander vermischen möchte und deswegen habe ich da zwei Teams. Aber trotzdem muss das eine vielleicht mal auf das andere zugreifen, das Content erstellen wird abgerechnet oder beim Erstellen einer Rechnung möchte ich im Content Repository ablegen, was man da konstruieren kann. Auch da könnte es APIs zwischen diesen beiden Server Anwendungen geben. Das hätte dann nichts mit Frontend zu tun.

Lucas:

Gut, ich wollte das Beispiel nur einmal am Anfang erwähnen, weil es etwas ist, was bei zumindest bei vielen Leuten im Kopf ist, wenn sie an APIs denken.

Stefan:

Gerade heute, würde ich jetzt mal sagen. Das hast du insofern richtig generalisiert. Das ist ein ein schönes Beispiel dafür. Aber es gibt eben auch viele andere.

Lucas:

Okay, gut, wir haben ja am Anfang gesagt, irgendwie gibt es verschiedene Stile. Vielleicht kannst du erstmal deine groben Kategorien erst mal aufzählen, was du an Stilen kennst.

Stefan:

Also wahrscheinlich kann man hier ganz viele verschiedene Taxonomien wählen. Ich hätte jetzt mal so eine anzubieten, es gibt einen großen Block, eine große Familie von Dingen, die sich alle unter RPC oder RPC zusammenfassen lassen, Remote Procedure Call. Da gibt es einen ganzen Haufen von Dingen, so was wie PCE oder Sun RPC, alte Sachen oder SOAP, da gehört meistens RMI oder DCOM und so weiter und so fort. Dann gibt es HTTP Web APIs. Viele Leute nennen die REST APIs, aber ich teile es so ein bisschen auf. Ich sage erst mal HTTP Web APIs. Das sind APIs, bei denen HTTP verwendet wird und bei denen man HTTP Requests macht und HTTP Responses bekommt und sich dabei bemüht, relativ viel von HTTP richtig zu verwenden. So wie es von den Erfindern von HTTP gedacht war. Da gibt es eine andere Kategorie, die nenne ich dann tatsächlich REST APIs. Manche Leute sagen dazu Hypermedia APIs. Ich glaube, da musst du ein bisschen aufpassen, dass ich nicht zu sehr ins Quasseln gerate, sonst hört dieser Podcast nie mehr auf. Auf dem Unterschied können wir auch ein bisschen rumreiten, ein bisschen erklären. Ich finde aber, es sind tatsächlich zwei unterschiedliche Arten von API Design, die beide HTTP benutzen. Dann gibt es einen Stil, das im Moment häufig diskutiert wird oder eine Technologie, die häufig diskutiert wird. Das ist GraphQL, da können wir auch ein bisschen darüber reden. Und dann habe ich noch eine geheime Variante, die nennt sich Zero API, da reden wir dann vielleicht am Ende darüber, wenn wir noch Zeit haben.

Lucas:

Auf die du schon ein Patent angemeldet hast.

Stefan:

Ganz genau.

Lucas:

Dann beginnen wir doch mal mit dem, was du zuerst genannt hast, mit Remote Procedure Calls. Aus meiner Sicht würde ich mal sagen, ist das irgendwie das Älteste, von denen du vorgestellt hast. Ist das richtig?

Stefan:

Jein. Es gibt Dinge, die sind so klassisches Messaging, da würde man das praktisch oben drauf bauen. Es gab schon vorher Dinge, bei denen man bidirektionales Messaging zum Beispiel über so ein Duplex Kanal machen konnte und irgendwie eine Nachricht rübergeschickt, andere konsumiert. Aber relativ früh haben Leute angefangen, darauf so was wie RPC zu konstruieren. Ich möchte kurz erläutern, was das heißt. RPC bedeutet Remote Procedure Call und die Kernidee dabei ist, dass ich einen Prozeduraufruf oder ein Methodenaufruf oder einen Funktionsaufruf mache. Und dieser Funktionsaufruf fühlt sich für mich so an, als hätte ich einen normalen lokalen Funktionsaufruf gemacht, also genauso wie ich eine Methode eines Objektes oder eine implementierte Prozedur aufrufen kann, genauso kann ich das machen, wenn die Implementierung dieser Prozedur auf der anderen Seite einer Netzwerkverbindung liegt. Deswegen Remote Procedure Call. Und das ist etwas, das man sich, wenn man nur so ein Messaging System hat, also so einen synchronen Kommunikationskanal, über den man Nachrichten schicken und empfangen kann, dann baut man sich sowas relativ schnell selbst in der spezifischen Variante. Nehmen wir an, ich möchte gerne den Kontostand erfragen, der auf der anderen Seite gespeichert wird. Dann würde ich mir wahrscheinlich selbst eine Methode implementieren und eine Prozedur implementieren, die heißt GET Balance. Und in der Methode Get Balance würde ich dann eine Nachricht erstellen, die würde ich über die Leitung schicken, dann wird die Nachricht ausgepackt, interpretiert als: Aha, da will jemand den Kontostand und dann wird eine Antwort gebaut, da wird der Kontostand eingepackt, dann wird die Antwort zurückgeschickt. Und dann macht diese Funktion Get Balance ein Return mit diesem Wert, den sie bekommen hat. So würde wahrscheinlich mein Code auch aussehen, wenn ich keinen RPC Framework oder eine RPB Bibliothek hätte. Und die Idee von solchen Remote Procedure Call Ansätzen ist, das zu vereinfachen und es möglichst leicht zu machen, solche Wrapper Funktionen oder Wrapper Methoden oder Prozeduren zu erstellen, die mir verstecken, was da an Netzwerkkommunikation passiert. Das war die Client Sich darauf. Auf der Serversicht muss ich das auch haben. Da brauche ich eine Implementierung dieser Funktion Get Balance, also das Gegenstück sozusagen. Und die macht dann irgendwas, das kann das Tool nicht für mich generieren, aber es kann mir wiederum sozusagen diesen Wrapper generieren, der wie so ein Skeleton dient, wo ich dann so eine Implementierung habe, die bis auf die Geschäftslogik schon fertig ist. Die muss ich da noch reinpacken, aber das Messaging wird dann wieder von der Bibliothek und vom Tool übernommen.

Lucas:

Das bedeutet, da schreibe ich dann einfach eine Methode?

Stefan:

Es unterscheidet sich jetzt ein kleines bisschen. Es gibt natürlich ganz, ganz viele solcher Ansätze, vielleicht haben einige, die nicht so alt sind wie ich, das vielleicht relativ frisch auf dem Radar wegen der GRPC. Das ist Google, die aktuelle Google RPC Bibliothek. Aber es gibt es tatsächlich schon sehr lange. Und wie genau diese Dinge funktionieren, ist immer so ein kleines bisschen unterschiedlich, aber die meisten davon, stark vereinfacht gesagt, fordern, dass man die Schnittstelle, die man da gerne hätte, in Form einer Schnittstellenbeschreibungssprache mal formal hin schreibt. Ich öffne den Editor meiner Wahl. Ich erstelle eine IDL Datei mit irgendeinem Suffix, also einer Interface Description Language Datei. Die Formate heißen immer anders. Jedes Tool hat sein eigenes Vorgehen. Darin beschreibe ich, was ich alles gerne als logische Methoden hätte, nicht Implementierung, sondern nur Schnittstelle. Ich definiere, ich deklariere, ich schreibe die Signaturen der Methoden und dann werfe ich das in ein Tooling rein. Und dieses Tooling erzeugt mir Skeletons, also auf den beiden Seiten der Kommunikation sozusagen ein bisschen Code. Auf der Client-Seite ist das im Prinzip direkt aufrufbar. Also dieses Stub spricht dann vielleicht mit der Bibliothek, die mit dazugehört und verpackt mir die Nachrichten direkt und nimmt die Antwort, wenn es denn eine gibt und entpackt sie direkt. Also Client ist im Prinzip fertig und für die Serverseite wird mir so ein Skelett generiert, eine skeletthafte Implementierung, die muss ich noch füllen. Dafür greife ich auf die Datenbank zu oder auf mein Fallsystem oder auf ein Legacy System oder was auch immer meine Implementierung ist. Gebe das Ergebnis zurück und wiederum abhängig vom Werkzeug gibt es vielleicht noch irgendwelche Server Prozesse, irgendwelche Naming Services, alles mögliche an Zeug, aber im Prinzip ist die Kommunikation out of the box aus Entwickler:innensicht sehr einfach gestaltet, weil ich diese Schnittstellenbeschreibung habe und dann was generiere und dann fertig bin mit dem ganzen Zeug.

Lucas:

Okay, das klingt jetzt ein bisschen so, als müssten Client und Server in derselben Sprache geschrieben sein. Ist das so?

Stefan [00:12:29] Ne, das ist tatsächlich nicht so. Was tatsächlich eines der zentralen Versprechen all dieser Dinge, wenn es eine Implementierung dieses Toolings für verschiedene Sprachen gibt, eine Anwendung an verschiedene Sprachen können Client und Server in verschiedenen Sprachen implementiert sein. Und das ist tatsächlich sehr häufig der Fall. Der Server in einer typischen Sprache, in Java oder C++, Go oder C Sharp und der Client vielleicht in JavaScript oder in irgendwas anderem. Natürlich können sie auch die gleiche Sprache verwenden.

Lucas:

Okay, verstehe. Du hast eben eine Sache erwähnt, das würde ich gerne einmal kurz einschieben. Du hast über synchron und asynchron gesprochen. Ob eine API synchron oder asynchron ist, ist das abhängig von dieser Taxonomie oder ist das ein unabhängiger Faktor?

Stefan:

Das ist eine interessante und komplizierte Frage, weil wir so viele Begriffe da durcheinanderwerfen können. Das eine ist irgendwie Request/Response, also ist die Interaktion, bei der ich einen Request schicke und eine Response bekomme. Das zweite ist synchrone und asynchrone Verarbeitung. Wird die Verarbeitung asynchron durchgeführt und dann gibt es auch noch Blocking, Non-Blocking. Worüber wir hier typischerweise sprechen, sind unterschiedliche Arten der Verarbeitung, die der Client fühlt, das spielt bei unserer Diskussion jetzt eine größere Rolle als die darunterliegende Implementierung der Leitung. Und da gibt es verschiedene Varianten. Bei den Sachen, über die wir sprechen. Bei RPC denkt man typischerweise an so eine Request/Response-Interaktion. Ich schicke einen Request, bekomme eine Antwort zurück. Aber es gibt auch Varianten, bei denen ich einen Request schicke und gar keine Antwort erwarte. Ein Fire and Forget Ding. Es gibt andere, bei denen ich mehrere Antworten zurückbekomme bekomme. Ich schicke einen Request und bekomme dann ganz viele Antworten, eine nach der anderen, also so ein 1:n Ding. Es gibt welche, bei denen kann ich sagen: Ich möchte gerne informiert werden über X. Das ist mehr so ein Subscribe Modus. All diese Varianten gibt es. Und je nachdem, wie kompliziert wir es machen wollen, gibt es auch noch Implementierungen, die dann das Ganze auch noch versuchen zu abstrahieren, ob man unten drunter einen asynchronen Kommunikationsmechanismus hat oder nicht, also ob untendrunter die Kommunikation per Request/Response erfolgt oder zum Beispiel per Messaging Queue. Das ist aber in aller Regel ein zum Scheitern verurteiltes Unterfangen, weil man das nicht wirklich weg abstrahieren kann. Also irgendwie weiß man immer was unten drunter passiert oder nicht. Aber diese Welt ist so unglaublich groß. Also diese ganzen vielen Technologien, die über die Jahre entstanden sind, die sind so riesig. Deswegen lasst uns vielleicht lieber auf eine fokussieren. Zum Beispiel so was wie gRPC. Das ist das was im Moment ganz viele Leute damit assoziieren. Und bei gRPC ist es so, dass man typischerweise Request/Response Interaktionen macht, synchrone Request/Response-Interaktionen. Die laufen über HTTP/2. Also die werden durchaus effizient über HTTP/2 unter Nutzung dieses Binärprotokolls sozusagen gemacht. Benutzt ein effizientes Datenformat. Das ist ein Protocol Buffers, also jede dieser Technologien hat ihre eigene Art und Weise Daten zu serialisieren und zu deserialisieren. Und bei gRPC ist das Protocol Buffers, das könnte ich theoretisch auch für etwas anderes benutzen. Also das kann ich auch mit einem Web API benutzen, aber wenn ich gRPC benutze, kommt das sozusagen mit. Die IDL Datei heißt .proto. Also da definiere ich welche Request/Responses es gibt. Und es gibt auch so ein Streaming Support, wo ich im Prinzip, was ich gerade gesagt habe, zum Beispiel mir Antworten zurück streamen lassen kann, wenn ich mich irgendwo subscriben möchte. Das wäre dann eine moderne Implementierung von Ideen, die es schon eine ganze Weile gibt.

Lucas:

Genau, eine Idee davon hast du gerade noch mal kurz genannt, als Abkürzung, die wahrscheinlich nicht allen geläufig ist. Du hast IDL gesagt, was bedeutet das?

Stefan:

IDL ist diese Interface Definition Language. Ich habe es mal kurz erwähnt. In den meisten dieser Dinge beschreibe ich mein Interface in einer separaten Syntax, einer separaten Datei. Es gibt auch welche, die es anders machen, zum Beispiel RMI werden viele kennen. Das ist die Java Variante von Remote Procedure Call. RMI heißt Remote Method Invocation. Da wird einfach die Java Datei, also eine Java Interface Datei genommen und praktisch als IDL für diese Remote Kommunikation interpretiert. Das ist eine Implementierungsdetail und bei gRPC heißt die Interface Definition Language oder ist diese Datei diese Proto Datei.

Lucas:

Ich wollte das nur sicherstellen, dass alle wissen, was du da meinst. Gut, und wenn wir jetzt mal gRPC einfach als Beispiel nehmen, um die Komplexität von „jedes macht es ein bisschen“ anders rauszunehmen. Wo siehst du da die Vorteile von diesem Verfahren? Was ist gut daran?

Stefan:

Auch da müssten wir unterscheiden, weil man könnte zum Beispiel auch RPC über SOAP machen, da würde ich ganz andere Sachen sagen. Bei gRPC, als konkretes Beispiel, ist es so, dass es eine sehr effiziente Art ist, sowas zu machen. Ich kommuniziere sehr effizient mit Binärprotokoll über HTTP/2. Das ist ein guter Kompromiss zwischen Verfügbarkeit und Durchlässigkeit durch die Firewalls und Nutzbarkeit. Das ist eine gute Sache. Ich nutze meine Ressourcen sehr effizient. Ich kann das in ein systemnahen Programmiersprachen implementieren. Ich habe diese statische Schnittstellenbeschreibungssprache. Das mögen viele Leute sehr gerne, weil damit sehr klar beschrieben ist, was die Schnittstelle ist, gegen die ich da programmiere. Ich habe Support für verschiedene Programmiersprachen, den ich für das ganze benutzen kann. Also man könnte sagen, wenn ich so ein RPC Ansatz haben möchte, dann ist gRPC eine gute Wahl. Es ist eine gute moderne Implementierung dieses traditionell lang verfügbaren Ansatzes und adressiert auch ein paar Dinge, die oft Probleme machen in diesem RPC Umfeld. Zum Beispiel, mit einem zumindest begrenzt, Versions-Thema. Insofern bin ich kein Feind von gRPC, ich finde man muss sich überlegen in welchem Kontext, in welchem Szenario man das einsetzt.

Lucas:

Wollen wir das am Ende noch mal vergleichen, in welchen Szenarien du was benutzen würdest?

Stefan:

Das können wir gerne machen. Vielleicht kann man ganz kurz sagen, das habe ich auch schon angedeutet. Es gibt natürlich auch Nachteile von diesem RPC Ansatz und das ist wie so oft bei solchen Sachen, da kann man sagen: Diese statische Vertragssprache oder diese Contract Language, ist gleichzeitig Vorteil und Nachteil. Dieser statische Charakter sagt: Das ist das Interface, das ist das Interface, an das du dich halten musst. Das klingt erstmal total super, aber nur so lange, wie mein Client und mein Server genau zueinander passen. Wehe, die laufen auseinander. Das ist das Hauptproblem aller RPC Ansätze. Sie haben eine vom Grundsatz her deutlich engere Kopplung als Alternativen. Wiederum hängt es sehr vom Detail der jeweiligen Sache ab. gRPC gibt sich Mühe was zu machen. Da gibt es so Indizes, damit man zum Beispiel Änderungen in den Datenstrukturen zumindest zu einem gewissen Grad abfedern kann, wenn ein neues Feld dazukommt, aber dem Ganzen ist eine Grenze gesetzt und das liegt unter anderem auch daran, dass es so verführerisch ist. Also diese Remote Procedure Calls fühlen sich an wie Procedure Calls und auch das ist Fluch und Segen. Man spürt nicht so richtig, dass man da übers Netzwerk kommuniziert. Es fühlt sich so an, als ob man eine lokale Methode aufruft. Und noch schlimmer, wenn ich das auf meinem Rechner lokal mache, dann ist es auch fast so schnell, als ob ich eine lokale Methode aufrufe. Aber wehe, ich packe dann ein echtes Netzwerk dazwischen. Dann spüre ich das auf einmal sehr, dass der Call Faktor 100000 langsamer ist als ein lokaler Prozeduraufruf. Und das ist etwas, was häufig passiert. Man kann sich so vielleicht vorstellen. Im Prinzip ist alles was wir mit statischer Typisierung assoziieren, ist gebaut worden für Programme, die man zusammen linkt. Also ich habe da zwei Module, die passen super zueinander, die bilden ein Executable, ein Ding, das ich irgendwo laufen lasse. Aber sobald ich eine Netzwerkschnittstelle dazwischen habe, ist diese Annahme, dass das ein Ding ist, nur noch begrenzt gültig, weil ich das getrennt deployen kann. Also der Client kann schon neuer sein, der Server kann schon neuer sein. Der Client ist vielleicht eine iOS oder Android App auf einem Telefon, das gar nicht mehr upgraden kann. Früher gab es kein Problem. Wir rollen alle Clients, Server-seitig gemanagt über unser Software Verteilungsverfahren zum selben Zeitpunkt aus. Das klappt nicht so richtig super, wenn man in so einer dynamischeren Welt ist, wie es heute eigentlich üblich ist. Deswegen ist der Einsatzbereich vielleicht eher so eine Umgebung, die ich gemanagt habe. Ein schönes Beispiel ist: Kubernetes benutzt gRPC für die Kommunikation der Command Line Tools mit dem Kubernetes Cluster. Da ist das jetzt nicht so dramatisch, die werden nicht auseinander laufen, und wenn, dann muss ich eine neue Version der kleinen Tools installieren. Das ist ein Ding. Und dass die Google Leute oder die Leute, die Kubernetes bauen ist nicht nur Google, dass die intern gRPC benutzen, um effizient in dieser geclusterten Umgebung kommunizieren zu können, fair enough, habe ich überhaupt keine Einwände dagegen, finde ich einen guten Einsatzbereich. Für andere Einsatzbereiche sollte man vielleicht nochmal nachdenken.

Lucas:

Okay, aber das heißt, das mentale Modell ist, ich habe einfach irgendwelche Methoden, die ich aufrufen kann, kann ich mir vorstellen, wenn ich in meiner IDE und mal oder meinem Editor arbeite und ich ändere von einer Methode die Signatur, weil ich irgendwas hinzufüge beispielsweise, dann kann ich sehr einfach herausfinden: Wo sind alle Aufrufer und die anpassen. Und das ist der Punkt, der bei einem RPC Verfahren gar nicht mehr so einfach ist, oder?

Stefan:

Na ja, wie man es nimmt. Du hast einen Zwischenschritt. In deinem Beispiel müsstest du die IDL Datei, die Proto Datei, aktualisieren, würdest da die Methodensignatur ändern. Du würdest daraus den neuen Code für Client und Server generieren. Und dann wäre natürlich in deiner IDE die Stellen rot, an denen die Signatur nicht passt. Und das kann jetzt automatisiert in deiner IDE oder ist typischerweise automatisiert in deine IDE integriert und ist in deinem Bildprozess drin. Solange du Client und Server gleichzeitig baust, hast du kein Problem. Das Problem beginnt, wenn du nicht mehr weißt, ob deine Proto Datei die aktuelle ist. Wenn es zwei Teams sind, die sitzen auf zwei verschiedenen Kontinenten, in zwei verschiedenen Zeitzonen, dann muss irgendein Mechanismus gefunden werden, mit denen die Schnittstelle zwischen beiden synchron gehalten wird oder aber kompatibel gehalten.

Lucas:

Ja, verstehe. Okay, gut, dann lass uns das mal jetzt gegen HTTP Web API halten. Also erstmal was ist das und was hat das so für Eigenschaften?

Stefan:

Also in erster Näherung würde ich sagen, so ein HTTP Web API, wie ich das jetzt nenne, ist das, was die meisten Leute REST API nennen. Deswegen kennen das wahrscheinlich auch die meisten, weil das glaube ich mit großem Abstand im Moment der populärste API Stil ist. Wenn ich heute irgendeine Anwendung baue und ich möchte der eine API verpassen, das von möglichst vielen Leuten konsumiert werden kann, dann wird das so ein HTTP API sein. Und dass sieht typischerweise so aus, dass ich mir Gedanken darüber mache, welche Ressourcen oder manche Leute sagen, welche Endpoints es gibt also. Welche URLs oder URL Muster oder URL Templates habe ich so, da kann ich vielleicht unter /customers, /ID da kann ich einen Kunden abfragen oder mit einem Post auf /content kann ich ein neues Content Element erzeugen. Und typischerweise ist das eine Interaktion, die GET, PUT, POST, DELETE. Also die HTTP Verben benutzt und zwar so, wie sie von der HTTP Spec gedacht sind, benutzt zu werden. Das ist deswegen erwähnenswert, weil man das früher anders gemacht hat. Früher gab es sehr viele Ansätze, die HTTP so ein bisschen missbraucht haben oder nicht genutzt haben, je nachdem. Manche haben über HTTP GET, das ist eine Methode, die zum Lesen oder für sichere Dinge, typischerweise Lesen gedacht ist, benutzt, um Server zu starten oder herunterzufahren. Also solche Sachen sind heute relativ unüblich. Typischerweise würde man die lesenden Sachen mit irgendeinem GET machen. Man würde Dinge, die etwas aktualisieren mit einem PUT machen. Man würde Dinge, die etwas löschen, mit einem DELETE machen und etwas Neues anlegen oder eine beliebige Verarbeitung anstoßen mit einem POST. Wie so Töpfchen, wie so Kategorien, in die man Dinge einsortiert. Und diese Art der APIs ist sehr verbreitet, sehr üblich. Ich würde sagen, die meisten öffentlichen Internet APIs, zum Beispiel Programmableweb.com, das ist so eine Übersichtsseite, die listet ein paar Tausend APIs und 80, 90% davon sind genau diese Kategorie von HTTP Web APIs. Was ich auch noch sagen kann: Typischerweise gibt es dann irgendeine Form von Dokumentation zum Standard, das nennt sich Open APIs, hervorgegangen aus dem Swagger Kontext, den viele bestimmt kennen. Und da ist im Prinzip das, was ich gerade gesagt habe, diese URL Patterns mit dieser Methode und der Bedeutung, das ist da im Prinzip standardisiert. Ich habe so eine Beschreibung, eine maschinenlesbare Beschreibung, mit der ich relativ gut sehen kann, was es da alles so gibt, was in diesem API passiert. Und auch da gibt es einen Support, um zum Beispiel ein Code daraus zu generieren, aber vor allem auch, um diese Dokumentation möglichst gut navigierbar und darstellbar zu machen.

Lucas:

Okay, um noch mal auf diesen Browser Kontext einzugehen. Im Browser Kontext hat es auf jeden Fall schon mal den Vorteil, dass ich keine zusätzliche Library brauche, um damit umzugehen. Ich brauche jetzt nicht irgendeine RPC Library oder GraphQL Library, sondern grundsätzlich hat mein Browser alles, was er braucht, um damit zu interagieren.

Stefan:

Ich vermute, dass das auch der Haupttreiber für die Popularität ist. Es ist gerade aus JavaScript heraus extrem einfach zu konsumieren. Es ist auch sonst so einfach zu konsumieren, weil HTTP einfach ein so verbreiteter Standard ist. Es gibt keine Programmiersprache, wo es nicht eine Bibliothek gibt, mit der ich einfach mit HTTP interagieren kann, weil es offensichtlich eine Notwendigkeit ist. Was soll ich mit der Umgebung, mit der ich keine HTTP Requests abschicken oder verarbeiten kann? Dementsprechend ist das immer möglich. Ist es sozusagen vielleicht ein kleiner, kein kleinster, aber schon ein gemeinsamer Nenner, auf den sich alle einigen können. Und auch in den Welten, in denen das nicht so ist. Zum Beispiel, wenn ich gar keine Webanwendung baue, sondern vielleicht eine native iOS oder Android Anwendung oder eine Desktop Anwendung, ist das mittlerweile trotzdem einfach der Standard. Das machen eigentlich alle in den allermeisten Fällen, um möglichst einfaches Konsumieren durch möglichst viele unterschiedliche Clients zu ermöglichen.

Lucas:

Und dadurch, dass es irgendwie fast schon in jeder Standard Library von jeder Programmiersprache drin ist, kennt das auch einfach jeder. Das ist auch ein großer Vorteil. Da muss man die jetzt nicht noch mal kurz erklären, was HTTP ist. Das kann man meistens mal als gegeben voraussetzen. Okay, das wären auch jetzt schon für dich die Hauptvorteile oder siehst du da noch andere Vorteile, die dieses Verfahren hat?

Stefan:

Also Hauptvorteil ist die Ubiquität, also die Allgegenwärtigkeit von HTTP, aus meiner Sicht der größte Vorteil und als psychologischen oder politischen Vorteil kann man vielleicht noch nennen, dass man sich dafür niemals rechtfertigen muss. Und das bedeutet, du und ich, wir kennen das. Wenn man in Diskussionen, gerade in Architekturdiskussionen, in irgendwelchen Projekten ist, dann muss man einfach mit der eigenen Kapazität Kämpfe ausfechten und schonend umgehen. Und da freut man sich über jede Sache, bei der man nicht so viel diskutieren muss. Da ist es ein No Brainer. Ja, klar machen wir eine HTTP API. Fertig, das macht irgendwer und das klappt dann schon irgendwie. Das war früher mal deutlich anders. Ich erinnere mich an sehr, sehr heftige Grabenkämpfe zwischen der HTTP und Webservices Fraktion. Das lassen wir jetzt mal weg. Aber das war früher nicht so selbstverständlich und heute ist das ein weiterer Vorteil, würde ich sagen.

Lucas:

Das ist auf jeden Fall ein Vorteil. Siehst du da auch schon Nachteile?

Stefan:

Entschuldige, ich habe das jetzt nicht erwähnt. Ich muss das, um meinem Ruf gerecht zu werden. Natürlich hat HTTP da auch noch andere Vorteile, nämlich die bestehende Infrastruktur. Wir haben Proxys, Caches, es sind Firewalls offen. Ich kann Routing machen. Ich kann meinen Webserver benutzen, um eingehende HTTP Requests auf unterschiedliche Backends zu verteilen. Diese Allgegenwärtigkeit von HTTP drückt sich auch in einer Allgegenwärtigkeit von Infrastruktur aus, die HTTP unterstützt.

Lucas:

Und ich würde sogar noch ergänzen, dass viel von dieser Infrastruktur als Open Source Software vorliegt und auch kostenfrei verwendet werden kann.

Stefan:

Und zwar als sehr ausgereifte Open Source Software. So ein Ding, da muss ich nicht diskutieren, ob ein Webserver skaliert oder nicht. Das ist sehr bekannt, wie der skaliert und die Tatsache, dass unser Internet auf diesem Zeug beruht, ist relativ. Also unser Web darauf beruht, das ist ein relativ solider Qualitätsbeweis für das Ganze.

Lucas:

Und wer noch ein bisschen mehr über die ganzen Features von HTTP erfahren will, der kann auch noch mal unsere HTTP Folge hören. Die verlinken wir auch noch.

Stefan:

Eine großartige HTTP Folge.

Lucas:

Dankeschön.

Stefan:

Genau, nach Nachteilen hast du gerade gefragt. Also eine Sache, die man vielleicht sagen muss, es ist generell einfach ein generisches Applikationsprotokoll. Also HTTP ist kein Transportprotokoll, sondern HTTP ist ein Applikationsprotokoll. Das ist ein Vorteil, weil es diese generische Semantik hat. Das ist genau das, was wir gerade alles gesagt haben mit Infrastruktur, aber es ist immer auch ein Effizienznachteil gegenüber einem spezifischen Protokoll. Wenn ich ein spezifisches Protokoll entwerfen kann für irgendwas, dann ist das per Definition effizienter, als wenn ich ein generisches Protokoll benutze, um diese Sache zu lösen. Das ist einfach immer die Wahrheit. Wenn mir dieses letzte Quäntchen Effizienz unglaublich viel wert ist, dann werde ich kein HTTP API machen, sondern was Eigenes. Dann würde ich vielleicht sogar noch nicht mal so was wie gRPC benutzen, sondern noch eine Stufe unten drunter gehen. Aber vielleicht ist dann so was wie gRPC etwas, was ganz gut in der Mitte ist. In den meisten Fällen glaube ich, ist es nicht der Engpass. Also der Engpass ist eher das Netzwerk selbst, als wenn ich jetzt HTTP oder gRPC benutze. Aber das kann man definitiv als einen Nachteil nennen. Der vielleicht größere Nachteil aus meiner Sicht ist eigentlich weniger der Effizienz Teil, sondern das ein bisschen verschenkte Potenzial, weil das, was wir gerade genannt haben, nennen zwar viele Leute REST API, es ist aber tatsächlich kein REST API. Für ein REST API, das den Namen verdient, so sagt es zumindest der Mensch, der das Wort REST erfunden hat, die Dissertation dazu geschrieben hat, der gute Roy Fielding, damit es ein REST API ist, muss es Hypermedia-getrieben sein. Und das fehlt leider den allermeisten Web APIs. Die allermeisten Web APIs sehen so aus, wie wir es gerade beschrieben haben, mit diesen Strukturen. Und was ihnen im Prinzip fehlt, ist das, was das Web erst zum Web macht, also die Verbindung, die Hypermedia Verknüpfungen und Hypermedia Affordances, die Dynamik da reinbringen. Ich mache mal so ein Beispiel, wenn ich mit meinem iOS und Android Client, der der wird typischerweise nicht immer auf der allerneuesten Version sein, einfach weil Leute nicht immer auf der aktuellsten Version ihrer Applikationen sind, und manche es auch gar nicht mehr können, weil die Telefone die neue Version vielleicht gar nicht mehr unterstützen. Und das bedeutet, dass ich da eine gewisse Dynamik mir wünschen würde. Und eigentlich hat REST, also das REST Konzept darauf die Antwort, die kennt man aus HTML. Das sind dynamische Dinge, weil wenn ich zum Beispiel zu Amazon.com gehe oder Amazon.de oder irgendwas einkaufe, dann konstruiere ich auch nicht von Hand vorher irgendwie ein HTTP Request, sondern mein Browser macht das dynamisch und mein Browser bekommt mit jedem Request, mit jeder Response neue Dinge, die er als nächstes tun kann, neue Links, denen er folgen kann, neue Formulare, die er abschicken kann. Und so könnte meine iOS oder Android Anwendung auch funktionieren. Die könnte Request zum Server machen, es kommt eine Antwort zurück und in der Antwort stehen bestimmte Dinge, die sie dann als nächstes tun kann. Zum Beispiel bestimmten Links folgen und irgendwelche andere Features zu implementieren. Prinzip sind REST Clients ein bisschen mehr wie Browser als wie RPC Clients. Und dieses dynamische, das kostet natürlich was. Nichts ist umsonst. Es kostet einfach gegebenenfalls eine zusätzliche kleine Server Interaktion. Aber mit dieser zusätzlichen kleinen Server Interaktion kaufe ich mir sehr viel mehr Dynamik, weil zum Beispiel Features. Nehmen wir ein Beispiel, ich baue ein neues Feature ein. Das wäre in der RESTful Anwendung einfach ein neuer Link, der in unserem Antwortdokument zurückkommt. Und der Client, der diesen Link nicht kennt, der macht dann damit nichts, der geht aber auch nicht kaputt. Und ein Client, der diesen Link gerne hätte, um was zu machen, ihn aber nicht findet, weil er vielleicht mit dem alten Server spricht, der zeigt diese kleinen Funktionalitäten nicht an. Also diese Dynamik da rein zu bauen, die ist in der Regel eine Menge wert. Die ist gerade dann was wert, wenn ich für meine App und das ist bei iOS und Android alles noch in irgendeinem blöden App-Store rein muss, bevor sie aktualisiert wird. Also ich weiß nicht, 14 Tage Aktualisierungszyklen. Wenn ich nicht umgehen kann, indem ich sehr viel dynamischer Dinge mache, dann ist das möglicherweise eine Menge wert.

Lucas:

Verstehe. Und du hast jetzt schon angefangen, über den nächsten Teil zu sprechen, über REST und Hypermedia APIs. Ich glaube, man muss da immer noch einmal über den Elefanten im Raum sprechen. Woher kommt das denn? Du hast eben gesagt, viele nennen das REST API und jetzt sagst du: aber das ist gar keine REST API. Woher kommt das? Woran liegt das, dass da dieses Missverständnis existiert?

Stefan:

Also es ist einfach so, dass Dinge, die gut sind, oft nicht leicht sind. Es ist einfach schwieriger, ein gutes REST API zu bauen, als ein mittelgutes HTTP Web API. Und das ist umso mehr so, wenn der Mainstream dir das immer wieder erzählt. Und da gibt es einige Leute, die da immer argumentieren, so wie mich oder dich, andere Leute, die immer argumentieren, warum es viel besser wäre, ein ordentliches REST API zu machen. Aber solange das mühseliger ist, ein REST API zu machen, wird es immer Leute geben, die das wählen, was gut genug ist und dann bei dem HTTP Web API landen. Das heißt jetzt nicht, dass ich das besser finde. Ich stehe immer noch zu 100% dazu, dass ich von den Vorteilen von Hypermedia APIs, von echten REST APIs wirklich fundamental überzeugt bin. Ich glaube, das ist viel besser. Aber was soll ich sagen? Ich meine, das kann ich jetzt natürlich nicht in 20, 30 Jahre meines Lebens immer wieder darauf rumreiten. Ich bin sehr froh, dass diese HTTP Web APIs schon mal deutlich besser sind als die Katastrophen, die wir früher hatten. Dieses: Ich benutze GET, um irgendwas irgendwas Destruktives zu tun. Und wenn man an der einen oder anderen Stelle mal Hypermedia Elemente rein bekommt, weil sie da einen konkreten Vorteil bringen und weil jemand das gesehen hat, ist das okay. Oft ist es glaube ich eine Frage, dass die Leute das zumindest mal an einem konkreten Beispiel illustriert bekommen haben müssen. Und dann kann man es nutzen. Aber es ist eben nicht ganz so intuitiv und einfach. Und deswegen haben wir viel von diesen anderen APIs.

Lucas:

Es gibt auch bestimmte Dinge, die Leute mit REST APIs oder HTTP APIs verbinden als Nachteile. Also beispielsweise, dass man so viele Anfragen hintereinander machen muss. Und darauf würde ich gerne gleich erst eingehen, weil ich erst einmal auf diese Reaktion darauf eingehen würde. Das wäre für mich GraphQL. Kannst du mir erläutern, was GraphQL ist und was die Ziele davon sind?

Stefan:

Das ist echt schwer das zu tun, ohne jetzt auf das einzugehen, was du gerade als Stichwort gesagt hast. Okay, lassen wir es mal weg, machen wir gleich. Also GraphQL, muss man auch kurz erklären, ist eine von Facebook stammende Initiative, die eine bestimmte Art von Client/Server oder Consumer/Provider Interaktion versucht zu adressieren, nämlich eine, bei der der Consumer sehr stark bestimmt, welche Daten er bekommt. Also bei den APIs, von dem wir bis jetzt gesprochen haben, ist es so, dass typischerweise die Server Seite bestimmt, was genau dem Client zur Verfügung gestellt wird. Mal ist das generisch und mal ist es spezifisch, also individuell beschrieben. Aber irgendwie bestimmt der Server: Das sind die Dinge, die, du lieber Client bekommst. Das sind die Optionen, die ich dir anbiete. Suche dir davon was aus. Und GraphQL dreht das so ein bisschen um. Im Prinzip sind die anderen, als ob ich im Restaurant bin und da eine Speisekarte ist und GraphQL macht sozusagen den Gast zum Koch. Ich habe eine Schnittstelle, über die ich mit dem Server kommunizieren kann. Aber ich kann sehr klar bestimmen, was ich haben möchte. Und es funktioniert in dem GraphQL, Graph Query Language, eine Art generische Sprache zum Abfragen von Graphen anbietet. Es hat jetzt nicht weniger was mit Graphdatenbanken zu tun, sondern es ist eher die Idee, dass alles, was ich typischerweise auf der Serverseite so habe, sich auf so einen Graphen abbilden lässt. Das sind Kunden, an denen Adressen hängen, an denen möglicherweise Regionen hängen. Und dann gibt es am Kunden noch Produktkategorien und daran Produkte. Und das ist alles so wild miteinander verknüpft. Und was genau ich aus diesem großen Graph jetzt haben möchte, hängt sehr davon ab, was als Client gerade mein Bedürfnis ist und die Wurzel hat das Ganze in diesem, was wir ganz am Anfang der Folge schon mal diskutiert hat, nämlich diesen Client, diesem JavaScript-lastiger Client im Browser, der jetzt von der Serverseite irgendwas haben möchte und dabei abhängig von dem, was er gerade anzeigen möchte, sehr unterschiedliche Anforderungen hat. Mal will ich die Details mit, mal sollen die Details wegbleiben, mal will ich eine Master/Detail Beziehung komplett auflösen und mal will ich nur die Master-Seite anzeigen lassen. Ein bisschen ist es so, ganz abstrakt. Also QL ist schon mal zwei Drittel Ähnlichkeit wie bei SQL. Also da sage ich auch in meiner Abfrage, was genau ich haben möchte und bekomme das zurück. Und es ist Aufgabe der darunterliegenden oder dahinterliegenden Datenbank, der mir das möglichst effizient zur Verfügung zu stellen. Und so ähnlich funktioniert GraphQL auch. GraphQL geht über HTTP, also wird über HTTP ausgeliefert. Aber ich habe dieses etwas andere Client-seitige. Wer so was noch kennt, es gibt eine entfernte Ähnlichkeit zu so was wie OData, aber wirklich nur sehr entfernt. Auch da kann ich so einer spezifischen Syntax sagen, was ich haben möchte. Hier ist es so, dass ich nicht in der Query, als Query Parameter an meiner HTTP URI sage, was ich haben möchte. Dafür wäre das zu kompliziert, ich schicke so ein JSON hin. Das ist im Prinzip so eine Mischung aus Query und Query Example Syntax. Da sage ich, was ich gerne hätte. Und dann ist es Aufgabe des Servers, die richtigen Sachen zusammen zu suchen und mir das zurückzugeben und dabei ganz viele coole Features drin. Zum Beispiel gibt es automatischen Support für Paginierung, also das Durchscrollen durch ein großes Result Set. Ich hole immer so 20 und 20 und nochmal 20. Es gibt Subscriptions, wo ich sagen kann, ich habe hier eine Query geschickt und jetzt hätte ich bitte gerne Updates, wenn sich was ändert, was diese Query betrifft. Und dann gibt es zum Beispiel in manchen Tools auch Caching Support. Also habe ich eine Client Bibliothek, die holt sich, cached das lokal und macht so eine Subskription. Und wenn auf der Serverseite sich was ändert, dann wird auf der Client Seite das direkt aktualisiert.

Lucas:

Okay, aufgrund meiner Vorgeschichte muss ich natürlich auch immer kurz fragen. Brauche ich denn für GraphQL auch eine Graph Datenbank oder ist das nicht notwendig?

Stefan:

Nein, brauchst du nicht. Also man könnte sich alles mögliche vorstellen. GraphQL ist erstmal eine Spec, die kann alles mögliche auf der Serverseite haben. Und was sehr üblich ist, ist, dass man GraphQL benutzt, um auf bestehende Sachen zuzugreifen. Ich habe vielleicht eine API und dann habe ich da drüben noch eine Datenbank und da habe ich noch eine Legacy Anwendung, wo ich irgendwie mit was Proprietärem machen muss und da habe ich noch eine Standard Anwendung und dafür muss ich noch irgendwas bauen. Und all dieses Zeug, all diese unterschiedlichen Dinge aggregiere ich unter einem mit Tool Support selbstgebastelten Server, der dann dieses GraphQL Interface anbietet. Es gibt auch Tools wie zum Beispiel Content Management Systeme, die bieten sozusagen nativ GraphQL an und ich denke auch, wer es nicht weiß, will ich jetzt mal vermuten, dass Graphdatenbanken allein aus Marketinggründen bestimmt auch eine einfache Möglichkeit haben, GraphQL anzubieten. Aber theoretisch kann das auf allem Möglichen drauf sein und es gibt auch so einen serverseitiges Programmiermodell, wo ich Dinge dann einklinken kann, die das machen. Wir haben eine neue Folge aufgenommen für den CaSE Podcast, in dem wir beide auch drin sind, wo der Artur Ortega in sehr viel Detail mir beibringt, wie GraphQL funktioniert. Insofern sollten wir darauf verweisen für die Leute, die mehr Details gerne dazu hätten.

Lucas:

Das machen wir auf jeden Fall. Ich hatte schon so ein Thema so leicht ausgeklammert. Auf das will ich jetzt gerne eingehen. Wenn man sich so einen GraphQL Vortrag anschaut auf YouTube. Dann ist eine der Sachen, die da gesagt wird: REST APIs sind doof, weil dauernd kriege ich viel zu viele Daten zurück oder zu wenig Daten zurück. Und das ist das, was GraphQL löst. Was würdest du denn dazu sagen? Wie siehst du das?

Stefan:

Herr Doktor, Herr Doktor, es tut so weh, wenn ich mich mit dem Finger ins Auge steche. Dann tut das nicht. Ich meine, in gewisser Weise… Die Kritik ärgert mich immer sehr, weil das ein Straw Man Ding ist, so ein Strohmann Argument. Da wird im Prinzip eine schlechte Art von REST API genommen, um das Konzept grundsätzlich zu kritisieren. Dabei wäre das gar nicht nötig. Also ich bin auf Hörer und Hörerinnen Feedback gespannt. Ich glaube, ich habe mir alle Mühe gegeben, GraphQL sehr neutral zu schildern und das geht auch. Man kann erklären, was das ist und wozu das da ist, ohne zu behaupten: REST APIs sind alle bescheuert, weil da viel zu viele kleine Server Interaktionen stattfinden. Ob das nämlich so ist oder nicht, kommt darauf an, wie ich mein Rest API entworfen habe. Also wenn mein Client Bedürfnis ist: Ich möchte gerne einen bestimmten Anwendungsfall unterstützen, dann ist das REST API gut, wenn es diesen Anwendungsfall unterstützt. Und wenn es stattdessen nur viel fein granularen Fälle unterstützt und die nicht Clientseitig zusammenbauen muss, ist das natürlich eine Katastrophe. Aber das muss ich nicht tun. Ich kann auf der Server Seite mir überlegen, was braucht der Client und kann die Dinge in einen Kontext zusammenpacken. Also ein REST API, das sozusagen auf Zeilenbene einer normalisierten relationalen Datenbank HTTP Requests unterstützt, ist bescheuert und ganz sicher kein REST-API. Ich würde doch nicht ein Request zum Beispiel für jede Rechnungsposition oder jede Bestellposition machen, sondern für die ganze Rechnung, wenn das die Einheit meiner der Verarbeitung ist. Und wahrscheinlich würde ich, wenn ich eine Rechnung verarbeite, möchte ich wahrscheinlich auch den Rechnungsempfänger und vielleicht den Lieferanten und keine Ahnung was für Informationen. Also die Informationen, die ich brauche, um sinnvollerweise in diesem Kontext eine nächste Entscheidung zu treffen, die würde ich zurückliefern und inklusive der Hypermedia Affordances und das jetzt im nächsten Schritt zu tun. Und dann würde der Client sich eins davon greifen und den nächsten logischen Schritt machen. Da gibt es vielleicht verschiedene Pfade dadurch, weil man natürlich nicht jeden Fall mit derselben Ressource klären kann. Man kann absolut hocheffiziente, ganz tolle REST Interfaces entwerfen, für die diese Kritik überhaupt nicht gilt. Trotzdem gibt es Anwendungsfälle, bei denen vielleicht es anders ist. Ich habe das vorhin als Beispiel gesagt. Ein CMS, das ein natives GraphQL Interface hätte, klingt für mich wie eine coole Idee, weil das ist die Definition eines CMS, dass es nicht weiß, wie der Client das braucht. Also da kann ich mir durchaus vorstellen, dass ich das machen kann. Ich glaube, die Kritik kommt eigentlich aus einer ganz anderen Ecke, nämlich dass Leute ein Problem hatten mit einer seltsamen Dynamik zwischen Frontend und Backend Team und der Tatsache, dass das Frontend Team sich schneller bewegen konnte als das Backend Team sich bewegen konnte und das Backend Team deswegen nicht so schnell hinterher kam, die REST APIs zu ändern und das Client Team deswegen immer anfangen musste selbst Business Logik zu implementieren. Und das ist vielleicht der entscheidende Faktor. Wenn ich im Client Geschäftslogik implementieren will, dann ist eine generische Datenzugriffssprache wie GraphQL oder SQL eine coole Idee. Wenn ich für Clients keine Geschäftslogik implementieren möchte, dann ist das auch nicht das richtige Interface. Dann brauche ich einen Interface, das die Geschäftslogik auf dem Server versteckt. Beides sind gültige Anwendungsfälle und beide adressiere ich mit unterschiedlichen API Stilen und Werkzeug.

Lucas:

Also ein Beispiel was mir einfällt, wo eine größere Firma ihre API umgestellt hat von einer REST API, würde ich auch als REST API bezeichnen. Zu einer GraphQL API ist GitHub, die haben das gemacht und für die war eine der Anforderungen. Wir wissen gar nicht so genau, was die Leute mit unserer API machen. Also die könnten alles mögliche damit bauen von einem Issue Browser oder was auch immer. Die könnten da alles mögliche bauen. Wir wissen es einfach nicht und deswegen wollen wir denen einfach alle Möglichkeiten offen halten. Würdest du das als gutes Argument sehen, sich so was wie GraphQL anzuschauen oder ist diese Argumentation irgendwo falsch?

Stefan:

Also ich verstehe so ein sehr generisches API über einen sehr großen Haufen von Daten. Das kann ich irgendwie schon nachvollziehen, warum man sowas machen will. Auf der anderen Seite gibt es Dinge wie beim GitHub Beispiel. Ich habe keine Ahnung wie das da realisiert ist. So was wie ein Pull Request, das ist eher was Flow-orientiertes. Da geht es nicht um eine generische Abfrage beliebiger Daten, sondern da geht es einfach eher darum: Was kann ich jetzt im nächsten Schritt machen? Das finde ich eine sehr naheliegende Sache und das ist glaube ich, da schaue ich gerade darauf, können wir auch verlinken. Ich schaue auf die GitHub Reference für Pulls, für das Pulls-API und das sieht ehrlich gesagt aus wie ein REST API. Das könnten wir vielleicht im Nachgang noch mal näher angucken. Vielleicht liefern sie da auch immer noch beides. Das weiß ich nicht genau. Es ist einfach neu.

Lucas:

Es gibt noch die alte und die neue GraphQL API.

Stefan:

Genau, das könnte man mal vergleichen. Da hätten wir vielleicht im Vorhinein tun sollen, aber sonst können wir das auch verlinken. Und dann kann man sich als Hörerin und Hörer mal anschauen, wie die “alte” Version mit dem REST API aussieht und die neue Version mit GraphQL.

Lucas:

Wir hätten es vorbereiten können, wenn ich vorher dran gedacht hätte. Okay, gut, aber das ist auf jeden Fall schon mal eine gute Übersicht, die beiden gegenüberzustellen. Also für dich ist es auf jeden Fall jetzt nicht so, dass GraphQL gar keinen Platz hat. Aber du würdest sagen, dass es manchmal mit der falschen Argumentation bevorzugt wird.

Stefan:

Also ich glaube tatsächlich, dass es in vielen Fällen mit der falschen Argumentation bevorzugt wird und auch zu einem ganz gruseligen Ergebnis führt, wenn man es einmal benutzt hat. Also erstmal ist es eine Menge Komplexität. Gerade wenn man es mit so einem HTTP Web API vergleichen, sind es einfach viel mehr bewegliche Teile, viel mehr Komplexität, viel mehr Dinge da drin, glaube ich. Es ist so, dass ich das Risiko eingehe, dass meine Clients sehr viel stärker an meinen Server gekoppelt werden. Auch wenn das erst mal nicht intuitiv klingt, glaube ich, dass das Exponieren von Daten und Datenstrukturen in so großem Maße mehr Kontrolle an den Client delegiert. Und das bedeutet, dass der Server mehr die Dinge konstant halten muss, konstant halten müsste, wenn er mehr geschätzte Logik auf seiner Seite hätte. Und generell bin ich der Meinung, dass in den allermeisten Fällen die Geschäftslogik zu 100% auf den Server gehört, auf den Provider und nicht in den Aufrufer irgendeines APIs. Aber wenn ich die Geschäftslogik hinter dem API habe, dann ist das auch die Stelle, an der ich sie zentral ändern kann, ohne dass ich alle aktualisieren muss. Ich glaube, es gibt sehr gute Argumente dagegen. Aber das gilt nicht immer. Einfache Antworten gibt es nicht. Alles, was wir jetzt gesagt haben, gRPC, die Web APIs, die REST APIs und die GraphQL haben alle ihren Platz in unterschiedlichen Kontexten.

Lucas:

Aber ich würde trotzdem gerne nochmal im Vergleich gerade von diesen dreien, also gRPC, REST und GraphQL noch mal auf Kopplung eingehen. Wie ordnest du die im Bereich der Kopplung ein? Wer ist am meisten gekoppelt, wer ist am losesten gekoppelt?

Stefan:

Also ich würde sagen, am engsten gekoppelt ist gRPC. Für mich gar keine Frage. Ich habe diesen statischen Contract. Ich habe diese Codegenerierung, klar ein bisschen was mit Versionen, aber das ist nicht das primäre Ziel von gRPC, ist es nicht ein, einen zwei Jahre alten Client mit den aktuellen Versionen irgendwie von irgendwas laufen zu lassen. Das ist für mich aber nicht schlimm. Das ist nun mal so. Es hat einen Ansatz. Es ist für mich total okay, wenn Effizienz wichtiger ist, wenn ich eigentlich Client und Server in einer Hand habe, vielleicht bei einem Team oder zwei sehr eng zusammenarbeiten in Teams finde ich das total in Ordnung. Es passt viel mehr zu einem Produkt, also zu einem Produkt, wenn kleine Server Teil eines Produkts sind, als es zu einer API Economy Vision passt. Wenn ich verschiedenste Leute habe, die so ein API nutzen. Das ist aus meiner Sicht nicht die Stärke. Vielleicht noch eingeschränkt in dem Fall, wo die Server Seite, also je nach API definiert, extrem übermächtig ist gegenüber den Clients, aber auch da, das für mich nur eine Performance Optimierung, bei der ich mir sehr genau überlegen sollte, ob ich die brauche oder nicht. Und wenn, dann ist das total in Ordnung. Warum nicht? Es gibt doch noch andere, Thrift oder so. Man kann ganz viele solche Ansätze sich anschauen, die alle so ähnlich funktionieren. Die sind alle für solche Dinge okay. Würde ich so was bauen zum Beispiel, wenn ich vielleicht den Administrations Client meines Datenbank Servers, wo ich das so sage, selbst da bin ich mir nicht sicher, ob ich das benutzen würde. Aber okay. Die lose gekoppelste Variante mit riesigem Abstand ist aus meiner Sicht die REST API Variante und lose Kopplung kostet mich was. Das heißt, die hat einen gewissen Overhead zur Laufzeit und für diesen Overhead oder mit diesem Preis dieses Overheads kaufe ich mir eine extrem lose Kopplung. Und das gilt insbesondere dann, wenn ich eine spezifische Logik exponieren möchte. Also immer in dem Fall, in dem klassische Business Services habe oder klassische Serverseitige Geschäftslogik, die ich mit einem API exponieren möchte, mit höchstmöglicher Kompatibilität und Evolutionsfähigkeit, also der Fähigkeit, sich weiterzuentwickeln, sehr unterschiedliche Clients zu unterstützen, mit unterschiedlichen Release Dates und einen sauberen Weg in Zukunft zu haben, ist das ein super Ding und mein Beleg dafür ist, dass das Web so funktioniert. Also das, was gewählt wurde, um beliebige Websites auf der Welt mit dem Browser zu verbinden, ist genau dieses REST Zeug. Und das ist nicht abgelöst durch irgendwas anderes. Das ist für mich das zentrale, entscheidende Ding. Und in vielen Fällen ist das eine sehr gute Lösung. Die GraphQL Geschichte ist aus meiner Sicht eine spezifische Lösung für den Fall, indem ich ein extrem generisches API brauche. Man könnte sagen, in gewisser Weise ist das einfach der generelle Regler. Noch mal eine Stufe weiter geregelt als bei HTTP. Bei HTTP habe ich gesagt, das gibt diese Töpfchen, GET, PUT, POST, DELETE. Diese Methodensemantik und dieses Generische und GraphQL sagt einfach: Wir packen außerdem auch noch irgendwie an, wir haben drei Töpfchen, also die haben Lesende und Schreibende und Subscription. Also Lesen-Dinge, mutierende Dinge und Subscription Geschichten. Das sind die drei Töpfe. Aber außerdem haben wir auch noch eine generische Datenstruktur und eine generische Abfragesprache. Und das macht es extrem generisch. Und das führt dazu, dass ich, weil ich noch mehr Generic habe, eben in diesem Fall mehr auf dem Client machen muss.

Lucas:

Okay, das war doch nur ein guter Vergleich direkt von all diesen Ansätzen. Du hast am Anfang noch eine sehr spannende Sache gesagt.

Stefan:

Ich bin gespannt, wie viel Kontra wir dazu bekommen, aber das sind immer sehr interessante Diskussionen.

Lucas:

Auf jeden Fall. Ich freue mich auch über Kontra. Ihr dürft gerne sagen, was ihr falsch findet. Und auf eine Sache möchte ich noch darauf zurückkommen, weil du die am Anfang einmal gesagt hast mit dem Frontend und Backend Team, dass du vielleicht gar nicht so einen Frontend und was in React oder was auch immer gebaut ist und was eingebaut ist, als gar nicht so ein gutes Beispiel betrachtest. Magst du darauf noch mal kurz eingehen?

Stefan:

Passt gut. Ich hatte am Anfang auch den Hint fallen lassen, dass ich diese Zero API noch als tolle Lösung habe. Und das ist natürlich ein doofer Witz. Es soll einfach heißen kein API zu bauen ist manchmal die beste Lösung. Und das passt natürlich super, weil mittlerweile reagiere ich echt allergisch auf die Begriffe Frontend und Backend Team. Mittlerweile würde ich behaupten, Frontend und Backend Teams sind ein Anti-Pattern oder ein Organisations-Smell. Frontend und Backend ist fast immer eine bescheuerte Idee, weil es fast immer bedeutet, dass ich etwas, was eigentlich Implementierung und Architektur-Implementierungsdetail sein sollte, auf einmal zu dem Organisationsding mache, also eine schlimmere Vernetzung von Conway’s Law kann man sich eigentlich kaum vorstellen. Als erstes Mal sorge ich dafür, dass es nichts Interessantes gibt, was von einem Team implementiert werden könnte. Alles, was interessant ist, erfordert immer eine Synchronisation zwischen zwei Teams. In aller Regel ist das eine blöde Entscheidung. Also solche absoluten Aussagen sollte man nie treffen. Manchmal ist es eine gute Entscheidung, aber viel öfter als man denkt, ist es eine schlechte. Und ich bin mittlerweile fest davon überzeugt, dass es sehr viel klüger ist, Teams anders zu schneiden, nicht eben horizontal in Frontend und Backend Team zu schneiden, sondern vertikal in das Team, das sich ums Accounting kümmert. Das Team, das sich um CMS kümmert, das Team, das sich um Order Management kümmert und das Team, das sich um den Produktkatalog kümmert. Und diese Teams, die sollten Ende zu Ende Verantwortung haben. Von ganz oben bis ganz unten, also vom UI bis runter zur Datenbank. Und dann ergibt sich auf einmal die Frage: Wozu genau brauche ich jetzt ein API? Was genau ist das API, von dem ich da spreche? Also es gibt in Webanwendungen und auch in eigentlich allen interessanten Anwendungen heute die, die auch den die nativen Teil haben, gibt es immer eine Netzwerk Strecke, die ist irgendwie schon da. Aber gerade bei einer Webanwendung ist es so, dass es eigentlich ein bestehendes Protokoll gibt und einen bestehenden Client gibt. Der Client heißt Browser. Das bestehende Protokoll heißt HTTP, es ist sogar schon REST API. Das ist nämlich HTML, ein Hypermedia. Es ist alles schon da. Ich muss es nicht alles gar nicht neu erfinden. Ich könnte auch einfach eine ordentliche Webanwendung bauen und darauf verzichten, für alles eine API einzuziehen, weil so ein API habe ich kostenlos. Also all diese Sachen, die wir gerade diskutiert haben, sind alle cool, machen alle Spaß. Es ist nett und eine intellektuell stimulierende Sache, ein schickes und gutes API zu entwerfen, noch Zeit sparen, da ist es, kein API zu entwerfen. Und wenn ich sage, ich habe eine Sicht, ich muss mein Produktkatalog darstellen, dann könnte ich einfach dafür sorgen, dass ich zum Beispiel auf der Serverseite HTML erzeuge, das aus dem Produktkatalog generiert wird. Da habe ich hoffentlich eine modulare Struktur, da habe ich vielleicht eine Schichten Architektur oder Innenarchitektur, mit der ich sozusagen meine Software Modular gestalte. Aber wer sagt, dass da noch mal eine Netzwerk-, dass eine Schicht dazwischen sein muss? Was soll das? Das eine Netzwerk reicht doch, um die Performance runter zu ziehen. Warum soll ich das noch schlimmer machen auf der Serverseite? Ich könnte einfach eine ordentliche Webanwendung bauen und dann wäre ich vielleicht schon fertig und dann würde ich vielleicht eine API für die Dinge bauen, die nicht in dieser Säule, in dieser Vertikale realisiert werden. Also wenn es jetzt andere Teams gibt, die von mir auch irgendwas brauchen und die dazu nicht auf mich verlinken können oder auf mich verweisen können, sondern die wirklich vielleicht irgendwas brauchen, den gebe ich ein API, aber dann ist mein API auf einmal nur noch ein Hundertstel von dem, was ich machen müsste, wenn ich einfach beschließe, dass alles immer über so ein API laufen muss. Also dieses: Ich muss so ein API in der Mitte haben, das so mitten durchgeht. Das empfinde ich als viel zu kurz und viel zu schnell schon in Richtung Lösung gedacht. Also manchmal ist das die richtige Lösung, manchmal sollte man genau das machen, aber keinesfalls ist das ein No Brainer und etwas, was immer die richtige Antwort ist.

Lucas:

Super cool! Dann danke ich dir, Stefan. Fand ich ein super Überblick über das ganze Thema. Wenn wir nicht noch irgendwas vergessen haben, würde ich sagen machen wir an der Stelle Ende.

Stefan:

Ja, finde ich auch.

Lucas:

Super. Gut, dann sage ich mal den Hörerinnen und Hörern, bis zum nächsten Mal und dir auch. Vielen Dank!

Stefan:

Vielen Dank, Lucas! Bis bald, ciao, tschüss!