| von Andy Schunke

Die Evolution von APIs: Ein Blick auf GraphQL und seine Auswirkungen auf die moderne Entwicklung

Bevor wir tiefer in die Welt von REST APIs und GraphQL eintauchen, lassen Sie uns zunächst zwei wichtige Begriffe klären:

API: Eine API, oder Application Programming Interface, ist eine Schnittstelle, die es verschiedenen Softwareanwendungen ermöglicht, miteinander zu kommunizieren. Sie definiert die Methoden und Datenformate, die von einer Anwendung bereitgestellt werden, um von anderen Anwendungen verwendet zu werden.

REST: REST steht für Representational State Transfer und ist ein Architekturstil für die Entwicklung von Webdiensten. RESTful APIs verwenden HTTP-Methoden wie GET, POST, PUT und DELETE, um Daten zwischen Client und Server zu übertragen. Sie basieren auf dem Prinzip, dass Ressourcen durch eindeutige URLs identifiziert und durch standardisierte Operationen manipuliert werden können.

Einleitung

In der Welt der APIs stehen REST APIs und GraphQL als zwei der bekanntesten Architekturstile im Rampenlicht. Während man REST APIs als eine Schatztruhe betrachten kann, aus der man alle Schätze auf einmal erhält, und GraphQL eher mit einem Bankschließfach vergleichbar ist, aus dem man gezielt die benötigten Gegenstände herausnimmt, gibt es subtilere Unterschiede zu beachten. REST APIs bieten eine traditionelle, ressourcenorientierte Architektur, die eine umfassende Datensammlung auf einmal liefert, während GraphQL eine abfragesprachbasierte, flexible Alternative bietet. Diese ermöglicht es den Entwicklern, genau die Daten abzurufen, die sie benötigen.

Beispiele für Unternehmen, die erfolgreich auf GraphQL setzen und die Vorteile dieser Technologie nutzen, sind Facebook, GitHub und Shopify.

REST API vs. GraphQl
REST API vs. GraphQl

Doch neben den Vorteilen, die GraphQL zweifellos bietet, ist es wichtig anzuerkennen, dass auch diese Technologie ihre eigenen Trade-offs hat. In diesem Artikel werden wir nicht nur die revolutionären Aspekte von GraphQL beleuchten, sondern auch auf seine Herausforderungen und potenziellen Kompromisse eingehen.

Was ist graphql?

GraphQL ist eine von Facebook 2015 entwickelte Abfragesprache und Laufzeitumgebung für APIs. Im Gegensatz zu traditionellen REST APIs, die mehrere Endpunkte mit fest definierten Datenstrukturen bereitstellen, ermöglicht GraphQL eine einzige flexible Endpunktschnittstelle, über die Clients genau die Daten abrufen können, die sie benötigen.

Im Gegensatz zu traditionellen REST APIs, die hauptsächlich durch direkte HTTP-Anfragemethoden wie GET, PUT und DELETE interagieren, bietet GraphQL eine flexiblere Interaktion über spezifische Abfragen, Mutationen und Abonnementen (Subscriptions). Während REST APIs den Entwicklern erlauben, direkte HTTP-Anfragen zu schreiben, um auf Ressourcen zuzugreifen oder diese zu manipulieren, nutzt GraphQL unter der Oberfläche standardmäßig POST-Anfragen, um Abfragen, Mutationen und Abonnements an den GraphQL-Server zu senden. Dies ermöglicht eine einheitliche Schnittstelle für alle Arten von Operationen und erfordert keine spezifischen Endpunkte für jede Aktion, wie es bei REST APIs der Fall sein kann.

  • Abfragen (Queries): Mit Abfragen können Clients Daten von einem GraphQL-Server abrufen. Der Client sendet eine Abfrage an den Server, in der spezifiziert wird, welche Daten er erhalten möchte. Der Server liefert dann genau diese Daten zurück, und zwar nur diejenigen, die vom Client angefordert wurden.
  • Mutationen (Mutations): Mutationen werden verwendet, um Änderungen an den Daten auf dem Server vorzunehmen, z. B. um Daten zu erstellen, zu aktualisieren oder zu löschen. Im Gegensatz zu Abfragen, die nur lesende Operationen sind, ermöglichen Mutationen schreibende Operationen, um den Zustand der Daten zu ändern.
  • Subscriptions (Abonnement): Subscriptions ermöglichen es Clients, sich für Echtzeitaktualisierungen von Daten auf dem Server zu registrieren. Wenn sich auf dem Server Daten ändern, sendet der Server automatisch eine Aktualisierung an alle Clients, die die entsprechende Registrierung aktiviert haben.

Es ist wichtig, die Grundlagen von GraphQL zu verstehen, insbesondere wenn man über APIs spricht. Durch das Verständnis von GraphQL können Entwickler und IT-Mitarbeiter fundierte Entscheidungen darüber treffen, welche Technologien sie verwenden möchten, und sicherstellen, dass diese zum jeweiligen Anwendungsfall passen.

Vorteile von GraphQL im Vergleich zu REST:

GraphQL bietet eine Vielzahl von Vorteilen im Vergleich zu traditionellen RESTful APIs. Die Möglichkeit, über einen einzigen API-Endpunkt auf beliebige oder alle Datenpunkte zuzugreifen, ist einer der Hauptvorteile von GraphQL. Im Gegensatz dazu können RESTful APIs oft zu Overfetching oder Underfetching führen, was die Effizienz beeinträchtigen kann.

 

Datenabfrage
Beispiel Abfrage mehrerer Daten

Eine weitere Stärke von GraphQL liegt in der Flexibilität der Resolver. Resolver sind Funktionen, die bestimmen, wie die Daten für einen bestimmten Feldtyp aufgelöst werden. Hier liegt der Unterschied zu traditionellen RESTful APIs: Während bei RESTful APIs der Server die Struktur und den Inhalt der Daten festlegt, hat der Client bei GraphQL die Kontrolle darüber, welche Daten geliefert werden sollen und wie sie aufgelöst werden.

Zu den weiteren Vorteilen von GraphQL gehören Introspection, das es ermöglicht, die Struktur einer GraphQL API zur Laufzeit zu erkunden, sowie Versionierung, um Änderungen an der API zu verwalten, ohne bestehende Clients zu beeinträchtigen.

Wann ist GraphQL sinnvoll?

GraphQL bietet sich in verschiedenen Szenarien an, in denen Flexibilität, Skalierbarkeit und effiziente Datenabfrage entscheidend sind. Hier sind einige typische Anwendungsfälle, in denen die Verwendung von GraphQL gegenüber REST APIs besonders vorteilhaft ist:

  • Komplexe Datenanforderungen: Wenn eine Anwendung komplexe Datenanforderungen hat und unterschiedliche Arten von Daten aus verschiedenen Quellen abgerufen werden müssen, ist GraphQL besonders nützlich. Durch die Möglichkeit, genau die benötigten Daten mit einer einzigen Anfrage abzurufen, können Entwickler Overfetching vermeiden und die Leistung der Anwendung verbessern.
  • Mikroservice-Architekturen: In einer Mikroservice-Architektur, in der mehrere unabhängige Services miteinander kommunizieren müssen, bietet GraphQL eine effiziente Möglichkeit, Daten zwischen den Services auszutauschen. Statt viele verschiedene Endpunkte zu erstellen, können Entwickler eine einzige GraphQL-Schnittstelle verwenden, um auf Daten aus verschiedenen Services zuzugreifen. Besonders nützlich ist GraphQL in diesem Kontext als gemeinsame Schnittstellensprache oder Abstraktionsebene für Teams, die unterschiedliche Programmiersprachen verwenden.
  • Mobile Anwendungen: Für mobile Anwendungen, insbesondere für Apps mit begrenzter Bandbreite und Ressourcen, ist GraphQL ideal. Durch die Möglichkeit, nur die benötigten Daten abzurufen und die Größe der Antwort anzupassen, können mobile Apps schneller und effizienter arbeiten.
  • Entwicklung von benutzerdefinierten Dashboards oder Kundenportalen: Wenn Benutzer die Möglichkeit haben sollen, benutzerdefinierte Dashboards oder Portale zu erstellen, in denen sie genau die gewünschten Daten anzeigen können, ist GraphQL die richtige Wahl. Mit GraphQL können Benutzer ihre Abfragen dynamisch anpassen und nur die Daten anzeigen, die für sie relevant sind.

Diese Anwendungsfälle verdeutlichen, wie GraphQL in verschiedenen Entwicklungs- und Einsatzszenarien die Effizienz und Flexibilität verbessern kann.

Herausforderungen und Lösungen bei der Verwendung von GraphQL

Obwohl GraphQL viele Vorteile bietet, sind bei seiner Verwendung auch einige Herausforderungen zu beachten. Insbesondere beim Umgang mit nicht nativ unterstützten Datenformaten wie Bytes sowie dem 1:N-Problem können Schwierigkeiten auftreten. Hier sind einige potenzielle Hürden und Lösungen:

Nicht nativ unterstützte Datenformate wie Bytes: GraphQL wurde primär für die Arbeit mit strukturierten Daten entwickelt und unterstützt daher nicht nativ bestimmte Datentypen wie Binärdaten (Bytes). Dies kann problematisch sein, wenn Anwendungen solche Daten verarbeiten müssen.

Lösung: Eine mögliche Lösung besteht darin, solche Daten in einem geeigneten Format zu serialisieren und dann als Zeichenfolge oder benutzerdefinierten skalaren Typ in GraphQL zu übergeben. Auf diese Weise können nicht nativ unterstützte Datenformate trotzdem über GraphQL abgerufen und manipuliert werden.

Byte scalar / JavaScript

import { GraphQLScalarType, Kind } from 'graphql';
const Byte = new GraphQLScalarType({
  name: 'Byte',
  description: 'Byte custom scalar type',
  parseValue(value: string) {
    return Buffer.from(value, 'base64'); // value from the client
  },
  serialize(value: Buffer) {
    return value.toString(); // value sent to the client
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING) {
      return Buffer.from(ast.value, 'base64'); // value from the client
    }
    return null;
  },
});
export const scalarList = { [Byte.name]: Byte };

Das 1:N-Problem mit GraphQL: Das 1:N-Problem tritt auf, wenn eine Abfrage zu einem einzigen Datensatz (1) eine unerwartet große Anzahl von Datensätzen (N) zurückgibt. Dies kann dazu führen, dass der Server überlastet wird und unnötige Daten übertragen werden. Insbesondere bei GraphQL kann dieses Problem auftreten, wenn die Abfragebeziehungen zwischen verschiedenen Datenobjekten nicht optimal modelliert sind.

Das bedeutet, dass eine einzelne Anfrage möglicherweise mehr Daten zurückgibt als erwartet, was zusätzliche, nicht optimierte Abfragen gegen die darunterliegenden Datentöpfe zur Folge hat. In solchen Fällen ist es wichtig, die Datenmodellierung und Abfragerelationen sorgfältig zu überprüfen und zu optimieren, um die Effizienz und Leistung der GraphQL-API zu verbessern.

Lösung: Eine bewährte Lösung für das 1:N-Problem ist die Verwendung eines sogenannten "Dataloaders". Ein Dataloader ist ein Tool, das speziell für GraphQL entwickelt wurde und es ermöglicht, effizient Daten zu laden, indem es Caching und Batch-Operationen verwendet. Dadurch können mehrere Anfragen zu einem Datensatz zusammengeführt und bereits erhaltene Datenbankergebnisse wiederverwendet werden. Dies reduziert die Anzahl der Abfragen und vermeidet unnötige Duplikate, was die Leistung der Anwendung erheblich verbessert.

Beispiel ohne Dataloader
Beispiel ohne Dataloader

In diesem Beispiel, ohne einen Dataloader zu verwenden, wird eine Anfrage nach zwei Benutzern gestellt (einem Benutzer mit der ID 1 und einem Benutzer mit der ID 2). Da beide Benutzer unterschiedliche Daten liefern sollen, führt GraphQL zunächst eine Datenbankabfrage für jeden Benutzer durch. Anschließend wird für jeden zurückgegebenen Benutzer eine zusätzliche Anfrage an die Datenbank gesendet, um die Anzahl der „Followers“ zu erhalten.

Beispiel mit Dataloader
Beispiel mit Dataloader

Bei Verwendung eines Dataloaders kann man Informationen vor dem Abrufen von Daten aus der Datenbank bündeln, was die Möglichkeit bietet, Datenbankabfragen zu minimieren. In diesem Beispiel fragen wir die Datenbank nach Benutzern mit den IDs 1 und 2 sowie nach Informationen wie Namen, Adressen und Posts. Die zurückgegebene Liste mit Benutzern wird dann verwendet, um die spezifischen Follower-Namen anhand der Benutzer-IDs abzufragen.

Es ist wichtig zu beachten, dass die Verwendung von GraphQL eine zusätzliche Lernkurve für Entwickler bedeutet, da es sich um eine neue Technologie handelt. Im Vergleich zu REST APIs erfordert GraphQL ein tieferes Verständnis für seine Funktionsweise und Konzepte.

Die Lösung solcher Probleme mit GraphQL erfordert daher nicht nur technische Fähigkeiten, sondern auch eine gründliche Auseinandersetzung mit den Prinzipien und Best Practices von GraphQL. Entwickler müssen sich mit Konzepten wie Schemas, Resolvers und Typsystemen vertraut machen, um effektiv mit GraphQL arbeiten zu können. Dies bedeutet, dass die Einführung von GraphQL in ein Projekt zusätzliche Schulungen und Ressourcen für die Entwickler erfordern kann, um sicherzustellen, dass sie die Technologie optimal nutzen können.

Fazit

In diesem Blogbeitrag haben wir einen Einblick in GraphQL gewonnen, eine leistungsfähige Abfragesprache und Laufzeitumgebung für APIs. Wir haben gesehen, wie GraphQL im Vergleich zu traditionellen REST APIs Flexibilität bietet, indem es eine einzige flexible Endpunktschnittstelle ermöglicht, über die Clients genau die benötigten Daten abrufen können. Darüber hinaus haben wir einige der Herausforderungen diskutiert, die bei der Verwendung von GraphQL auftreten können, wie z.B. das 1:N-Problem, und Lösungen vorgestellt, wie den Einsatz von Dataloadern.

Zusammenfassend lässt sich sagen, dass sowohl GraphQL als auch REST ihre Vor- und Nachteile haben. Während GraphQL mit seiner Flexibilität und Effizienz die Art und Weise der Datenabfrage und -manipulation revolutioniert hat, bleiben RESTful APIs weiterhin eine beliebte Wahl für viele Entwickler aufgrund ihrer Einfachheit und weit verbreiteten Akzeptanz. Die Entscheidung zwischen GraphQL und REST hängt letztendlich von den spezifischen Anforderungen und Zielen eines Projekts ab. Es ist wichtig, die Stärken und Schwächen jeder Technologie sorgfältig abzuwägen und die am besten geeignete Lösung für den jeweiligen Anwendungsfall zu wählen.

Indem wir uns mit neuen Technologien wie GraphQL vertraut machen, können wir innovative Lösungen entwickeln und die Zukunft der API-Entwicklung gestalten.

Quellen

Rest API: https://www.w3.org/2001/sw/wiki/REST
Github GraphQL: https://docs.github.com/en/graphql/overview/about-the-graphql-api
Shopify Graphql: https://www.shopify.com/partners/blog/getting-started-with-graphql

Teile diesen Artikel mit anderen

Über den Autor

Andy Schunke ist seit 2023 als Associate Consultant bei der Woodmark Consulting AG tätig. Als Fullstack-Entwickler spezialisiert er sich auf kundenorientierte Softwarelösungen im Frontend und Backend mit Python und TypeScript. Mit seiner AWS Developer Zertifizierung bringt er fundierte Kenntnisse in cloudbasierten Lösungen ein und entwickelt maßgeschneiderte Softwarelösungen, die den spezifischen Anforderungen der Kunden gerecht werden.

Zur Übersicht Blogbeiträge