How-To

Schnittstellen-Booster: GraphQL als Alternative zu Rest

Seite 2 / 2

Schema-Definition: Variante 2

Für die Schema-Definition mit GraphQL SDL lassen sich Entwickler das bestehende Schema mit dem Modul printSchema in der GraphQL „Schema Definition Language“ ausgeben.

// data/printSchema.js
import { printSchema } from 'graphql';
import schema from './data/schema';
console.log(printSchema(schema));

Beim Start mit bash bin/printSchema erhalten sie die Ausgabe:

# Wurzelknoten, siehe "hi"
type Query {
   # Gibt einfach nur "Hello world!" zurück'
   hi: String
}

Umgekehrt lässt sich dieses Format als kompakte Alternative zur bisherigen Definition des Schemas verwenden. Dazu benutzen Entwickler einfach buildSchema aus dem Modul graphql:

// Listing 4
// data/schema.js
import { buildSchema } from 'graphql';

const schema = buildSchema(`
#
# „Wurzelknoten“
#
type Query {
   # Gibt einfach nur "Hello world!" zurück'
   hi: String
}
`);
export default schema;

Neben der Typdefinition muss natürlich auch die Logik implementiert werden, um bei Abfragen konkrete Werte zu erhalten. Im Server setzen Entwickler dazu die Definition des Wurzelknotens als Wert für rootValue, von dem aus alle anderen Knoten erreicht werden. Dazu müssen sie nur sogenannte resolver hinzufügen. Dazu gleich noch mehr. Der Rückgabewert der Funktion hi repräsentiert hier den Wert für das Feld hi von oben.

// Listing 5
// ... in server.js :
app.use('/graphql‘, expressGraphQL(req => ({
    schema,    
    rootValue: {
      hi: () => 'Hello world!'
    },
    graphiql: true
})));

Auch wenn GraphQL nur baumartige Strukturen zurückliefert, kann jede Abfrage auch Daten aus einem zyklischen Graphen auslesen. Ein Beispiel macht das deutlich: Die Suche bei Twitter nach allen Followern der Follower eines Twitter-Nutzers enthält typischerweise auch den Startknoten, wenn sich Twitter-Nutzer gegenseitig folgen. Mit solchen Abfragen wächst die Ergebnismenge natürlich schnell exponentiell an. Als Lösung gibt es in der Sangria-Scala-Bibliothek ein Modul, das die Abfrage­komplexität anhand der Zahl der Ebenen abschätzt.

Resolver

  • Über Resolver können GraphQL-Entwickler Daten aus einer beliebigen Datenquelle abrufen. Dabei gibt es verschiedene Typen:
  • konstanter Wert/Objekt
  • eine Funktion, etwa:
    new Date().getFullYear()
  • eine Funktion, die ein Promise zurückgibt, das asynchron aufgelöst wird, beispielsweise: fetch(„from_url“)
  • keine explizite Funktion/fehlend: Wenn kein Resolver definiert ist, leitet GraphQL den Wert automatisch aus einer Eigenschaft des Objektes mit demselben Namen ab. Entwickler können es beispielsweise dann verwenden, wenn sie mit dem ES6 Spread Operator die Werte aus der JSON-Antwort direkt übernehmen.

In den resolver-Methoden lassen sich Argumente verwenden, was für alle Abfragen nötig ist. In diesem Beispiel lässt sich so die Suche queryArtists(„byName“) parametrisieren, was in der SDL dann so definiert wird:

type Query {
  queryArtists(byName: String = "Xul Zolar"): [Artist]
}

Promise-Objekte sind sehr interessant, weil mit ihnen viele asynchron laufende Datenabfragen möglich sind, ohne dass Anwender einzeln auf die Ergebnisse warten müssen. Dadurch kann man alle mächtigen Bibliotheken ohne großen Aufwand ­integrieren und nutzen, wie zum Beispiel Mongoose oder die Github-, ­Twitter- oder beliebige andere Client-Bibliotheken.

Übrigens: GraphQL erlaubt auch modifizierende Operationen (sogenannte „mutations“) und Benachrichtigungen des Clients per Subscribe-Mechanismus (sogenannte „subscriptions“). Die Abfragesprache ist hierbei ebenfalls unabhängig vom Protokoll: Programmierer können also neben Websockets zum Beispiel auch MQTT verwenden, was sich für Internet-of-Things-Anwendungen etabliert hat.

Weitere Details zum Umgang mit GraphQL, etwa zur Implementierung eines Resolvers, um die Abfrage der REST-API zu kapseln und damit einen GraphQL-API-Gateway aufzubauen, oder zur Implementierung der GraphQL-Schnittstelle für die Nutzung von Client aus, finden Entwickler in einer umfangreichen Blogreihe.

Bereit für den Produktiveinsatz

GraphQL spielt gegenüber REST dann seine Vorteile aus, wenn es eine exakte Definition gibt, welche Daten für eine Anwendung benötigt werden. Darüber hinaus ist es ideal für Abfragen durch Aggregation auf der Serverseite mit nur einem Request – also für mobile Verbindungen. Beim Einsatz von GraphQL sollte der Zugriff auf zusammenhängende Daten möglich sein, sodass sich die API-Entwicklung von der Client-Seite aus passend treiben lässt. Die Praxistauglichkeit von GraphQL zeigt nicht zuletzt die schnelle Adaption durch Entwickler und große Unternehmen.

Eine längere Fassung des Artikels ist im Softwerker-Magazin der codecentric AG erschienen.

Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Schreib den ersten Kommentar!