GraphQL: ein wichtiger Schritt für Headless Magento 2

Was ist GraphQL?

GraphQL ist ein API-Standard, ähnlich wie REST oder SOAP. Die GraphQL-Spezifikation definiert eine Abfragesprache („query language“) und ein Typen-System („type system“). Man kann damit Lese- und Schreib-Abfragen in Programmiersprachen-neutraler Weise schreiben. In vielen Anwendungsfällen ist es ein potentieller Nachfolger für REST oder selbstgebaute nicht-standardisierte Webservice-Architekturen. Aufgrund seiner Vorteile ist es besonders für den Einsatz in Web-Applikationen, zum Beispiel Online-Shops attraktiv.

Facebook entwickelte GraphQL ursprünglich 2012 intern für die Verbesserung der mobilen Anwendungen. 2015 wurde es als Open Source veröffentlicht. Seitdem erfreut sich die Technologie stark steigender Beliebtheit. Zu den Unternehmen, die GraphQL verwenden (Stand Ende 2018) zählen unter anderem Facebook, GitHub, Shopify, Twitter, Yelp, WordPress und The New York Times.

Um das Commitment zu GraphQL zu festigen (und vielleicht auch, um die Abhängigkeit von Facebook zu verringern, haben Branchen-Größen hinter GraphQL wie Audi, CNBC, GitHub, Netflix, Shopify, The New York Times, Twitter, Pinterest und Help eine Foundation gegründet, um GraphQL ein offenes und neutrales Zuhause zu bieten und die Verbreitung von GraphQL zu fördern.

Warum ist GraphQL beliebt?

GraphQL erlebt spätestens seit 2018 einen Hype in der EntwicklerInnen-Szene. Die Vorteile bedeuten nicht nur mehr Komfort für die Developer. Auch Unternehmen profitieren, weil sich Web-Anwendungen damit schneller entwickeln lassen und günstiger im Betrieb sind.

Vorteile

Die folgende Liste enthält vor allem technische Details. Sie wirken sich direkt auf betriebliche und wirtschaftliche Vorteile aus.

Datensparsamkeit

Bei REST kann man sich nicht aussuchen, welche Datenfelder man zurück bekommt. Zum Beispiel erhalte ich bei einem REST-Call ein Produkt mit all seinen Attributen, obwohl ich eigentlich nur den Produkt-Namen und die SKU benötige. Das bezeichnet man als „overfetching“. Manchmal erhält man mit dem einen Call auch zu wenige Daten („underfetching“) und muss weitere Anfragen stellen.

Mit GraphQL hingegen definiere ich genau, welche Datenfelder ich haben möchte. Das reduziert die übertragene Datenmenge. Es fällt weniger Traffic an und die Daten werden schneller übertragen.

Weniger Requests

Mit REST muss man oft viele Anfragen stellen. Zum Beispiel holt man sich zuerst anhand bestimmter Kriterien eine Liste von Bestellungen und erhält die Bestell-Nummern. Dann muss man für jede Bestellung einen extra Abruf starten. Wenn ich auf derselben Seite Produkt- oder Kategorie-Informationen benötige, sind das viele weitere Anfragen. Diese Netzwerk-Anfragen werden noch dazu wie im Wasserfall-Prinzip hintereinander abgearbeitet. Sie finden also nicht parallel statt.

GraphQL erlaubt es, alle Entitäten (Bestellungen, Produkte, Kategorien, …) mit einem einzigen Call abzurufen. Man kann auch Hierarchien von Daten mit einem einzelnen Call abfragen. Dadurch reduziert sich die Zahl der „Round-Trips“ gewaltig. Das verspricht wiederum eine bessere Geschwindigkeit und weniger benötigte Bandbreite.

Davon profitiert man in Magento 2 noch mehr, weil man sich die Zeit für das „Bootstraping“ von Magento 2 spart. Damit gemeint ist, dass bei jedem Seiten- oder Schnittstellenaufruf bestimmter Code ausgeführt wird um die Verarbeitung starten zu können. Das passiert bei dem GraphQL-Call nur einmal, weil man alle Entitäten auf einmal abfragt.

Automatische Dokumentation der Schnittstelle

Dokumentation in GraphQL ist ein „first-class citizen“. Das heißt: wenn man das Schema für die Lese- und Schreib-Anfragen definiert, kann und sollte man jedes Feld und jede Entität gleich mit dokumentieren. Daraus kann man dann mit Tools einfach und automatisch eine API-Dokumentation generieren. Dank der Dokumentation binden EntwicklerInnen die Schnittstelle schneller und günstiger ein.

Weil die Dokumentation direkt an der gleichen Stelle wie die Schema-Definition erfolgt kann man leicht die Dokumentation aktuell halten. Das Risiko sinkt stark, dass die Dokumentation und Implementierung auseinander laufen.

Zusätzlich kann man über das Inspection-System das Schema erkunden, wovon auch die Entwickler-Umgebungen (IDEs) profitieren, die somit Auto-Completion und co. anbieten können.

Typisierung

Ein wichtiges Feature für die Stabilität der Schnittstelle ist die starke Typisierung. Das heißt: für jedes Feld wird der Datentyp (Text, Zahl, …) explizit festgelegt. Außerdem wird definiert, ob ein Feld leer sein darf und ob genau ein oder mehrere Werte erwartet werden.

Das verhindert schwammige Definitionen und hilft oft, subtile Fehler in der Implementierung zu vermeiden.

Validierung

Dank des Schema können die Anfragen validiert, das heißt auf ihre Gültigkeit überprüft werden.

Keine Versionierung nötig

Gemeint ist damit natürlich nicht die Versionierung von Code: die muss immer erfolgen. Man muss aber nicht mehr wie in REST eine Version 1, 2, 2.1, … definieren, was unübersichtlich werden und zu Fehlern führen kann. Der Grund: „Deprecation“ ist ein in GraphQL eingebautes Konzept. Ich kann also kennzeichnen, wenn ein Feld nicht mehr verwenden soll. Auch die Deprecation ist  dokumentierbar. So hält man fest, warum das Feld nicht mehr verwendet werden soll und was die Alternative ist. Da die UserInnen selbst entscheiden welche Felder abgefragt werden, kann man leicht im Hintergrund neue Felder anbieten ohne verschiedene Versionen der Schnittstelle veröffentlichen zu müssen.

Man ist nicht komplett vor „Breaking Changes“ gefeit und muss sich trotzdem von Beginn an gründliche Gedanken über die Schnittstellen-Definition machen. Insgesamt kommen inkompatible Änderungen wesentlich seltener vor als bei Änderungen an REST-Schnittstellen.

Eine zentrale API für viele Services im Hintergrund

Für große, komplexe Systeme gibt es einen weiteren Vorteil: das in der Spezifikation fix vorgesehene „GraphQL schema stitching„. Dieses erlaubt es, zu externen Systemen hin eine zentrale API anzubinden, im Hintergrund aber beliebig viele Services zu implementieren.

So wird es möglich, für verschiedene Domänen getrennte GraphQL-Services zu implementieren – zum Beispiel einen Microservice für Preisabfragen und einen für Verfügbarkeitsabfragen. Nach außen hin, zum Beispiel für externe Systeme oder Dritt-Anbieter, verbindet man die Services über Schema-Stitching und macht die gewünschten Teile der Microservices über eine gemeinsame API zugänglich.

Nachteile

Wie alles im Leben gibt es auch Nachteile beim Einsatz dieser Technologie. Diese können großteils durch Middleware wie Apollo abgefangen werden. Für die Teile, bei denen Apollo nicht aushelfen kann ist Magento 2 dafür verantwortlich, sie zu verbessern.

  • Das Auslesen der Daten auf der Server-Seite muss effizient implementiert werden, um gute Performance zu gewährleisten. Darüber hinaus muss man darauf achten, Fallstricke wie Rekursionen zu vermeiden.
  • Bei öffentlich erreichbaren APIs muss Rate-Limiting mitbedacht werden, um zu verhindern dass jemand der Server mit einer großen Anzahl an (komplexen) Fragen in die Knie zwingt. Rate-Limiting ist gerade bei hierarchischen Daten-Strukturen unter Umständen nicht einfach gut umzusetzen.
  • Dasselbe gilt für das zugegebenermaßen nie ganz triviale Thema Caching und Cache-Invalidierung. Zum Glück können Libraries wie jene der Apollo-Plattform hier Abhilfe schaffen.

Wann ist REST besser geeignet?

  1. Wenn Sie über eine umfangreiche Legacy-Anwendung verfügen, die bereits REST unterstützt und für die eine neue Umsetzung der Schnittstelle nicht wirtschaftlich ist.
  2. Wenn Ihre Applikation bzw. Domäne stark in klassischen Ressourcen denkt.
  3. Wenn Sie die Flexibilität von GraphQL nicht benötigen.

GraphQL in Magento 2

Mit Version 2.3.0 hielt die erste Ausbaustufe von GraphQL Einzug in Magento 2. Die nächsten Versionen bauen die Implementierung sukzessive aus.

Während der Code bereits im Core enthalten ist, finden die Verbesserungsarbeiten im extra Community-Repository magento/graphql-ce statt.

Roadmap

Der  Plan für die weiteren Schritte finet sich in der offiziellen Roadmap.