Deutsch

Lernen Sie skalierbare GraphQL-Schema-Designmuster für robuste und wartbare APIs, die eine vielfältige globale Zielgruppe ansprechen. Meistern Sie Schema Stitching, Federation und Modularisierung.

GraphQL-Schema-Design: Skalierbare Muster für globale APIs

GraphQL hat sich als eine leistungsstarke Alternative zu traditionellen REST-APIs etabliert und bietet Clients die Flexibilität, genau die Daten anzufordern, die sie benötigen. Wenn Ihre GraphQL-API jedoch an Komplexität und Umfang zunimmt – insbesondere, wenn sie eine globale Zielgruppe mit unterschiedlichen Datenanforderungen bedient – wird ein sorgfältiges Schema-Design entscheidend für Wartbarkeit, Skalierbarkeit und Leistung. Dieser Artikel untersucht mehrere skalierbare GraphQL-Schema-Designmuster, die Ihnen helfen, robuste APIs zu erstellen, die den Anforderungen einer globalen Anwendung gewachsen sind.

Die Bedeutung eines skalierbaren Schema-Designs

Ein gut gestaltetes GraphQL-Schema ist die Grundlage einer erfolgreichen API. Es legt fest, wie Clients mit Ihren Daten und Diensten interagieren können. Ein schlechtes Schema-Design kann zu einer Reihe von Problemen führen, darunter:

Bei globalen Anwendungen verstärken sich diese Probleme. Verschiedene Regionen können unterschiedliche Datenanforderungen, regulatorische Beschränkungen und Leistungserwartungen haben. Ein skalierbares Schema-Design ermöglicht es Ihnen, diese Herausforderungen effektiv zu bewältigen.

Grundprinzipien des skalierbaren Schema-Designs

Bevor wir uns mit spezifischen Mustern befassen, lassen Sie uns einige Grundprinzipien skizzieren, die Ihr Schema-Design leiten sollten:

Skalierbare Schema-Designmuster

Hier sind mehrere skalierbare Schema-Designmuster, die Sie verwenden können, um robuste GraphQL-APIs zu erstellen:

1. Schema Stitching

Schema Stitching ermöglicht es Ihnen, mehrere GraphQL-APIs zu einem einzigen, einheitlichen Schema zu kombinieren. Dies ist besonders nützlich, wenn verschiedene Teams oder Dienste für unterschiedliche Teile Ihrer Daten verantwortlich sind. Es ist, als hätte man mehrere Mini-APIs, die über eine „Gateway“-API miteinander verbunden werden.

So funktioniert es:

  1. Jedes Team oder jeder Dienst stellt seine eigene GraphQL-API mit eigenem Schema bereit.
  2. Ein zentraler Gateway-Dienst verwendet Schema-Stitching-Tools (wie Apollo Federation oder GraphQL Mesh), um diese Schemas zu einem einzigen, einheitlichen Schema zusammenzuführen.
  3. Clients interagieren mit dem Gateway-Dienst, der Anfragen an die entsprechenden zugrunde liegenden APIs weiterleitet.

Beispiel:

Stellen Sie sich eine E-Commerce-Plattform mit separaten APIs für Produkte, Benutzer und Bestellungen vor. Jede API hat ihr eigenes Schema:

  
    # Produkte-API
    type Product {
      id: ID!
      name: String!
      price: Float!
    }

    type Query {
      product(id: ID!): Product
    }

    # Benutzer-API
    type User {
      id: ID!
      name: String!
      email: String!
    }

    type Query {
      user(id: ID!): User
    }

    # Bestellungen-API
    type Order {
      id: ID!
      userId: ID!
      productId: ID!
      quantity: Int!
    }

    type Query {
      order(id: ID!): Order
    }
  

Der Gateway-Dienst kann diese Schemas zusammenfügen, um ein einheitliches Schema zu erstellen:

  
    type Product {
      id: ID!
      name: String!
      price: Float!
    }

    type User {
      id: ID!
      name: String!
      email: String!
    }

    type Order {
      id: ID!
      user: User! @relation(field: "userId")
      product: Product! @relation(field: "productId")
      quantity: Int!
    }

    type Query {
      product(id: ID!): Product
      user(id: ID!): User
      order(id: ID!): Order
    }
  

Beachten Sie, wie der Typ Order jetzt Verweise auf User und Product enthält, obwohl diese Typen in separaten APIs definiert sind. Dies wird durch Schema-Stitching-Direktiven (wie @relation in diesem Beispiel) erreicht.

Vorteile:

Zu beachtende Aspekte:

2. Schema Federation

Schema Federation ist eine Weiterentwicklung des Schema Stitching, die entwickelt wurde, um einige seiner Einschränkungen zu beheben. Sie bietet einen deklarativeren und standardisierteren Ansatz zur Komposition von GraphQL-Schemas.

So funktioniert es:

  1. Jeder Dienst stellt eine GraphQL-API bereit und annotiert sein Schema mit Federation-Direktiven (z. B. @key, @extends, @external).
  2. Ein zentraler Gateway-Dienst (der Apollo Federation verwendet) nutzt diese Direktiven, um einen Supergraphen zu erstellen – eine Repräsentation des gesamten föderierten Schemas.
  3. Der Gateway-Dienst verwendet den Supergraphen, um Anfragen an die entsprechenden zugrunde liegenden Dienste weiterzuleiten und Abhängigkeiten aufzulösen.

Beispiel:

Unter Verwendung des gleichen E-Commerce-Beispiels könnten die föderierten Schemas so aussehen:

  
    # Produkte-API
    type Product @key(fields: "id") {
      id: ID!
      name: String!
      price: Float!
    }

    type Query {
      product(id: ID!): Product
    }

    # Benutzer-API
    type User @key(fields: "id") {
      id: ID!
      name: String!
      email: String!
    }

    type Query {
      user(id: ID!): User
    }

    # Bestellungen-API
    type Order {
      id: ID!
      userId: ID!
      productId: ID!
      quantity: Int!
      user: User! @requires(fields: "userId")
      product: Product! @requires(fields: "productId")
    }

    extend type Query {
      order(id: ID!): Order
    }
  

Beachten Sie die Verwendung von Federation-Direktiven:

Vorteile:

Zu beachtende Aspekte:

3. Modulares Schema-Design

Modulares Schema-Design beinhaltet die Aufteilung eines großen, monolithischen Schemas in kleinere, leichter zu verwaltende Module. Dies erleichtert das Verstehen, Ändern und Wiederverwenden einzelner Teile Ihrer API, auch ohne auf föderierte Schemas zurückzugreifen.

So funktioniert es:

  1. Identifizieren Sie logische Grenzen innerhalb Ihres Schemas (z. B. Benutzer, Produkte, Bestellungen).
  2. Erstellen Sie separate Module für jede Grenze und definieren Sie die Typen, Abfragen und Mutationen, die sich auf diese Grenze beziehen.
  3. Verwenden Sie Import-/Export-Mechanismen (abhängig von Ihrer GraphQL-Server-Implementierung), um die Module zu einem einzigen, einheitlichen Schema zu kombinieren.

Beispiel (mit JavaScript/Node.js):

Erstellen Sie separate Dateien für jedes Modul:

  
    // users.graphql
    type User {
      id: ID!
      name: String!
      email: String!
    }

    type Query {
      user(id: ID!): User
    }

    // products.graphql
    type Product {
      id: ID!
      name: String!
      price: Float!
    }

    type Query {
      product(id: ID!): Product
    }
  

Kombinieren Sie sie dann in Ihrer Haupt-Schemadatei:

  
    // schema.js
    const { makeExecutableSchema } = require('graphql-tools');
    const { typeDefs: userTypeDefs, resolvers: userResolvers } = require('./users');
    const { typeDefs: productTypeDefs, resolvers: productResolvers } = require('./products');

    const typeDefs = [
      userTypeDefs,
      productTypeDefs,
      ""
    ];

    const resolvers = {
      Query: {
        ...userResolvers.Query,
        ...productResolvers.Query,
      }
    };

    const schema = makeExecutableSchema({
      typeDefs,
      resolvers,
    });

    module.exports = schema;
  

Vorteile:

Zu beachtende Aspekte:

4. Interface- und Union-Typen

Interface- und Union-Typen ermöglichen es Ihnen, abstrakte Typen zu definieren, die von mehreren konkreten Typen implementiert werden können. Dies ist nützlich für die Darstellung polymorpher Daten – Daten, die je nach Kontext unterschiedliche Formen annehmen können.

So funktioniert es:

Beispiel:

  
    interface Node {
      id: ID!
    }

    type User implements Node {
      id: ID!
      name: String!
      email: String!
    }

    type Product implements Node {
      id: ID!
      name: String!
      price: Float!
    }

    union SearchResult = User | Product

    type Query {
      node(id: ID!): Node
      search(query: String!): [SearchResult!]!
    }
  

In diesem Beispiel implementieren sowohl User als auch Product das Node-Interface, das ein gemeinsames id-Feld definiert. Der Union-Typ SearchResult repräsentiert ein Suchergebnis, das entweder ein User oder ein Product sein kann. Clients können das Feld `search` abfragen und dann das Feld `__typename` verwenden, um festzustellen, welchen Ergebnistyp sie erhalten haben.

Vorteile:

Zu beachtende Aspekte:

5. Connection-Muster

Das Connection-Muster ist eine Standardmethode zur Implementierung der Paginierung in GraphQL-APIs. Es bietet eine konsistente und effiziente Möglichkeit, große Datenlisten in Blöcken abzurufen.

So funktioniert es:

Beispiel:

  
    type User {
      id: ID!
      name: String!
      email: String!
    }

    type UserEdge {
      node: User!
      cursor: String!
    }

    type UserConnection {
      edges: [UserEdge!]!
      pageInfo: PageInfo!
    }

    type PageInfo {
      hasNextPage: Boolean!
      hasPreviousPage: Boolean!
      startCursor: String
      endCursor: String
    }

    type Query {
      users(first: Int, after: String, last: Int, before: String): UserConnection!
    }
  

Vorteile:

Zu beachtende Aspekte:

Globale Überlegungen

Beim Entwurf eines GraphQL-Schemas für eine globale Zielgruppe sollten Sie diese zusätzlichen Faktoren berücksichtigen:

Betrachten Sie zum Beispiel ein Produktbeschreibungsfeld:


type Product {
 id: ID!
 name: String!
 description(language: String = "en"): String!
}

Dies ermöglicht es Clients, die Beschreibung in einer bestimmten Sprache anzufordern. Wenn keine Sprache angegeben wird, wird standardmäßig Englisch (`en`) verwendet.

Fazit

Ein skalierbares Schema-Design ist unerlässlich für die Erstellung robuster und wartbarer GraphQL-APIs, die den Anforderungen einer globalen Anwendung gewachsen sind. Indem Sie die in diesem Artikel beschriebenen Prinzipien befolgen und die geeigneten Designmuster verwenden, können Sie APIs erstellen, die leicht zu verstehen, zu ändern und zu erweitern sind und gleichzeitig eine hervorragende Leistung und Skalierbarkeit bieten. Denken Sie daran, Ihr Schema zu modularisieren, zu komponieren und zu abstrahieren und die spezifischen Bedürfnisse Ihrer globalen Zielgruppe zu berücksichtigen.

Indem Sie diese Muster anwenden, können Sie das volle Potenzial von GraphQL ausschöpfen und APIs erstellen, die Ihre Anwendungen für die kommenden Jahre antreiben können.