GraphQL: Die Flitterwochen im Enterprise sind vorbei
(johnjames.blog)- GraphQL versucht, das Problem des Overfetching zu lösen, aber in den meisten Enterprise-Umgebungen wurde dieses Problem bereits auf andere Weise gelöst
- In Unternehmenssystemen, in denen eine BFF-Architektur (Backend for Frontend) verbreitet ist, schrumpfen die wichtigsten Vorteile von GraphQL erheblich
- Durch Implementierungskomplexität, geringere Observability, Caching-Probleme, ID-Einschränkungen und umständliche Dateiverarbeitung steigen die Kosten im realen Betrieb deutlich
- REST ist einfach und schnell, und Fehlerbehandlung sowie Onboarding sind leichter, was es in großen Teamumgebungen effizienter macht
- Fazit: GraphQL ist in bestimmten Situationen nützlich, für die meisten Enterprise-Anwendungen aber eine überzogene Wahl
Das Problem, das GraphQL lösen will
- Das Kernziel von GraphQL ist die Vermeidung von Overfetching (unnötig übermäßige Datenabfragen)
- Clients fordern nur die Felder an, die sie benötigen, wodurch unnötige Datenübertragung reduziert wird
- Ein Vorteil ist, dass nicht bei jeder neuen UI-Anforderung Änderungen am Backend nötig sind
- In der Praxis passt dieses Idealbild jedoch nicht zur komplexen Realität
Overfetching ist durch BFF oft bereits gelöst
- Die meisten Enterprise-Frontends verwenden bereits eine BFF-Schicht (Backend for Frontend)
- Sie kombiniert Daten passend zur UI, bündelt mehrere Downstream-Aufrufe und verbirgt Backend-Komplexität
- Ein REST-basiertes BFF kann bereits nur die benötigten Daten zurückgeben, wodurch sich der Vorteil von GraphQL doppelt
- Wenn eine GraphQL-Schicht Daten aus einer REST-API holt, wandert das Overfetching lediglich eine Ebene nach unten
- GraphQL kann nützlich sein, wenn mehrere Seiten denselben Endpunkt gemeinsam nutzen, aber
- dieser Vorteil bedeutet oft nur, für ein paar eingesparte Kilobyte deutlich mehr Einrichtungs- und Wartungsaufwand in Kauf zu nehmen
Implementierungskomplexität und sinkende Produktivität
- GraphQL ist im Vergleich zu REST deutlich aufwendiger und komplexer in der Implementierung
- Zusätzliche Arbeit für Schema, Typen, Resolver und die Definition von Datenquellen ist erforderlich
- Außerdem entsteht Aufwand, Schema und Client synchron zu halten
- GraphQL optimiert den Konsum (Bequemlichkeit für Clients), opfert dafür aber die Produktion (Geschwindigkeit der Serverentwicklung)
- In Enterprise-Umgebungen sind Entwicklungsgeschwindigkeit und Einfachheit wichtiger
Probleme bei Observability und Monitoring
- Das HTTP-Statuscode-System von GraphQL ist inkonsistent
- Selbst in einer 200-Antwort können Fehler enthalten sein, was die Unterscheidung von Erfolg und Misserfolg im Monitoring erschwert
- REST ist durch 2XX/4XX/5XX klar getrennt, wodurch Dashboard-Filterung intuitiv bleibt
- Mit Apollo und ähnlichen Tools lässt sich das anpassen, aber das verursacht zusätzliche Konfiguration und mentale Belastung
- Bei der Reaktion auf Störungen im Betrieb ist es schwieriger und komplexer, Probleme zu identifizieren als bei REST
Praktische Grenzen des Cachings
- Das normalized caching von Apollo ist theoretisch stark, in der Praxis jedoch fragil und komplex
- Selbst Queries, die sich nur in einem einzigen Feld unterscheiden, werden separat behandelt und müssen manuell verknüpft werden
- Cache-Debugging wird schnell zu einem eigenen Problemfeld
- REST kann dagegen einfach die vollständige Antwort cachen und ist dadurch stabiler und leichter wartbar
Das Problem mit ID-Feld-Einschränkungen
- Apollo geht davon aus, dass alle Objekte ein Feld id oder _id besitzen
- Viele Enterprise-APIs haben jedoch keine eindeutigen IDs oder keine globalen Identifikatoren
- Um das auszugleichen, muss das BFF Logik zur Erzeugung lokaler IDs hinzufügen
- Das führt letztlich zu mehr unnötigen Feldern und zusätzlicher Logik, wodurch der Nutzen gegen Overfetching geschmälert wird
Ineffizienz bei Datei-Uploads und -Downloads
- GraphQL ist für die Verarbeitung binärer Daten ungeeignet
- In der Praxis wird meist nur eine Download-URL zurückgegeben, während die Datei selbst per REST übertragen wird
- Wenn große Datenmengen wie PDFs in GraphQL-Antworten eingebettet werden, führt das zu Leistungseinbußen
- Dadurch zerbricht das GraphQL-Ideal einer „einzigen API“
Onboarding und Lernkurve
- Die meisten Entwickler haben viel REST-Erfahrung, GraphQL muss dagegen erst gelernt werden
- Es müssen neue Konzepte wie Schema, Resolver, Query-Aufbau, Caching-Regeln und Fehlerbehandlung erlernt werden
- Dadurch verlangsamt sich das Onboarding im Team
- REST ist als „langweilige, aber hochskalierbare“ Herangehensweise für große Teams besser geeignet
Komplexität der Fehlerbehandlung
- Fehlerantworten in GraphQL sind komplex durch nullable Felder, partial data, ein
errors-Array und erweiterte Statuscodes- Zusätzlich muss nachverfolgt werden, welcher Resolver fehlgeschlagen ist
- REST trennt dies einfach über 400/500 und ist dadurch leichter zu verstehen und zu debuggen
Fazit: GraphQL ist eine Nischentechnologie
- GraphQL ist in bestimmten Situationen ein sinnvolles Werkzeug
- In den meisten Enterprise-Umgebungen wurden die Probleme jedoch bereits mit BFF und REST gelöst
- Die eigentlichen Hauptthemen sind nicht Overfetching, sondern Observability, Zuverlässigkeit und Geschwindigkeit
- Letztlich löst GraphQL ein eng umrissenes Problem und verursacht dabei breitere Komplexität
- Das Fazit lautet: „GraphQL ist nicht schlecht, aber in den meisten Fällen nicht notwendig“
2 Kommentare
Hacker-News-Kommentare
Ich stimme nicht zu, dass das Hauptproblem von GraphQL Overfetching sei
Für mich liegen die eigentlichen Vorteile darin, dass es (a) strikte typbasierte Verträge erzwingt und (b) die Schema-Evolution deutlich einfacher macht
Dank des Typsystems folgen Ein- und Ausgaben immer einer definierten Form, und mit benutzerdefinierten Skalar-Typen (z. B. Telefonnummern, E-Mail-Adressen usw.) lassen sich Bugs und Sicherheitsprobleme stark reduzieren
Außerdem ist das Hinzufügen neuer Felder oder das Ausmustern bestehender Felder standardisiert, sodass sowohl auf Server- als auch auf Client-Seite die kognitive Last geringer ist
Ich nutze GraphQL wegen API-Komposition und Evolution. Gerade in großen Systemen mit M:N-Strukturen ist der Ablauf „Client beschreibt, was er braucht → Server komponiert → Domain-Services lösen es“ langfristig viel leichter zu warten
In Kombination mit guter Observability wird das zu einer starken Grundlage für den Datenzugriff
Ein weiterer Punkt ist, dass Resolver-Wiederverwendung und Federation einfach sind. In REST ist das ziemlich umständlich
Die Schema-Evolution wird auch von Protobuf gut gehandhabt
Der eigentliche Vorteil von GraphQL ist, dass sich UI-Daten aus kleinen Bausteinen zusammensetzen lassen
Nutzt man wie in diesem Video Fragment-Colocation, wirken sich Änderungen an untergeordneten Komponenten nicht auf andere Teile aus
Da Queries automatisch auf Basis von Fragmenten erzeugt werden, sinkt auch das Risiko, dass andere Komponenten beim Entfernen eines Feldes kaputtgehen
Wenn das System klein ist oder schnelle Entwicklung nicht so wichtig, kann GraphQL wie eine Überinvestition wirken
Colocation ist wirklich ein revolutionäres Konzept, aber Apollo hat es fast nie erwähnt
Die Dokumentation von Relay ist zwar weiterhin schwach, aber das Entrypoint-Konzept ist großartig
Allerdings ist die Implementierung von graphql-codegen bei der Plugin-Kompatibilität schwach, sodass wir eigene Plugins schreiben mussten
Im gesamten Ökosystem fehlt es an Konsistenz
Zu sagen, Overfetching sei das Kernproblem von GraphQL, ist übertrieben
Ich sehe GraphQL als ein Werkzeug, das die Impedanzfehlanpassung auf Client-Ebene behandelt, die ORMs auf ihrer Ebene lösen
Es ohne compilerbasierte Tooling wie Relay zu verwenden, ist ein Anti-Pattern
Da KI heute die Data-Layer automatisch generiert, scheint der Bedarf an GraphQL zu sinken
Die Developer Experience (DevEx) ist hervorragend, etwa weil nicht existierende Felder automatisch erzeugt werden
Die Verlangsamung des modernen Webs kommt größtenteils von zu viel übertragener Datenmenge. Tatsächlich arbeiten viele Apps mit weniger als 0,5 % Effizienz
Ich nutze GraphQL seit 2016
Im Kern ist GraphQL eine RPC-Spezifikation. Auf dem Server wird es als Mapping „Action(Args) → ResultType“ implementiert
Statt vieler Endpunkte wie bei REST arbeitet GraphQL über einen einzigen
/query-Endpunkt mit einer Resolver-MapIm Ergebnis ist es also eine Struktur, bei der wie bei OpenAPI oder gRPC Ein- und Ausgaben typisiert definiert sind
Apollo ist mit Fragment Masking etwas besser geworden, aber ein Relay-zentriertes Denken bleibt wichtig
und das Backend diese in eine einzige SQL-Abfrage übersetzt und verarbeitet
Resolver sollte man nur ausnahmsweise für Daten verwenden, die sich nicht direkt aus der DB holen lassen
Als ich früher ein Team leitete, wollte das FE GraphQL, also haben wir es eingeführt
Am Ende holte jede Seite alle Daten über eine einzige riesige Query, und bei Änderungen wurde der gesamte JSON-Blob erneut gesendet
Die App lief zwar, aber am Ende pivotierte das Unternehmen, und der Code verschwand
In der Praxis enden viele GraphQL-Projekte offenbar als Implementierungen, die nur formal so aussehen
Der Auth-Flow von GraphQL ist eine der größten Herausforderungen
Weil Resolver in verschiedenen Kontexten aufgerufen werden, muss man alle Fälle berücksichtigen
Die Komplexität und die Denk-Kosten sind so hoch, dass man am Ende Felder sperrt
Ich habe selbst graphql-autharoo gebaut, aber das reichte nicht aus
Die meisten Funktionen lassen sich auch ohne GraphQL einfacher umsetzen
Da für jede GraphQL-Ressource granulare Berechtigungen ergänzt werden müssen, funktionieren Queries nicht, bis die gesamte Ressource aktualisiert wurde
Die Belastung ist so groß, dass man fast sagt: „Man sollte es lieber wieder als REST bauen“
Statt alles selbst zu komponieren, ist es meiner Meinung nach besser, ein ausgereiftes Server-Framework zu verwenden
GraphQL sieht oberflächlich gut aus, ist in der Praxis aber eine Technologie, die mit der Zeit immer schwerer zu warten ist
Wie bei vielen Technologien lautet die Lehre am Ende: Ein Rad ist eben nur ein Rad
Der Vorteil von GraphQL ist, dass man im Schema einfach nur Felder ergänzt und alle Clients sie sofort abfragen können
Dadurch verschwinden FE-Anfragen wie „Bitte fügt dieses Feld auch noch hinzu“, und die Zusammenarbeit wird einfacher
Außerdem ist es leicht, Schema-Snapshots zu erzeugen und Änderungen in Integrationstests zu erkennen
Für mich wirkte es konsistenter als REST, aber das ist nur persönliche Erfahrung
Weil sich Anfragen kaskadierend von A bis E stellen lassen, verschärfen sich Performance-Probleme und die Kopplung zwischen Frontend und Datenstruktur
Auch React setzt inzwischen standardmäßig auf frameworkbasiertes SSR und Server Components
Am Ende bewegt sich alles in die Richtung, dass TypeScript Client und Server zusammenführt
Ich frage mich, wie GraphQL Probleme wie DB-Last oder ineffiziente Queries verhindert
Könnten bösartige Queries den internen Zustand nicht explodieren lassen?
REST ist mir zu langweilig geworden, deshalb probiere ich GraphQL aus
Mir gefällt, dass sich Server und Client schon zur Compile-Zeit über Request und Response abstimmen können
Ich wünschte, Blogs würden nicht nur sagen „Das ist nicht gut“, sondern auch Alternative Technologien nennen
Beide Technologien lösen das Problem des Client-Server-Vertrags sehr gut
Es mag Vor- und Nachteile geben, aber es wirkt besser, Daten und Zugriffskontrolle auf Schema-Ebene zu entwerfen, als jedes Mal, wenn man etwas hinzufügt, es in der REST API ergänzen zu müssen und später am Ende doch alles zurückzugeben. Die Nachteile sind klar, aber die Vorteile eben auch, haha.