Chapitre 7.3GraphQL

Demander exactement ce dont on a besoin.

4 minutes de lecture

Dans le chapitre précédent, nous avons vu que REST souffre de deux problèmes récurrents : le sur-chargement (recevoir trop de données) et le sous-chargement (devoir faire plusieurs appels pour obtenir ce qu'on veut).

À partir de 2012, Facebook développe en interne un nouveau langage de requête pour résoudre exactement ces problèmes. L'entreprise le publie en open source en 2015, puis en confie la gouvernance à une fondation indépendante en 2018. Il s'appelle GraphQL.

Le principe

Avec REST, c'est le serveur qui décide quelles données il retourne. Avec GraphQL, c'est le client qui décrit exactement ce qu'il veut.

Imagine un restaurant. Avec REST, tu commandes "le menu du jour" et tu reçois entrée, plat, dessert, même si tu ne voulais que le plat. Avec GraphQL, tu commandes à la carte : "je veux le plat et le dessert, sans l'entrée".

Exemple concret :

Tu veux afficher un produit avec son nom, son prix et les trois derniers avis.

En REST, il faudrait potentiellement deux appels (un pour le produit, un pour les avis), et chaque appel retournerait des champs inutiles.

En GraphQL, tu envoies une seule requête qui décrit précisément ton besoin :

La requête envoyée par le client
{
    produit(id: 42) {
        nom
        prix
        avis(limite: 3) {
            note
            commentaire
        }
    }
}

Et tu reçois exactement ça, rien de plus :

La réponse du serveur
{
    "data": {
        "produit": {
            "nom": "Casque audio",
            "prix": 89.99,
            "avis": [
                { "note": 5, "commentaire": "Excellent son !" },
                { "note": 4, "commentaire": "Très confortable." },
                { "note": 3, "commentaire": "Correct pour le prix." }
            ]
        }
    }
}

La structure de la réponse est le décalque exact de la requête, à un enrobage près. GraphQL range toujours le résultat dans un champ "data", et les éventuels problèmes dans un champ "errors" à côté.

Un seul appel, zéro donnée inutile. C'est la promesse de GraphQL.

Lectures, écritures et abonnements

Une API REST distingue ce qu'on fait grâce aux verbes HTTP. GraphQL n'en utilise en pratique qu'un seul, POST, et n'expose qu'une seule adresse, généralement /graphql. La distinction se fait donc à l'intérieur de la requête, avec trois types d'opérations.

  • Les requêtes (query) : lire des données, comme dans l'exemple ci-dessus.
  • Les mutations (mutation) : modifier quelque chose, créer une commande, changer une adresse, annuler un abonnement.
  • Les abonnements (subscription) : recevoir en continu les mises à jour, par exemple les nouveaux messages d'une conversation. Ça repose sur une connexion permanente comme celles que nous verrons dans le chapitre sur le temps réel.

Cette adresse unique a une conséquence à laquelle personne ne pense au début. Comme tout passe par le même POST, une requête GraphQL qui échoue renvoie très souvent un code HTTP 200, avec l'erreur cachée dans le corps de la réponse. Tes outils de supervision, eux, voient donc une API en parfaite santé pendant que la moitié des écrans de l'application affichent une page blanche. Il faut instrumenter spécifiquement l'API pour retrouver la visibilité qu'on avait gratuitement avec REST.

Le schéma : un contrat explicite

L'une des grandes forces de GraphQL, c'est son schéma. Le serveur déclare explicitement toutes les données disponibles, leur type et leurs relations. Ce schéma sert de contrat entre le client et le serveur.

C'est comme un catalogue : tu sais exactement ce que tu peux commander avant même de passer commande. Si tu demandes un champ qui n'existe pas, tu obtiens une erreur claire immédiatement, sans avoir besoin de lancer l'application pour t'en rendre compte.

Ce schéma permet aussi de générer automatiquement la documentation. Des outils comme GraphiQL offrent un environnement interactif où tu peux explorer l'API, tester des requêtes et voir en temps réel les données disponibles. C'est un gain de productivité énorme pour les développeurs.

Il apporte au passage une solution élégante à un problème qui empoisonne les API REST, celui des versions. Comme le serveur sait exactement quel champ chaque client demande, il n'a pas besoin de figer une v1 et une v2 entières. Il ajoute librement de nouveaux champs, sans risque, puisque les anciens clients ne les demandent pas et ne les recevront donc jamais. Et quand un champ doit disparaître, on le marque comme déprécié dans le schéma, on regarde qui l'utilise encore, on prévient les intéressés, et on le supprime une fois le compteur tombé à zéro.

Cette mesure d'usage champ par champ est une information précieuse au-delà de la technique. Elle te dit littéralement quelles données de ton produit sont réellement affichées, et lesquelles personne n'a jamais regardées depuis leur mise en ligne.

Pourquoi tout le monde n'utilise pas GraphQL ?

Si GraphQL résout si bien les problèmes de REST, pourquoi n'a-t-il pas tout remplacé ?

La raison principale tient à la complexité côté serveur. Avec REST, chaque URL correspond à un traitement simple et prévisible. Avec GraphQL, le client peut demander n'importe quelle combinaison de données, ce qui rend le serveur plus complexe à construire et à optimiser.

Quelques défis concrets :

  • Les performances : un client mal intentionné ou mal conçu peut demander une requête gigantesque qui met le serveur à genoux. "Donne-moi tous les produits avec tous leurs avis avec tous les profils des auteurs avec tous leurs autres avis..." La requête s'emboîte à l'infini. On se protège en limitant la profondeur d'imbrication autorisée, ou en attribuant un coût à chaque champ et un budget à chaque client.
  • Le cache : avec REST, chaque URL a un contenu fixe qu'on peut facilement mettre en cache. Avec GraphQL, tout passe par la même adresse en POST et chaque requête est une combinaison différente, ce qui met hors-jeu le cache du navigateur et des CDN. Il faut reconstruire cette mécanique soi-même, plus finement.
  • La courbe d'apprentissage : GraphQL introduit de nouveaux concepts (schéma, résolveurs, mutations, abonnements) que l'équipe doit maîtriser. REST, basé sur HTTP qu'on connaît déjà, est plus accessible.
  • La sécurité : une seule adresse et une seule requête peuvent traverser dix domaines métier différents. Vérifier que l'utilisateur a bien le droit de voir chaque champ demandé se joue donc beaucoup plus finement qu'avec un contrôle par URL.

Le problème du N+1

Le piège le plus classique mérite qu'on s'y arrête, parce qu'il explique beaucoup de mises en production catastrophiques.

Reprends la requête du début, mais demande cette fois les cent premiers produits avec, pour chacun, le nom de son vendeur. Écrit naïvement, le serveur va aller chercher la liste des produits, puis interroger la base de données une fois par produit pour récupérer son vendeur. Une requête pour la liste, plus cent requêtes derrière. D'où le nom, N+1.

Le client, lui, n'a rien fait de mal, il a écrit trois lignes parfaitement innocentes. C'est le renversement fondamental de GraphQL, le coût d'un appel n'est plus visible dans l'appel. La parade existe et porte le nom de DataLoader, une technique qui regroupe les cent demandes de vendeurs en une seule requête, mais encore faut-il que l'équipe back-end l'ait mise en place partout.

REST ou GraphQL ?

Ce n'est pas un combat, ce sont des outils complémentaires.

  • REST est adapté aux API publiques, aux services simples, aux cas où les données demandées sont prévisibles. Sa simplicité est sa force.
  • GraphQL brille quand le front-end a des besoins variés et changeants : applications mobiles avec des écrans très différents, dashboards personnalisables, interfaces riches qui agrègent beaucoup de données.

Facebook a créé GraphQL parce que son application mobile avait des centaines d'écrans différents, chacun avec ses propres besoins en données. Faire une route REST pour chaque écran serait devenu ingérable.

Beaucoup d'entreprises utilisent les deux, REST pour les API publiques ou les services simples, GraphQL pour les frontends internes qui ont besoin de flexibilité. Un montage très courant consiste d'ailleurs à poser une couche GraphQL par dessus des services internes qui, eux, continuent de dialoguer en REST entre eux.

De mon expérience, GraphQL est un excellent choix quand l'équipe front-end et l'équipe back-end sont distinctes et que le front-end évolue plus vite que le back-end. Il permet au front-end d'avancer sans attendre que le back-end crée de nouvelles routes pour chaque nouveau besoin. À l'inverse, pour un projet porté par une petite équipe polyvalente, REST sera probablement plus simple à mettre en place et à maintenir.

PrécédentLa programmation objet Tous les chapitres