Die GraphQL Query

GraphQL Query: Alles was es zu beachten gibt.
Die GraphQL Query
Jens Dressler
Founder & CEO

Wie wir bereits in anderen Beiträgen über GraphQL geschrieben haben, beschreibt die GraphQL Spezifikation die Abfragesprache und die Laufzeitumgebung um GraphQL Operationen vom Typ Query, Mutation oder Subscription auszuführen. Dieser Artikel fokussiert auf die GraphQL Query (Abfrage) und beschreibt wie sie strukturiert und ausgeführt wird.

Die GraphQL Query-Operation

Die GraphQL-Abfrage ist eine der Kernoperationen von GraphQL. Über einen einzigen Endpunkt können HTTP-Clients verschiedene Arten von Daten von einem GraphQL-Server abrufen. Eine Abfrage ist somit das Äquivalent zu einer HTTP-GET-Anfrage in einer REST-API mit dem Unterschied, dass man bei REST-APIs überlicherweise einen Endpunkt pro Datentyp bereitstellt. Per Konvention ist festgelegt, dass GraphQL-Abfragen keine Seiteneffekte erzeugen.

Das GraphQL-Schema definiert die Struktur der Abfrage, z. B. ihre Argumente, Felder und Rückgabewerte. Bei der Definition eines Schemas deklarieren API-Entwickler:innen Abfragen als Felder des Root-Typs Query. Ein GraphQL-Server validiert die Abfrage anhand des GraphQL-Schemas, bevor er die angeschlossenen Resolver ausführt und die abgerufenen Felder an den Client zurückgibt. Verschiedene GraphQL Resolver werden bei Abfragen parallel ausgeführt, um eine niedrige Latenz zu gewährleisten.

GraphQL Query Beispiel

Beginnen wir mit einer einfachen Abfrage zum Abrufen einer Willkommensnachricht vom Server. Das entsprechende GraphQL-Schema mit einem Welcome-Objekttyp und seinem Abfragefeld welcome könnte wie folgt aussehen:

Um die Abfrage auszuführen, kann ein Entwickler die folgende Syntax z.B. in den GraphiQL-Explorer eingeben:

Im obigen Beispiel haben wir die Kurzform ohne den Operationstyp und ohne einen Operationsnamen verwendet. Wenn kein Operationstyp angegeben wird, wird standardmäßig angenommen, dass es sich um eine Abfrage handelt. Bei der Ausführung in der Produktion wird empfohlen einen Operationsnamen anzugeben z.B.:

GraphQL Abfragen über HTTP

Der Standard für die Bereitstellung von GraphQL über HTTP sieht wie folgt aus:

Die Eigenschaft operationName ist erforderlich, wenn mehrere Operationen in einer Abfrage ausgeführt werden sollen. Die Stapelung von Abfrageoperationen ist einer der vielen Vorteile, die GraphQL gegenüber klassischen REST-APIs hat. Es ist wichtig zu beachten, dass auch jede Abfrageoperation selbst einen eindeutigen Namen haben muss, damit der GraphQL-Server sie erfolgreich ausführen kann. Um dies zu erreichen, bietet GraphQL das Aliasing-Konzept.

Query-Aliasse und -Fragmente

Aliase helfen dabei die Abfrageergebnisse zu strukturieren. Werfen wir einen Blick auf ein Beispiel:

Im obigen Beispiel haben wir auch Fragmente verwendet, mit denen wir einmalig definieren können, mit welchen Feldern der Server antworten soll. Die Operation kann das Fragment in allen Abfragen referenzieren, die Objekte des Typs Welcome. Das Ergebnis der obigen Abfrage sieht dann folgendermaßen aus:

Konzepte wie Aliase und Fragmente sind eine einfache Möglichkeit die Antwort vom Server zu strukturieren. Da Anwendungen jedoch in der Regel mehr tun als nur Benutzer zu begrüßen, werden wir uns im nächsten Abschnitt mit Objektbeziehungen und verschachtelten Abfragen beschäftigen.

Verschachtelte GraphQL Abfragen

In vielen Anwendungen stehen Objekttypen oft in Beziehung zueinander. In diesem Fall ist es beim Entwurf eines Datenmodells hilfreich, die Beziehungen zwischen den Objekten mit einfachen Begriffen wie hat ein oder hat viele zu definieren. Ein Benutzer eines sozialen Netzwerks hat beispielsweise ein Profil, hat viele Freunde, hat viele Posts erstellt und viele Kommentare geschrieben.

Diese Beziehungen können nun wie folgt definiert werden:

  • Benutzer hat ein Profil
  • Benutzer hat viele Freunde
  • Benutzer hat viele Posts
  • Benutzer hat viele Kommentare

Schema für verschachtelte Abfragen

In einem GraphQL-Schema werden die Beziehungen zwischen Objekten mit einem Verbindungstyp definiert, der die Einbettung der Felder des verschachtelten Typs in die Abfrage eines übergeordneten Typs ermöglicht. Zum Beispiel, nehmen wir an wir wollen viele Musiker statt nur einem begrüßen. In diesem Fall würde das Welcome-Objekt und das Schema würde wie folgt aussehen:

Die genaue Syntax wie eine Verbindung im Schema definiert wird, hängt von der GraphQL-Server-Plattform oder der persönlichen Präferenz ab. Bei graphapi® haben wir uns entschieden, das Wort Connection an den verschachtelten Object-Typ zu hängen.

Die Ausführung einer veschachtelten Abfrage

Eine Abfrage mit einem verschachtelten Typ sieht wie folgt aus:

Das Ergebnis dieser Abfrage dann folgendermaßen:

Ausführung von Listenabfragen

Wenn Listenabfragen verfügbar sind, ermöglichen sie die Abfrage aller Elemente eines bestimmten Typs auf ähnliche Weise.

Bei der Ausführung der Abfrage erhält man dann folgendes Ergebnis:

In den vorherigen Beispielen wird klar, dass der Client die Antwortstruktur einer Abfrage definiert, indem er Aliase, Argumente und Felder angibt. Dies ist ein grundlegender Unterschied zu klassischen REST-APIs, bei denen der Server die Antwortstruktur einer bestimmten Anfrage fest vorgibt.

Bei der the_beatles Query im obigen Beispiel werden auch Variablen und Argumente verwendet. Im nächsten Abschnitt schauen wir uns beide Konzepte nochmal genauer an.

GraphQL Query Variablen

In den vorherigen Beispielen haben wir Argumente und Werte direkt als Teil der Abfrage definiert. Während dies für Demonstrationszwecke sinnvoll ist, sind GraphQL Variablen für Anwendungen, die den Kontext häufig ändern und auf dynamische Benutzereingaben reagieren müssen, besser geeignet.

Variablen werden wie folgt verwendet:

  • Statische Werte in Argumenten müssen mit einer benutzerdefinierten Variable, z.B. $variableName ersetzt werden.
  • Die Variable $variableName wird als ein Parameter der Abfrage deklariert.
  • Es muss sichergestellt werden, dass der Typ der Variable dem Typ im Schema entspricht.
  • Die Variablenwerte werden dann als Map mit Schlüssel-Wert-Paaren übergeben.

Durch die Verwendung von Variablen entfällt die Notwendigkeit, den Abfrage-String zur Laufzeit kontextuell zu verändern. Alle deklarierten Variablen müssen entweder Skalare, Enums oder Eingabetypen sein.

GraphQL Query Parameter

In REST-basierten APIs übergeben die Kunden Parameter als Teil der URL. In GraphQL kann jedoch jedes Feld typisierte Parameter haben. Zusätzlich zum Standardsatz skalarer Typen, z.B., String, Int, oder Float, kann ein GraphQL-Server auch benutzerdefinierte Typen deklarieren. Welche Parameter verfügbar sind, hängt von der jeweiligen GraphQL Server-Implementierung ab.

Mit graphapi® stellen wir folgende Parameter bereit:

  • limit:Int - Limitiert die Länge einer Liste.
  • nextToken:String - Für das Blättern zur nächsten Seite.
  • sortDirection:SortOrderType - Ändert die Sortierreihenfolge einer Liste.
  • filter:TypeComparisonInput - Filtert eine Liste.

Zusammenfassung

Die GraphQL-Query ist die Kernoperation von GraphQL-basierten APIs. Sie bietet eine Vielzahl von Optionen, die die Abfrageantwort von einem GraphQL-Server beeinflussen. Obwohl die Leistungsfähigkeit und Flexibilität von GraphQL-Abfragen die Integration von GraphQL-APIs für Anwendungsentwickler einfach macht, kann es für Teams, die für die Implementierung der gesamten Logik auf der Serverseite verantwortlich sind, eine Herausforderung sein. Mit graphapi® abstrahieren wir diese Komplexität vollständig, so dass Teams schneller starten und sich auf die Bereitstellung von Funktionalitäten für ihre Kunden konzentrieren können.

Weitere Informationen zu GraphQL