Subscriptions GraphQL : leur fonctionnement sur le réseau | We.Inc
Ce que sont les subscriptions GraphQL, la règle du champ racine unique, un parcours pas à pas des messages graphql-ws, l'option SSE, et les cas où le polling est un meilleur choix.
Une subscription GraphQL est une opération de longue durée : le client envoie une seule fois un document de subscription, et le serveur pousse un nouveau résultat chaque fois que l'événement correspondant se produit. GraphQL n'impose pas le transport. En pratique, elle passe par des WebSockets, avec le protocole graphql-ws, ou par des Server-Sent Events. Chaque opération de subscription doit sélectionner exactement un champ racine.
Subscriptions, polling et nouvelle requête
Approche
Comment arrivent les mises à jour
Bien adaptée à
Subscription
Le serveur pousse un résultat par événement
Des changements petits et fréquents que les utilisateurs veulent voir immédiatement
Polling
Le client relance une requête à intervalle régulier
Des données qui changent de temps en temps
Nouvelle requête après action
Le client relance une requête après une action de l'utilisateur
Des écrans qui ne changent que lorsque l'utilisateur agit
Notification push
Un message en dehors de l'application
Les utilisateurs mobiles dont l'application est fermée
Le pas-à-pas ci-dessous rejoue une subscription sur le protocole graphql-ws, message par message. Chaque étape montre la trame JSON qui traverse le socket et le côté qui l'envoie, de la première poignée de main jusqu'au complete final.
Appuyez sur Suivant pour avancer dans l'échange une trame à la fois.
Lisez qui envoie chaque trame et ce qu'elle signifie.
Observez l'id de l'opération : toutes les trames d'une même subscription portent le même id.
Utilisez Retour ou Recommencer pour revoir une étape.
Commencez par du polling et ne passez à une subscription que si quelques secondes de délai nuisent vraiment à l'expérience.
Envoyez un petit événement dans chaque résultat, comme le nouveau message, plutôt que la liste entière, et laissez le client le fusionner.
Prévoyez les reconnexions : après une coupure du socket, le client doit se réabonner et récupérer tout ce qu'il a manqué.
Vérifiez l'authentification à l'ouverture de la connexion puis à nouveau dans chaque resolver, car les droits d'un utilisateur peuvent changer pendant une longue session.
Questions fréquentes
Pourquoi un seul champ racine par subscription ?
Chaque subscription correspond à un flux d'événements. graphql.org montre que placer deux champs racine dans une même opération de subscription est invalide ; écrivez plutôt deux subscriptions nommées.
Quel sous-protocole WebSocket graphql-ws utilise-t-il ?
Il négocie graphql-transport-ws pendant la poignée de main, avec des types de trames comme connection_init, subscribe, next et complete. D'autres bibliothèques WebSocket pour GraphQL peuvent utiliser un autre protocole : vérifiez que le client et le serveur sont d'accord avant de déboguer quoi que ce soit d'autre.
Les subscriptions peuvent-elles fonctionner sans WebSockets ?
Oui. Le protocole graphql-sse envoie chaque résultat sous forme de Server-Sent Event nommé next et termine par complete. Il fonctionne en HTTP simple, ce qui aide derrière les proxys qui bloquent les upgrades WebSocket.
Les subscriptions passent-elles à l'échelle comme les requêtes ?
Non. graphql.org souligne que chaque client abonné est lié à une instance de serveur et nécessite un état conservé pendant toute sa durée de vie : il faut donc aussi un système pub/sub pour diffuser les événements sur plusieurs serveurs.
Ce qui se passe quand vous vous abonnez
Le client envoie un document qui commence par le mot-clé subscription, choisit un champ racine et liste les champs qu'il veut dans chaque événement. Le serveur le valide une fois et le garde ouvert.
Quand quelque chose publie un événement correspondant, comme un nouvel avis, le serveur exécute le selection set sur cet événement et envoie le résultat. Chaque résultat a la forme habituelle data et errors : le code client le lit donc comme une requête.
Le protocole graphql-ws en bref
Après l'upgrade WebSocket, le client envoie connection_init, souvent avec un jeton d'authentification dans son payload, et attend connection_ack. Ce n'est qu'ensuite qu'il peut envoyer des trames subscribe. Chaque subscribe porte un id unique, que répète chaque trame next, error ou complete de cette opération : de nombreuses subscriptions partagent ainsi un seul socket.
Chaque côté peut envoyer ping et l'autre répond pong. Le serveur ferme le socket avec le code 4408 si connection_init n'arrive pas à temps, et avec 4409 quand un client réutilise un id encore en cours.
Quand le polling est un meilleur choix
Les subscriptions exigent des connexions persistantes, une couche pub/sub et un code client soigné pour les réabonnements et les situations de concurrence. Pour un tableau de bord qui se rafraîchit chaque minute, une requête à intervalle régulier est plus simple et échoue plus proprement.
graphql.org recommande les subscriptions pour les données qui changent souvent et par petites touches, et le polling, les notifications push ou les nouvelles requêtes pour les données plus lentes ou les clients mobiles à faible bande passante.
Schéma et code client
Déclarer un champ de subscription
Subscription est un type racine comme Query et Mutation. Chaque champ est un flux qu'un client peut ouvrir.
S'abonner avec le client graphql-ws
createClient ouvre le socket à la demande, et iterate renvoie un itérateur asynchrone qui produit un résultat par événement.
La règle du champ racine unique
Séparer deux flux en deux opérations
Une seule subscription qui liste reviewCreated et un autre champ racine échoue à la validation. Deux opérations nommées fonctionnent.
Le client envoie connection_init
Envoyé juste après l'ouverture du socket. Le payload est libre ; les serveurs y lisent souvent un jeton.
Le serveur envoie connection_ack
Le serveur a accepté la connexion. Avant cela, une trame subscribe fermerait le socket avec 4401 Unauthorized.
Le client envoie subscribe
L'id est choisi par le client et doit être unique parmi ses opérations en cours. Le payload contient la requête et les variables habituelles.
Le serveur envoie next
Un avis a été publié : le serveur a exécuté le selection set et envoyé le résultat sous le même id.
Le serveur envoie à nouveau next
Un autre événement, une autre trame. Cela se répète tant que la subscription reste ouverte.
Le client envoie complete
L'utilisateur a quitté la page, le client arrête donc l'opération. Le socket peut rester ouvert pour d'autres subscriptions.