Entwicklung skalierbarer Java-APIs mit GraphQL

Haben Sie sich jemals gefragt, ob es einen besseren Weg gibt, Daten für Ihre Anwendungen abzurufen als REST-APIs? In der Backend-Entwicklung hat sich GraphQL als kraftvolle Alternative herauskristallisiert, die einen flexibleren und effizienteren Ansatz zum Abrufen von Daten bietet. Für Entwickler, die mit Java vertraut sind, eröffnet die Integration von GraphQL in ein modernes Backend die Möglichkeit, skalierbare und leistungsstarke APIs zu erstellen, die auf eine Vielzahl von Anwendungsfällen zugeschnitten sind.

Dieser Blog wird die wichtigsten Unterschiede zwischen GraphQL und REST untersuchen, die einzigartigen Vorteile der Verwendung von GraphQL zum Abrufen von Daten hervorheben und Sie durch die Implementierung einer GraphQL-API in Java mit einem realen Beispiel führen.

Was ist GraphQL?

GraphQL ist eine Abfragesprache für APIs und eine Laufzeitumgebung zum Ausführen dieser Abfragen. Im Gegensatz zu REST, bei dem feste Endpunkte vordefinierte Daten zurückgeben, ermöglicht GraphQL den Clients, genau die Daten anzufordern, die sie benötigen. Diese Granularität macht GraphQL besonders effizient, insbesondere für komplexe oder datengesteuerte Anwendungen.

Vorteile des GraphQL-Ansatzes:

  • Granulares Datenabrufen: Der Client kann nur Name und Bezeichnung abfragen, ohne unnötige Felder wie Abteilung abzurufen.
  • Verschachtelte Abfragen: Abrufen der Managerdetails zusammen mit den Mitarbeiterinformationen in einer einzigen Abfrage.
  • Schema-gesteuerte Entwicklung: Das Schema fungiert als Vertrag, der die Evolution der API erleichtert.

Was ist eine REST-API?

Representational State Transfer (REST) ist ein Architekturstil für den Aufbau von APIs. Es verwendet standardisierte HTTP-Methoden wie GET, POST, PUT und DELETE, um CRUD-Operationen durchzuführen. REST ist bekannt für seine Einfachheit und weit verbreitete Anwendung.

Einschränkungen von REST:

  • Über- oder Unterabfrage von Daten.
  • Erfordert mehrere Endpunkte und Versionierung, um Änderungen anzupassen.
  • Keine integrierten Echtzeitfunktionen.

GraphQL vs. REST-API: Was ist der Unterschied?

GraphQL und REST sind zwei beliebte Ansätze zum Erstellen von APIs, von denen jeder seine Stärken hat. Während REST jahrelang der Standard war, bietet GraphQL mehr Flexibilität und Effizienz, insbesondere bei der Datenabfrage und der Zusammenarbeit zwischen Frontend- und Backend-Teams.

Wesentliche Unterschiede

  • Im Gegensatz zu REST, das mehrere Endpunkte verwendet und für Änderungen eine Versionierung erfordert, konsolidiert GraphQL die Datenabfrage in eine einzige Abfrage und reduziert den Bedarf an Versionierung, da Clients die Datenanforderungen angeben. 
  • Während REST HTTP-Statuscodes verwendet, um Erfolg oder Fehler anzuzeigen, gibt GraphQL immer einen 200 OK-Status zurück und kommuniziert Fehler im Antworttext. 
  • GraphQL unterstützt auch Echtzeitaktualisierungen über Abonnements, im Gegensatz zu REST, das keine integrierte Echtzeitunterstützung bietet.
  • Obwohl REST weit verbreitet ist und viele Werkzeuge bietet, hat sich die Umgebung von GraphQL schnell entwickelt und bietet leistungsstarke Tools wie GraphiQL für eine einfachere Entwicklung.
  • Zuletzt, während REST Header für das Caching verwendet, erfordert GraphQL aufgrund dynamischer Abfragen fortgeschrittenere Techniken, bietet jedoch Optionen wie persistente Abfragen für effizientes Caching.

Kernkonzepte von GraphQL

1. Schema-Definition-Sprache (SDL)

GraphQL hat sein eigenes Typsystem, das verwendet wird, um das Schema einer API zu definieren. Die Syntax zum Schreiben von Schemata wird Schema-Definition-Sprache (SDL) genannt.

2. Abfragen vs. Mutationen vs. Abonnements

  • Abfragen werden verwendet, um Daten vom Server abzurufen. Im Gegensatz zu REST, das mehrere feste Endpunkte verwendet, nutzt GraphQL einen einzigen Endpunkt, und der Client gibt die benötigten Daten in der Abfrage an, was Flexibilität bietet.
  • Mutationen werden verwendet, um Daten auf dem Server zu ändern, wie das Erstellen, Aktualisieren oder Löschen von Daten. Sie ermöglichen es den Clients, Änderungen an das Backend zu senden und sind unerlässlich für Anwendungen, die Daten schreiben müssen.
  • Abonnements ermöglichen Echtzeit-Updates, indem sie eine ständige Verbindung zwischen dem Client und dem Server aufrechterhalten. Wenn ein abonnierter Ereignis eintritt, sendet der Server Updates an den Client und bietet kontinuierliche Datenströme, im Gegensatz zu Abfragen und Mutationen, die einem Anfrage-Antwort-Zyklus folgen.

3. GraphQL-Schema

Es definiert die Datenstruktur, die abgefragt oder verändert werden kann, und fungiert als Vertrag zwischen Server und Client. Es spezifiziert die Typen, Felder und Beziehungen, auf die Clients zugreifen können. Das Schema umfasst in der Regel spezielle Wurzeltypen: Abfrage für die Datenabfrage, Mutation zur Änderung von Daten und Abonnement für Echtzeitaktualisierungen. Diese Typen definieren zusammen die Fähigkeiten der API und wie Clients mit ihr interagieren können.

4. Resolver: Zuordnung von GraphQL-Abfragen zu Daten

Resolver sind Funktionen, die die Logik für das Abrufen von Daten in einem GraphQL-Server behandeln. Jedes Feld in einem Schema ist mit einem Resolver verknüpft, der bestimmt, wie die Daten für dieses Feld abgerufen oder berechnet werden. Wenn eine Abfrage ausgeführt wird, ruft der Server die entsprechenden Resolver für die angeforderten Felder auf. Resolver können Skalare oder Objekte zurückgeben, wobei die Ausführung für untergeordnete Felder fortgesetzt wird, wenn ein Objekt zurückgegeben wird, und abgeschlossen wird, wenn ein Skalar zurückgegeben wird. Wenn null zurückgegeben wird, stoppt die Ausführung. Resolver sind unerlässlich für die Zuordnung von GraphQL-Abfragen zu den tatsächlichen Datenquellen.

Vorteile der Verwendung von GraphQL in Java

  1. Exakte Datenabfrage: Abfragen Sie nur die benötigten Daten, nichts mehr, um vorhersehbare und effiziente Ergebnisse zu gewährleisten.
  2. Eine Anfrage für mehrere Ressourcen: Rufen Sie verwandte Daten in einer Abfrage ab, um mehrere API-Aufrufe zu reduzieren.
  3. Typsystem: Organisiert APIs nach Typen und Feldern, um sicherzustellen, dass Abfragen gültig sind und Fehler klar sind.
  4. Entwicklerwerkzeuge: Steigern Sie die Produktivität mit Tools wie GraphiQL, verwenden Sie Typdefinitionen für besseren Abfrageaufbau und Debugging.
  5. Versionlose Evolution: Fügen Sie Felder hinzu oder veralten Sie sie, ohne bestehende Abfragen zu unterbrechen, um die APIs wartbar zu halten.
  6. Flexible Datenintegration: Erstellen Sie eine einheitliche API über vorhandenen Daten und Code, die mit verschiedenen Speicher-Engines und Sprachen kompatibel ist.

Einrichten einer GraphQL-API in Java

Praxisbeispiel: Benutzer und Aufträge

Stellen Sie sich vor, Sie erstellen eine Mitarbeiterverzeichnis-API für eine große Organisation. Das Ziel ist es, es den Clients zu ermöglichen, Details wie den Namen des Mitarbeiters, die Bezeichnung, die Abteilung und sogar deren Berichtslinie abzufragen.

1. Projekt einrichten

Erstellen Sie ein neues Spring Boot-Projekt mit Spring Tool Suite oder besuchen Sie Spring Initialiser. Fügen Sie dann diese Abhängigkeiten zur pom.xml-Datei hinzu:

XML

 

2. Erstellen Sie Ihre Entitäten

Erstellen Sie Java-Entitäten (z. B. Benutzer und Auftrag), um die Daten darzustellen, die über GraphQL abgefragt oder mutiert werden. Zum Beispiel:

Java

 

3. Repositories erstellen

Erstellen Sie Repositories, um mit der Datenbank zu interagieren:

Java

 

4. Service-Klassen erstellen

Erstellen Sie Service-Klassen, um die Geschäftslogik zu verarbeiten:

Java

 

5. Erstellen Sie GraphQL-Controller

Definieren Sie GraphQL-Controller, um Abfragen und Mutationen zu verarbeiten:

Java

 

6. Definieren Sie Ihr GraphQL-Schema

Erstellen Sie eine schema.graphqls-Datei im Verzeichnis src/main/resources:

Plain Text

 

7. Konfigurieren Sie GraphQL in der application.properties

Optional können Sie GraphQL-Einstellungen in scr/main/resources/application.properties konfigurieren:

Properties files

 

8. Führen Sie Ihre Anwendung aus

Führen Sie die SpringBoot-Anwendung mit mvn spring-boot:run oder aus Ihrer IDE aus. Sobald sie läuft, können Sie auf den GraphAL-Endpunkt unter /graphiql zugreifen.

9. Testen Sie mit GraphQL-Abfragen

Testen Sie die GraphQL-API mit einem Tool wie GraphiQL oder Postman.

Für Mutation: 

Plain Text

 

Ausgabe:

Plain Text

 

Für Abfrage:

Plain Text

 

Ausgabe:

JSON

 

Erweiterte GraphQL-Funktionen

1. Verbessern der Wiederverwendbarkeit mit Fragments

Ein Fragment ist im Grunde eine wiederverwendbare Gruppe von Feldern, die für einen bestimmten Typ definiert sind. Es ist eine Funktion, die die Struktur und Wiederverwendbarkeit Ihres GraphQL-Codes verbessert.

2. Feldparameterisierung mit Argumenten

In GraphQL können Felder Argumente akzeptieren, um Abfragen dynamischer und flexibler zu gestalten. Diese Argumente ermöglichen es, die von der API zurückgegebenen Daten zu filtern oder anzupassen.

3. Paginierung und Sortierung mit GraphQL

Paginierung

Paginierung ist ein schwieriges Thema im API-Design. Auf einer hohen Ebene gibt es zwei Hauptansätze, wie sie angegangen werden kann.

  • Limit-Offset: Fordern Sie einen bestimmten Abschnitt der Liste an, indem Sie die Indizes der abzurufenden Elemente angeben (tatsächlich geben Sie hauptsächlich den Startindex (Offset) sowie eine Anzahl von abzurufenden Elementen (Limit) an).
  • Cursor-basiert: Dieses Paginierungsmodell ist etwas fortgeschrittener. Jedes Element in der Liste ist mit einer eindeutigen ID (dem Cursor) verknüpft. Clients, die durch die Liste paginieren, geben dann den Cursor des Start-Elements sowie eine Anzahl von abzurufenden Elementen an.

Sortierung

Mit GraphQL API Design ist es möglich, Listen von Elementen zurückzugeben, die entsprechend spezifischer Kriterien sortiert (geordnet) sind.

Herausforderungen und Überlegungen zur Verwendung von GraphQL

  • Komplexität: Die Verwaltung von GraphQL-Schemas und -Abfragen kann für einfache Datenmodelle oder unerfahrene Teams herausfordernd sein.
  • Leistungsprobleme: Tief verschachtelte Abfragen können die Backend-Ressourcen belasten, wenn sie nicht optimiert sind.
  • Caching-Herausforderungen: Standard-REST-basierte Caching-Strategien sind nicht anwendbar und erfordern individuelle Lösungen.
  • Sicherheitsbedenken: Übermäßiges Abrufen und bösartige Abfragen erfordern Abfragegrenzen und andere Sicherheitsvorkehrungen.
  • Hybrid-Nutzung: Funktioniert am besten für komplexe Datenanforderungen, oft in Kombination mit REST für einfachere Operationen.

Fazit

GraphQL bietet einen flexiblen und effizienten Ansatz zum Erstellen moderner APIs in Java und ist daher eine ideale Wahl für dynamische und datenintensive Anwendungen. Die Architektur mit nur einem Endpunkt und die starke Typisierung vereinfachen das Design von APIs und gewährleisten dabei eine robuste Leistung. Egal, ob Sie ein einfaches Mitarbeiterverzeichnis oder eine komplexe Analyseplattform erstellen, GraphQL ermöglicht es Entwicklern, skalierbare Lösungen mit Leichtigkeit bereitzustellen. Beginnen Sie noch heute mit der Erkundung von GraphQL mit Tools wie Spring Boot und graphql-java, um das volle Potenzial in Ihrem nächsten Projekt auszuschöpfen.

Quellcode

Sie finden den vollständigen Quellcode für dieses Tutorial auf Github.

Source:
https://dzone.com/articles/design-scalable-java-apis-with-graphql