Entfesseln Sie die Kraft der GraphQL Federation mit Schema Stitching. Erfahren Sie, wie Sie eine einheitliche GraphQL-API aus mehreren Diensten erstellen und so die Skalierbarkeit und Wartbarkeit verbessern.
GraphQL Federation: Schema Stitching – Ein umfassender Leitfaden
In der sich ständig weiterentwickelnden Landschaft der modernen Anwendungsentwicklung ist der Bedarf an skalierbaren und wartbaren Architekturen von größter Bedeutung geworden. Microservices, mit ihrer inhärenten Modularität und unabhängigen Bereitstellbarkeit, haben sich als eine beliebte Lösung erwiesen. Die Verwaltung zahlreicher Microservices kann jedoch zu Komplexität führen, insbesondere wenn es darum geht, Client-Anwendungen eine einheitliche API bereitzustellen. Hier kommen GraphQL Federation und insbesondere Schema Stitching ins Spiel.
Was ist GraphQL Federation?
GraphQL Federation ist eine leistungsstarke Architektur, die es Ihnen ermöglicht, eine einzige, einheitliche GraphQL-API aus mehreren zugrunde liegenden GraphQL-Diensten (oft Microservices repräsentierend) zu erstellen. Sie ermöglicht es Entwicklern, Daten über verschiedene Dienste hinweg abzufragen, als wäre es ein einziger Graph, was die Client-Erfahrung vereinfacht und die Notwendigkeit komplexer Orchestrierungslogik auf der Client-Seite reduziert.
Es gibt zwei primäre Ansätze für die GraphQL Federation:
- Schema Stitching: Dies beinhaltet das Kombinieren mehrerer GraphQL-Schemas zu einem einzigen, einheitlichen Schema auf der Gateway-Ebene. Es ist ein früherer Ansatz und stützt sich auf Bibliotheken, um die Schema-Kombination und die Abfrage-Delegation zu verwalten.
- Apollo Federation: Dies ist ein neuerer und robusterer Ansatz, der eine deklarative Schema-Sprache und einen dedizierten Abfrageplaner verwendet, um den Föderationsprozess zu verwalten. Er bietet erweiterte Funktionen wie Typ-Erweiterungen, Key-Direktiven und verteiltes Tracing.
Dieser Artikel konzentriert sich auf Schema Stitching und untersucht dessen Konzepte, Vorteile, Einschränkungen und praktische Umsetzung.
Grundlagen des Schema Stitching
Schema Stitching ist der Prozess des Zusammenführens mehrerer GraphQL-Schemas zu einem einzigen, zusammenhängenden Schema. Dieses einheitliche Schema fungiert als Fassade und verbirgt die Komplexität der zugrunde liegenden Dienste vor dem Client. Wenn ein Client eine Anfrage an das zusammengefügte Schema stellt, leitet das Gateway die Anfrage intelligent an den/die entsprechenden zugrunde liegenden Dienst(e) weiter, ruft die Daten ab und kombiniert die Ergebnisse, bevor sie an den Client zurückgegeben werden.
Stellen Sie es sich so vor: Sie haben mehrere Restaurants (Dienste), die jeweils auf unterschiedliche Küchen spezialisiert sind. Schema Stitching ist wie eine universelle Speisekarte, die alle Gerichte aus jedem Restaurant kombiniert. Wenn ein Kunde (Client) von der universellen Speisekarte bestellt, wird die Bestellung intelligent an die entsprechenden Restaurantküchen weitergeleitet, das Essen wird zubereitet und dann zu einer einzigen Lieferung für den Kunden zusammengefasst.
Schlüsselkonzepte beim Schema Stitching
- Remote-Schemas: Dies sind die einzelnen GraphQL-Schemas jedes zugrunde liegenden Dienstes. Jeder Dienst stellt sein eigenes Schema bereit, das die von ihm bereitgestellten Daten und Operationen definiert.
- Gateway: Das Gateway ist die zentrale Komponente, die für das Zusammenfügen der Remote-Schemas und die Bereitstellung des einheitlichen Schemas für den Client verantwortlich ist. Es empfängt Client-Anfragen, leitet sie an die entsprechenden Dienste weiter und kombiniert die Ergebnisse.
- Schema-Zusammenführung (Merging): Dies ist der Prozess des Kombinierens der Remote-Schemas zu einem einzigen Schema. Dies beinhaltet oft das Umbenennen von Typen und Feldern, um Konflikte zu vermeiden, und das Definieren von Beziehungen zwischen Typen über verschiedene Schemas hinweg.
- Abfrage-Delegation: Wenn ein Client eine Anfrage an das zusammengefügte Schema stellt, muss das Gateway die Anfrage an den/die entsprechenden zugrunde liegenden Dienst(e) delegieren, um die Daten abzurufen. Dies beinhaltet die Übersetzung der Client-Anfrage in eine Anfrage, die vom Remote-Dienst verstanden werden kann.
- Ergebnis-Aggregation: Nachdem das Gateway Daten von den zugrunde liegenden Diensten abgerufen hat, muss es die Ergebnisse zu einer einzigen Antwort kombinieren, die an den Client zurückgegeben werden kann. Dies beinhaltet oft die Transformation der Daten, um der Struktur des zusammengefügten Schemas zu entsprechen.
Vorteile von Schema Stitching
Schema Stitching bietet mehrere überzeugende Vorteile für Organisationen, die eine Microservices-Architektur einführen:
- Einheitliche API: Bietet eine einzige, konsistente API für Clients, was den Datenzugriff vereinfacht und die Notwendigkeit für Clients reduziert, direkt mit mehreren Diensten zu interagieren. Dies führt zu einer saubereren und intuitiveren Entwicklererfahrung.
- Reduzierte Client-Komplexität: Clients müssen nur mit dem einheitlichen Schema interagieren, was sie von der Komplexität der zugrunde liegenden Microservices-Architektur abschirmt. Dies vereinfacht die clientseitige Entwicklung und reduziert die Menge des auf dem Client erforderlichen Codes.
- Erhöhte Skalierbarkeit: Ermöglicht die unabhängige Skalierung einzelner Dienste basierend auf ihren spezifischen Anforderungen. Dies verbessert die allgemeine Skalierbarkeit und Widerstandsfähigkeit des Systems. Zum Beispiel kann ein Benutzer-Service mit hoher Auslastung skaliert werden, ohne andere Dienste wie den Produktkatalog zu beeinträchtigen.
- Verbesserte Wartbarkeit: Fördert Modularität und Trennung der Belange (Separation of Concerns), was die Wartung und Weiterentwicklung einzelner Dienste erleichtert. Änderungen an einem Dienst haben eine geringere Wahrscheinlichkeit, andere Dienste zu beeinträchtigen.
- Schrittweise Einführung: Kann inkrementell implementiert werden, sodass Sie schrittweise von einer monolithischen Architektur zu einer Microservices-Architektur migrieren können. Sie können damit beginnen, bestehende APIs zusammenzufügen und den Monolithen dann schrittweise in kleinere Dienste zu zerlegen.
Einschränkungen von Schema Stitching
Obwohl Schema Stitching zahlreiche Vorteile bietet, ist es wichtig, sich seiner Einschränkungen bewusst zu sein:
- Komplexität: Die Implementierung und Verwaltung von Schema Stitching kann komplex sein, insbesondere in großen und komplexen Systemen. Eine sorgfältige Planung und Gestaltung sind unerlässlich.
- Performance-Overhead: Das Gateway führt durch die zusätzliche Indirektionsschicht und die Notwendigkeit, Abfragen zu delegieren und Ergebnisse zu aggregieren, einen gewissen Performance-Overhead ein. Eine sorgfältige Optimierung ist entscheidend, um diesen Overhead zu minimieren.
- Schema-Konflikte: Beim Zusammenführen von Schemas aus verschiedenen Diensten können Konflikte auftreten, insbesondere wenn sie dieselben Typ- oder Feldnamen verwenden. Dies erfordert ein sorgfältiges Schema-Design und möglicherweise das Umbenennen von Typen und Feldern.
- Begrenzte erweiterte Funktionen: Im Vergleich zu Apollo Federation fehlen Schema Stitching einige erweiterte Funktionen wie Typ-Erweiterungen und Key-Direktiven, was die Verwaltung von Beziehungen zwischen Typen über verschiedene Schemas hinweg erschweren kann.
- Tooling-Reife: Das Tooling und das Ökosystem rund um Schema Stitching sind nicht so ausgereift wie die für Apollo Federation. Dies kann die Fehlersuche und -behebung erschweren.
Praktische Umsetzung von Schema Stitching
Gehen wir ein vereinfachtes Beispiel durch, wie man Schema Stitching mit Node.js und der graphql-tools
-Bibliothek (eine beliebte Wahl für Schema Stitching) implementiert. Dieses Beispiel umfasst zwei Microservices: einen User-Service und einen Product-Service.
1. Definieren der Remote-Schemas
Definieren Sie zuerst die GraphQL-Schemas für jeden der Remote-Dienste.
User-Service (user-service.js
):
const { buildSchema } = require('graphql');
const userSchema = buildSchema(`
type User {
id: ID!
name: String
email: String
}
type Query {
user(id: ID!): User
}
`);
const users = [
{ id: '1', name: 'Alice Smith', email: 'alice@example.com' },
{ id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];
const userRoot = {
user: (args) => users.find(user => user.id === args.id),
};
module.exports = {
schema: userSchema,
rootValue: userRoot,
};
Product-Service (product-service.js
):
const { buildSchema } = require('graphql');
const productSchema = buildSchema(`
type Product {
id: ID!
name: String
price: Float
userId: ID! # Fremdschlüssel zum User-Service
}
type Query {
product(id: ID!): Product
}
`);
const products = [
{ id: '101', name: 'Laptop', price: 1200, userId: '1' },
{ id: '102', name: 'Smartphone', price: 800, userId: '2' },
];
const productRoot = {
product: (args) => products.find(product => product.id === args.id),
};
module.exports = {
schema: productSchema,
rootValue: productRoot,
};
2. Erstellen des Gateway-Service
Erstellen Sie nun den Gateway-Service, der die beiden Schemas zusammenfügen wird.
Gateway-Service (gateway.js
):
const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');
async function createRemoteSchema(uri) {
const fetcher = async (params) => {
const response = await fetch(uri, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
return response.json();
};
const schema = await introspectSchema(fetcher);
return makeRemoteExecutableSchema({
schema,
fetcher,
});
}
async function main() {
const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
const productSchema = await createRemoteSchema('http://localhost:4002/graphql');
const stitchedSchema = stitchSchemas({
subschemas: [
{ schema: userSchema },
{ schema: productSchema },
],
typeDefs: `
extend type Product {
user: User
}
`,
resolvers: {
Product: {
user: {
selectionSet: `{ userId }`,
resolve(product, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: userSchema,
operation: 'query',
fieldName: 'user',
args: {
id: product.userId,
},
context,
info,
});
},
},
},
},
});
const app = express();
app.use('/graphql', graphqlHTTP({
schema: stitchedSchema,
graphiql: true,
}));
app.listen(4000, () => console.log('Gateway-Server läuft auf http://localhost:4000/graphql'));
}
main().catch(console.error);
3. Ausführen der Dienste
Sie müssen den User-Service und den Product-Service auf verschiedenen Ports ausführen. Zum Beispiel:
User-Service (Port 4001):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4001, () => console.log('User-Service läuft auf http://localhost:4001/graphql'));
Product-Service (Port 4002):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4002, () => console.log('Product-Service läuft auf http://localhost:4002/graphql'));
4. Abfragen des zusammengefügten Schemas
Jetzt können Sie das zusammengefügte Schema über das Gateway (das auf Port 4000 läuft) abfragen. Sie können eine Abfrage wie diese ausführen:
query {
product(id: "101") {
id
name
price
user {
id
name
email
}
}
}
Diese Abfrage ruft das Produkt mit der ID "101" ab und holt auch den zugehörigen Benutzer vom User-Service. Dies zeigt, wie Schema Stitching es Ihnen ermöglicht, Daten über mehrere Dienste hinweg in einer einzigen Anfrage abzufragen.
Fortgeschrittene Techniken für Schema Stitching
Über das einfache Beispiel hinaus gibt es einige fortgeschrittene Techniken, die zur Verbesserung Ihrer Schema-Stitching-Implementierung verwendet werden können:
- Schema-Delegation: Dies ermöglicht es Ihnen, Teile einer Abfrage basierend auf den angeforderten Daten an verschiedene Dienste zu delegieren. Zum Beispiel könnten Sie die Auflösung eines
User
-Typs an den User-Service und die Auflösung einesProduct
-Typs an den Product-Service delegieren. - Schema-Transformation: Dies beinhaltet die Modifizierung des Schemas eines Remote-Dienstes, bevor es in das einheitliche Schema eingefügt wird. Dies kann nützlich sein, um Typen und Felder umzubenennen, neue Felder hinzuzufügen oder bestehende Felder zu entfernen.
- Benutzerdefinierte Resolver: Sie können benutzerdefinierte Resolver im Gateway definieren, um komplexe Datentransformationen zu handhaben oder Daten von mehreren Diensten abzurufen und zu einem einzigen Ergebnis zu kombinieren.
- Kontext-Teilung (Context Sharing): Es ist oft notwendig, Kontextinformationen zwischen dem Gateway und den Remote-Diensten zu teilen, wie z.B. Authentifizierungstoken oder Benutzer-IDs. Dies kann durch die Weitergabe von Kontextinformationen im Rahmen des Abfrage-Delegationsprozesses erreicht werden.
- Fehlerbehandlung: Implementieren Sie eine robuste Fehlerbehandlung, um Fehler, die in den Remote-Diensten auftreten, ordnungsgemäß zu behandeln. Dies kann das Protokollieren von Fehlern, das Zurückgeben benutzerfreundlicher Fehlermeldungen oder das Wiederholen fehlgeschlagener Anfragen umfassen.
Die Wahl zwischen Schema Stitching und Apollo Federation
Obwohl Schema Stitching eine praktikable Option für GraphQL Federation ist, hat sich Apollo Federation aufgrund seiner fortschrittlichen Funktionen und der verbesserten Entwicklererfahrung zur beliebteren Wahl entwickelt. Hier ist ein Vergleich der beiden Ansätze:
Merkmal | Schema Stitching | Apollo Federation |
---|---|---|
Schema-Definition | Verwendet die bestehende GraphQL-Schema-Sprache | Verwendet eine deklarative Schema-Sprache mit Direktiven |
Abfrageplanung | Erfordert manuelle Abfrage-Delegation | Automatische Abfrageplanung durch das Apollo Gateway |
Typ-Erweiterungen | Begrenzte Unterstützung | Integrierte Unterstützung für Typ-Erweiterungen |
Key-Direktiven | Nicht unterstützt | Verwendet die @key -Direktive zur Identifizierung von Entitäten |
Verteiltes Tracing | Erfordert manuelle Implementierung | Integrierte Unterstützung für verteiltes Tracing |
Tooling und Ökosystem | Weniger ausgereiftes Tooling | Ausgereifteres Tooling und eine große Community |
Komplexität | Kann in großen Systemen komplex zu verwalten sein | Für große und komplexe Systeme konzipiert |
Wann Sie Schema Stitching wählen sollten:
- Sie haben bereits bestehende GraphQL-Dienste und möchten diese schnell kombinieren.
- Sie benötigen eine einfache Föderationslösung und keine erweiterten Funktionen.
- Sie haben begrenzte Ressourcen und möchten den Aufwand für die Einrichtung von Apollo Federation vermeiden.
Wann Sie Apollo Federation wählen sollten:
- Sie bauen ein großes und komplexes System mit mehreren Teams und Diensten.
- Sie benötigen erweiterte Funktionen wie Typ-Erweiterungen, Key-Direktiven und verteiltes Tracing.
- Sie wünschen sich eine robustere und skalierbarere Föderationslösung.
- Sie bevorzugen einen deklarativeren und automatisierteren Ansatz zur Föderation.
Praxisbeispiele und Anwendungsfälle
Hier sind einige Praxisbeispiele, wie GraphQL Federation, einschließlich Schema Stitching, verwendet werden kann:
- E-Commerce-Plattform: Eine E-Commerce-Plattform könnte GraphQL Federation verwenden, um Daten aus mehreren Diensten zu kombinieren, wie z. B. einem Produktkatalog-Service, einem Benutzer-Service, einem Bestell-Service und einem Zahlungs-Service. Dies ermöglicht es Clients, einfach alle Informationen abzurufen, die sie benötigen, um Produktdetails, Benutzerprofile, Bestellhistorie und Zahlungsinformationen anzuzeigen.
- Social-Media-Plattform: Eine Social-Media-Plattform könnte GraphQL Federation nutzen, um Daten aus Diensten zu kombinieren, die Benutzerprofile, Beiträge, Kommentare und Likes verwalten. Dies ermöglicht es Clients, effizient alle Informationen abzurufen, die zur Anzeige des Profils eines Benutzers, seiner Beiträge und der damit verbundenen Kommentare und Likes erforderlich sind.
- Finanzdienstleistungsanwendung: Eine Finanzdienstleistungsanwendung könnte GraphQL Federation verwenden, um Daten aus Diensten zu kombinieren, die Konten, Transaktionen und Investitionen verwalten. Dies ermöglicht es Clients, einfach alle Informationen abzurufen, die sie benötigen, um Kontostände, Transaktionshistorie und Anlageportfolios anzuzeigen.
- Content-Management-System (CMS): Ein CMS kann GraphQL Federation nutzen, um Daten aus verschiedenen Quellen wie Artikeln, Bildern, Videos und nutzergenerierten Inhalten zu integrieren. Dies ermöglicht eine einheitliche API, um alle Inhalte zu einem bestimmten Thema oder Autor abzurufen.
- Gesundheitswesen-Anwendung: Integrieren Sie Patientendaten aus verschiedenen Systemen wie elektronischen Gesundheitsakten (EHR), Laborergebnissen und Terminplanung. Dies bietet Ärzten einen einzigen Zugangspunkt zu umfassenden Patienteninformationen.
Best Practices für Schema Stitching
Um eine erfolgreiche Implementierung von Schema Stitching zu gewährleisten, befolgen Sie diese Best Practices:
- Planen Sie Ihr Schema sorgfältig: Bevor Sie mit dem Zusammenfügen von Schemas beginnen, planen Sie sorgfältig die Struktur des einheitlichen Schemas. Dazu gehört die Definition der Beziehungen zwischen Typen über verschiedene Schemas hinweg, das Umbenennen von Typen und Feldern zur Vermeidung von Konflikten und die Berücksichtigung der allgemeinen Datenzugriffsmuster.
- Verwenden Sie konsistente Namenskonventionen: Übernehmen Sie konsistente Namenskonventionen für Typen, Felder und Operationen in allen Diensten. Dies hilft, Konflikte zu vermeiden und das Verständnis des einheitlichen Schemas zu erleichtern.
- Dokumentieren Sie Ihr Schema: Dokumentieren Sie das einheitliche Schema gründlich, einschließlich Beschreibungen von Typen, Feldern und Operationen. Dies erleichtert es Entwicklern, das Schema zu verstehen und zu verwenden.
- Überwachen Sie die Leistung: Überwachen Sie die Leistung des Gateways und der Remote-Dienste, um Leistungsengpässe zu identifizieren und zu beheben. Verwenden Sie Tools wie verteiltes Tracing, um Anfragen über mehrere Dienste hinweg zu verfolgen.
- Implementieren Sie Sicherheit: Implementieren Sie geeignete Sicherheitsmaßnahmen, um das Gateway und die Remote-Dienste vor unbefugtem Zugriff zu schützen. Dies kann die Verwendung von Authentifizierungs- und Autorisierungsmechanismen sowie die Eingabevalidierung und Ausgabekodierung umfassen.
- Versionieren Sie Ihr Schema: Wenn Sie Ihre Schemas weiterentwickeln, versionieren Sie sie entsprechend, um sicherzustellen, dass Clients ältere Versionen des Schemas ohne Unterbrechung weiterverwenden können. Dies hilft, Breaking Changes zu vermeiden und die Abwärtskompatibilität zu gewährleisten.
- Automatisieren Sie die Bereitstellung: Automatisieren Sie die Bereitstellung des Gateways und der Remote-Dienste, um sicherzustellen, dass Änderungen schnell und zuverlässig bereitgestellt werden können. Dies hilft, das Fehlerrisiko zu verringern und die allgemeine Agilität des Systems zu verbessern.
Fazit
GraphQL Federation mit Schema Stitching bietet einen leistungsstarken Ansatz zum Erstellen einheitlicher APIs aus mehreren Diensten in einer Microservices-Architektur. Indem Sie die Kernkonzepte, Vorteile, Einschränkungen und Implementierungstechniken verstehen, können Sie Schema Stitching nutzen, um den Datenzugriff zu vereinfachen, die Skalierbarkeit zu verbessern und die Wartbarkeit zu erhöhen. Obwohl sich Apollo Federation als eine fortschrittlichere Lösung herauskristallisiert hat, bleibt Schema Stitching eine praktikable Option für einfachere Szenarien oder bei der Integration bestehender GraphQL-Dienste. Berücksichtigen Sie sorgfältig Ihre spezifischen Bedürfnisse und Anforderungen, um den besten Ansatz für Ihre Organisation zu wählen.