Spring for GraphQL in der Praxis: Eine GraphQL-API für die Tierklinik

Dank Spring for GraphQL lassen sich GraphQL-APIs mit Spring (Boot) entwickeln und bereitstellen. Ein Beispiel für die Anwendung Spring PetClinic zeigt wie.

In Pocket speichern vorlesen Druckansicht

(Bild: Robert Eastman/Shutterstock.com)

Lesezeit: 16 Min.
Von
  • Nils Hartmann
Inhaltsverzeichnis

Die fiktive Tierklinik Spring PetClinic dient der Spring-Community seit Langem dazu, verschiedene Technologien der Spring-Projektfamilie anhand einer Demoanwendung vorzustellen. Dazu gibt es verschiedene Implementierungen, die fachliche Domain ist aber stets die gleiche: In der Tierklink kann ein Haustierbesitzer (Owner) sein Haustier (Pet) zur Untersuchung (Visit) anmelden. Die Untersuchung führt eine Tierärztin (Vetenarian bzw. Vet) durch, die über ein oder mehrere Fachgebiete (Specialty) verfügt. Es gibt ein Web-Frontend, mit dem Mitarbeitende der Tierklinik diese Entitäten verwalten können, also zum Beispiel neue Untersuchungstermine anlegen.

Das Frontend der Spring PetClinic (Abb. 1).

Im Folgenden ist exemplarisch beschrieben, wie sich für diese Domain mit fertig implementierten Datenmodell eine GraphQL-API umsetzen lässt, die beispielsweise zum Entwickeln des Frontends dienen könnte. Die Anwendung ist in zwei Prozesse aufgeteilt: das "Backend", in dem auch die GraphQL-API laufen soll, und ein Microservice ("Vet Service"), der die Tierärzte verwaltet und über eine REST API verfügt. Das Backend verwaltet alle anderen Daten und speichert diese in einer Datenbank, die Zugriff über Spring Data JPA bietet. Der Sourcecode der fertigen API liegt auf GitHub parat. Von Spring for Graph QL 1.0 ist kürzlich der erste Release Candidate erschienen.

Architektur der PetClinic-Anwendung (Abb. 2).

Als Basis für den Objekt-Graphen einer GraphQL-APIs sind Objekte mit Feldern und deren Typen zu definieren – die zugehörige Beschreibung ist in einem Schema hinterlegt. Aus dem Objekt-Graphen können Clients per GraphQL-Operation Daten abfragen und verändern. Dabei sind drei Operationstypen zu unterscheiden: Query, Mutation und Subscription. Für eine GraphQL-API ist allerdings nur Query zwingend erforderlich, Mutation und Subscription sind optional.

Das Schema der API lässt sich mit der Schema Definition Language (SDL) in einer oder mehreren Dateien in der Anwendung festlegen. Spring-GraphQL liest alle im Projekt vorhandenen SDL-Dateien ein und erzeugt daraus zur Laufzeit das Schema.

Ein Objekt in der API wird mit dem Schlüsselwort type beschrieben und enthält Felder, die ebenfalls einen Typ haben – ähnlich wie Felder an einer Java-Klasse. Es gibt dabei einige standardisierte primitive (skalare) Typen (z. B. String oder Int) und Anwendungen können bei Bedarf auch eigene skalare Typen definieren. Bei jedem Feld bedarf es neben dem Typ auch der Angabe, ob das Feld "nullable" ist – es also auch Null zurückliefern darf (was der Default ist) oder, ob es immer einen Wert zurückliefert (gekennzeichnet mit einem Ausrufezeichen hinter dem Typen).

Ein erster Entwurf für das Schema der PetClinic könnte wie im folgenden Listing aussehen. Es besteht aus einem GraphQL-Typ für einen Owner, dessen Haustiere und die Untersuchungen der einzelnen Tiere. Mit den dreifachen Anführungszeichen ist die Dokumentation im Markdown-Format für die Felder und Typen hinterlegt.

Listing: Erster Schema-Entwurf

"""Represents a Pet that is known in the PetClinic"""
type Pet {
    id: Int!
    name: String!
    owner: Owner!
    visits: [Visit!]!
}

type Visit {
    id: Int!
    """What was the result of the visit"""
    description: String!
    """When will/has happend this Visit"""
    date: Date!
}

type Owner {
    id: Int!
    firstName: String!
    lastName: String!
    """List of all Pets this Owner owns"""
    pets: [Pet!]!
}

Das Schema verwendet dieselben Namen für die GraphQL-API und die JPA-Entitäten. Das ist allerdings nicht zwingend notwendig. GraphQL macht keine Aussage darüber, woher die Daten kommen, und so müssen sie auch gar nicht aus einer Datenbank entnommen sein. Daher lassen sich zum Beispiel auch Daten über die API anbieten, die gar nicht im Entity-Modell der Anwendung vorhanden sind, etwa berechnete Daten.

Ein GraphQL-Schema beschreibt immer einen Objekt-Graphen, der genau einen Einstiegspunkt pro GraphQL-Operation (Query, Mutation oder Subscription) kennt. Mit einer Query lassen sich ausschließlich Daten lesen, via Mutation kann der Client Daten verändern und sich per Subscription über neue Daten vom Server informieren lassen. Der Grundgedanke ist bei allen Operationstypen gleich: Der Client schickt eine Anfrage an den Server, mit der er eine Menge von Feldern aus dem Objekt-Graphen auswählt. Dabei kann der Client Felder nur in der Form auswählen, wie sie im Schema beschrieben sind und muss zudem von einem sogenannten Root-Typ ausgehen. Ein Root-Typ sieht genauso aus wie ein fachlicher Typ, enthält also ebenfalls zahlreiche Felder, hat aber einen vorgegebenen Namen, der sich nach dem Operation-Typen richtet ("Query", "Mutation" oder "Subscription"). In der ersten Version der GraphQL-API für die PetClinic könnte der Query-Typ zum Beispiel wie folgt aussehen:

Listing: Die Root Type Query

type Query {
  owners: [Owner!]!
}

Er enthält in diesem Fall nur ein einziges Feld, mit dem der Client eine Liste aller Owner abfragen kann. Ein Client könnte mit dem nun definierten Schema beispielsweise folgende Query ausführen:

Listing: Eine GraphQL-Query, um Daten der Owner abzufragen

query { 
  owners { 
    firstName lastName
    pets { name }
  }
}

Damit fragt der Client jeweils den firstName und lastName jedes Owners sowie die Namen der jeweiligen Haustiere eines Owners ab. Es wäre dem Client aber nicht möglich, nur die Haustiere abzufragen, weil dazu kein entsprechendes Feld am Root-Typ definiert ist. Auch kann der Client die Liste der Owner nicht sortieren oder filtern, weil die dafür erforderliche Funktionalität ebenfalls nicht im Schema definiert ist.

Mehr zum Thema GraphQL

Im Rahmen der Konferenz betterCode() API liefert Nils Hartmann am 18. Mai 2022 mit seinem ganztägigen Workshop "Loslegen mit GraphQL – ein praktischer Einstieg mit Java und Spring Boot" eine detaillierte Anleitung zum Bau eigener GraphQL APIs.

Darüber hinaus stehen bei der heise Academy noch zwei Videokurse mit Nils Hartmann parat: GraphQL – Die praktische Einführung behandelt die Grundlagen und Konzepte der Abfragesprache GraphQL. Im zweiten Kurs findet sich eine Schritt-für-Schritt-Anleitung zu GraphQL – APIs mit Spring Boot entwickeln.

Welche Möglichkeiten dem Client zur Verfügung stehen und wie das Schema einer API aussieht, verrät das Tool GraphiQL. Die Webanwendung liest das Schema einer beliebigen GraphQL ein und stellt anschließend neben der Dokumentation der API auch einen Editor bereit, in dem sich Queries eingeben und ausführen lassen (vergleichbar mit einem SQL Explorer). Da sich das Schema einer GraphQL-API mittels einer speziellen GraphQL Query (Introspection Query) selbst abfragen lässt, kann GraphiQL beim Formulieren von Abfragen mit Code-Vervollständigung (Code Completion) unterstützen. GraphiQL lässt sich für die eigene API mit einem einzigen Property in der application.properties-Datei ganz einfach ein- oder ausschalten.

GraphiQL zeigt die API der PetClinic (Abb. 3).