GraphQL-subscriptions: hoe ze over de lijn werken | We.Inc
Wat GraphQL-subscriptions zijn, de regel van één root field, een stapsgewijze doorloop van de graphql-ws-berichten, de SSE-optie, en wanneer polling de betere keuze is.
Een GraphQL-subscription is een langlopende operatie: de client stuurt één keer een subscription-document, en de server pusht een nieuw resultaat telkens wanneer het bijbehorende event plaatsvindt. GraphQL legt het transport niet vast. In de praktijk draait het over WebSockets, met het graphql-ws-protocol, of over Server-Sent Events. Elke subscription-operatie moet precies één root field selecteren.
Subscriptions, polling en opnieuw ophalen
Aanpak
Hoe updates binnenkomen
Past goed bij
Subscription
Server pusht een resultaat per event
Kleine, frequente wijzigingen die gebruikers direct willen zien
Polling
Client herhaalt een query op een timer
Data die af en toe verandert
Opnieuw ophalen na actie
Client vraagt opnieuw op na een stap van de gebruiker
Schermen die alleen veranderen als de gebruiker iets doet
Pushmelding
Een bericht buiten de app
Mobiele gebruikers bij wie de app gesloten is
De stepper hieronder speelt één subscription af over het graphql-ws-protocol, bericht voor bericht. Elke stap toont het JSON-frame dat over de socket gaat en welke kant het verstuurt, van de eerste handshake tot de laatste complete.
Druk op Volgende om frame voor frame door het gesprek te gaan.
Lees wie elk frame verstuurt en wat het betekent.
Let op het operatie-id: elk frame van één subscription draagt hetzelfde id.
Gebruik Terug of Opnieuw beginnen om een stap nog eens te bekijken.
Begin met polling en stap pas over op een subscription als een paar seconden vertraging de ervaring echt schaadt.
Stuur in elk resultaat een klein event, zoals het nieuwe bericht, in plaats van de hele lijst, en laat de client het samenvoegen.
Houd rekening met reconnects: na een weggevallen socket moet de client opnieuw subscriben en alles wat hij heeft gemist opnieuw ophalen.
Controleer de authenticatie bij het openen van de verbinding en opnieuw in elke resolver, omdat de rechten van een gebruiker tijdens een lange sessie kunnen veranderen.
Veelgestelde vragen
Waarom maar één root field per subscription?
Elke subscription hoort bij één stroom van events. graphql.org laat zien dat twee root fields in één subscription-operatie ongeldig is; schrijf in plaats daarvan twee subscriptions met een naam.
Welk WebSocket-subprotocol gebruikt graphql-ws?
Het onderhandelt graphql-transport-ws tijdens de handshake, met frametypes zoals connection_init, subscribe, next en complete. Andere GraphQL-WebSocket-libraries gebruiken mogelijk een ander protocol, dus controleer of client en server het eens zijn voordat u iets anders gaat debuggen.
Kunnen subscriptions zonder WebSockets draaien?
Ja. Het graphql-sse-protocol stuurt elk resultaat als een Server-Sent Event met de naam next en eindigt met complete. Het werkt over gewone HTTP, wat helpt achter proxy's die WebSocket-upgrades blokkeren.
Schalen subscriptions zoals queries?
Nee. graphql.org wijst erop dat elke geabonneerde client aan een serverinstantie vastzit en state nodig heeft zolang hij bestaat, dus u hebt ook een pub/sub-systeem nodig om events over servers te verspreiden.
Wat er gebeurt als u subscribet
De client stuurt een document dat begint met het keyword subscription, één root field kiest en de velden opsomt die hij in elk event wil. De server valideert het één keer en houdt het open.
Als er een overeenkomend event wordt gepubliceerd, zoals een nieuwe review, voert de server de selection set uit op dat event en stuurt hij het resultaat. Elk resultaat heeft de normale vorm met data en errors, dus clientcode leest het op dezelfde manier als een query.
Het graphql-ws-protocol in het kort
Na de WebSocket-upgrade stuurt de client connection_init, vaak met een auth-token in de payload, en wacht op connection_ack. Pas daarna mag hij subscribe-frames sturen. Elke subscribe draagt een uniek id, en elk next-, error- of complete-frame voor die operatie herhaalt het, zodat veel subscriptions één socket delen.
Beide kanten kunnen ping sturen en de andere antwoordt met pong. De server sluit de socket met code 4408 als connection_init niet op tijd binnenkomt, en met 4409 als een client een id hergebruikt dat nog loopt.
Wanneer polling de betere keuze is
Subscriptions vereisen sticky verbindingen, een pub/sub-laag en zorgvuldige clientcode voor opnieuw subscriben en race conditions. Voor een dashboard dat elke minuut ververst, is een query op een timer eenvoudiger en faalt hij netter.
graphql.org raadt subscriptions aan voor data die vaak en in kleine stappen verandert, en polling, pushmeldingen of opnieuw ophalen voor tragere data of mobiele clients met weinig bandbreedte.
Schema en clientcode
Een subscription-veld declareren
Subscription is een root type zoals Query en Mutation. Elk veld is één stroom die een client kan openen.
Subscriben met de graphql-ws-client
createClient opent de socket pas wanneer nodig, en iterate geeft een async iterator terug die één resultaat per event oplevert.
De regel van één root field
Splits twee stromen in twee operaties
Een enkele subscription met reviewCreated en nog een root field faalt bij validatie. Twee operaties met een naam werken wel.
Client stuurt connection_init
Direct verstuurd nadat de socket opent. De payload is vrij van vorm; servers lezen er vaak een token uit.
Server stuurt connection_ack
De server heeft de verbinding geaccepteerd. Daarvoor zou een subscribe-frame de socket sluiten met 4401 Unauthorized.
Client stuurt subscribe
Het id wordt door de client gekozen en moet uniek zijn onder zijn lopende operaties. De payload is de gebruikelijke query met variables.
Server stuurt next
Er is een review geplaatst, dus de server voerde de selection set uit en stuurde het resultaat onder hetzelfde id.
Server stuurt opnieuw next
Nog een event, nog een frame. Dit herhaalt zich zolang de subscription open blijft.
Client stuurt complete
De gebruiker verliet de pagina, dus de client stopt de operatie. De socket kan open blijven voor andere subscriptions.