Français

Apprenez les patrons de conception de schémas GraphQL évolutifs pour créer des API robustes et maintenables répondant à un public mondial diversifié. Maîtrisez le schema stitching, la fédération et la modularisation.

Conception de schémas GraphQL : Patrons évolutifs pour les API globales

GraphQL s'est imposé comme une alternative puissante aux API REST traditionnelles, offrant aux clients la flexibilité de demander précisément les données dont ils ont besoin. Cependant, à mesure que votre API GraphQL gagne en complexité et en portée – en particulier lorsqu'elle dessert un public mondial avec des exigences de données diverses – une conception de schéma soignée devient cruciale pour la maintenabilité, l'évolutivité et la performance. Cet article explore plusieurs patrons de conception de schémas GraphQL évolutifs pour vous aider à construire des API robustes capables de gérer les exigences d'une application mondiale.

L'importance d'une conception de schéma évolutive

Un schéma GraphQL bien conçu est le fondement d'une API réussie. Il dicte la manière dont les clients peuvent interagir avec vos données et services. Une mauvaise conception de schéma peut entraîner un certain nombre de problèmes, notamment :

Pour les applications mondiales, ces problèmes sont amplifiés. Différentes régions peuvent avoir des exigences de données, des contraintes réglementaires et des attentes de performance différentes. Une conception de schéma évolutive vous permet de relever ces défis efficacement.

Principes clés d'une conception de schéma évolutive

Avant de nous plonger dans des patrons spécifiques, décrivons quelques principes clés qui devraient guider la conception de votre schéma :

Patrons de conception de schémas évolutifs

Voici plusieurs patrons de conception de schémas évolutifs que vous pouvez utiliser pour construire des API GraphQL robustes :

1. Schema Stitching

Le schema stitching vous permet de combiner plusieurs API GraphQL en un schéma unique et unifié. C'est particulièrement utile lorsque différentes équipes ou services sont responsables de différentes parties de vos données. C'est comme avoir plusieurs mini-API et les joindre via une API 'gateway' (passerelle).

Comment ça marche :

  1. Chaque équipe ou service expose sa propre API GraphQL avec son propre schéma.
  2. Un service de passerelle central utilise des outils de schema stitching (comme Apollo Federation ou GraphQL Mesh) pour fusionner ces schémas en un seul schéma unifié.
  3. Les clients interagissent avec le service de passerelle, qui achemine les requêtes vers les API sous-jacentes appropriées.

Exemple :

Imaginez une plateforme de e-commerce avec des API séparées pour les produits, les utilisateurs et les commandes. Chaque API a son propre schéma :

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

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

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

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

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

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

Le service de passerelle peut assembler ces schémas pour créer un schéma unifié :

  
    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
    }
  

Remarquez comment le type Order inclut maintenant des références à User et Product, même si ces types sont définis dans des API séparées. Ceci est réalisé grâce à des directives de schema stitching (comme @relation dans cet exemple).

Avantages :

Considérations :

2. Fédération de schémas (Schema Federation)

La fédération de schémas est une évolution du schema stitching, conçue pour remédier à certaines de ses limitations. Elle fournit une approche plus déclarative et standardisée pour composer des schémas GraphQL.

Comment ça marche :

  1. Chaque service expose une API GraphQL et annote son schéma avec des directives de fédération (par ex., @key, @extends, @external).
  2. Un service de passerelle central (utilisant Apollo Federation) utilise ces directives pour construire un supergraphe – une représentation de l'ensemble du schéma fédéré.
  3. Le service de passerelle utilise le supergraphe pour acheminer les requêtes vers les services sous-jacents appropriés et résoudre les dépendances.

Exemple :

En utilisant le même exemple de e-commerce, les schémas fédérés pourraient ressembler à ceci :

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

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

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

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

    # API Commandes
    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
    }
  

Remarquez l'utilisation des directives de fédération :

Avantages :

Considérations :

3. Conception de schéma modulaire

La conception de schéma modulaire consiste à décomposer un grand schéma monolithique en modules plus petits et plus gérables. Cela facilite la compréhension, la modification et la réutilisation des parties individuelles de votre API, même sans recourir à des schémas fédérés.

Comment ça marche :

  1. Identifiez les frontières logiques au sein de votre schéma (par ex., utilisateurs, produits, commandes).
  2. Créez des modules séparés pour chaque frontière, en définissant les types, les requêtes et les mutations liés à cette frontière.
  3. Utilisez des mécanismes d'import/export (en fonction de votre implémentation de serveur GraphQL) pour combiner les modules en un seul schéma unifié.

Exemple (avec JavaScript/Node.js) :

Créez des fichiers séparés pour chaque module :

  
    // 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
    }
  

Ensuite, combinez-les dans votre fichier de schéma principal :

  
    // 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;
  

Avantages :

Considérations :

4. Types Interface et Union

Les types Interface et Union vous permettent de définir des types abstraits qui peuvent être implémentés par plusieurs types concrets. C'est utile pour représenter des données polymorphes – des données qui peuvent prendre différentes formes selon le contexte.

Comment ça marche :

Exemple :

  
    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!]!
    }
  

Dans cet exemple, User et Product implémentent tous deux l'interface Node, qui définit un champ id commun. Le type union SearchResult représente un résultat de recherche qui peut être soit un User, soit un Product. Les clients peuvent interroger le champ `search` puis utiliser le champ `__typename` pour déterminer quel type de résultat ils ont reçu.

Avantages :

Considérations :

5. Patron de connexion (Connection Pattern)

Le patron de connexion est une manière standard d'implémenter la pagination dans les API GraphQL. Il fournit un moyen cohérent et efficace de récupérer de grandes listes de données par morceaux.

Comment ça marche :

Exemple :

  
    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!
    }
  

Avantages :

Considérations :

Considérations globales

Lors de la conception d'un schéma GraphQL pour un public mondial, tenez compte de ces facteurs supplémentaires :

Par exemple, considérons un champ de description de produit :


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

Cela permet aux clients de demander la description dans une langue spécifique. Si aucune langue n'est spécifiée, la valeur par défaut est l'anglais (`en`).

Conclusion

Une conception de schéma évolutive est essentielle pour construire des API GraphQL robustes et maintenables capables de gérer les exigences d'une application mondiale. En suivant les principes décrits dans cet article et en utilisant les patrons de conception appropriés, vous pouvez créer des API faciles à comprendre, à modifier et à étendre, tout en offrant d'excellentes performances et une grande évolutivité. N'oubliez pas de modulariser, composer et abstraire votre schéma, et de prendre en compte les besoins spécifiques de votre public mondial.

En adoptant ces patrons, vous pouvez libérer tout le potentiel de GraphQL et construire des API qui pourront alimenter vos applications pour les années à venir.