Skip to content

Commit 3b44d5d

Browse files
UrigoyaacovCR
andauthored
Subscriptions docs suggestions (#4435)
Adding some suggestions to the subscriptions section: As mentioned in [this comment](#4406 (comment)), the `graphql-subscriptions` library is not maintained ([reference](apollographql/graphql-subscriptions#240)) I've made a change to recommend another library for the solution. In order to move this our of draft, @enisdenjo @ardatan I believe we'll need to publish a README specifically for that library. I've also changed the comment about WebSockets and SSE, I'm not sure if we want to say that most people use WebSockets? --------- Co-authored-by: Yaacov Rydzinski <yaacovCR@gmail.com>
1 parent e3c0dd8 commit 3b44d5d

1 file changed

Lines changed: 43 additions & 13 deletions

File tree

website/pages/docs/subscriptions.mdx

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ This guide covers how to implement subscriptions in GraphQL.js, when to use them
1212

1313
A subscription is a GraphQL operation that delivers ongoing results to the client when a specific event happens. Unlike queries or mutations, which return a single response, a subscription delivers data over time through a persistent connection.
1414

15-
GraphQL.js implements the subscription execution algorithm, but it's up to you to connect it to your event system and transport layer. Most implementations use WebSockets for transport, though any full-duplex protocol can work.
15+
GraphQL.js implements the subscription execution algorithm, but it's up to you to connect it to your event system and transport layer. Common transport options include WebSockets and Server-Sent Events (SSE).
16+
For more context on the advantages of each approach, consider a [general comparison of WebSockets and SSE](https://websocket.org/comparisons/sse/) as well as [GraphQL Yoga's breakdown with respect to GraphQL](https://the-guild.dev/graphql/yoga-server/docs/features/subscriptions#sse-vs-websocket).
1617

1718
## How execution works
1819

@@ -85,30 +86,59 @@ GraphQL.js supports subscription execution, but you’re responsible for setting
8586
- An event-publishing mechanism
8687
- A transport layer to maintain the connection
8788

88-
The following examples use the [`graphql-subscriptions`](https://github.com/apollographql/graphql-subscriptions) package to set up an in-memory event system.
89+
The following examples use a small in-memory pub/sub helper to set up an event
90+
system for local development.
8991

9092
### Install dependencies
9193

9294
Start by installing the necessary packages:
9395

9496
```bash
95-
npm install graphql graphql-subscriptions
97+
npm install graphql
9698
```
9799

98-
To serve subscriptions over a network, you’ll also need a transport implementation. One option is [`graphql-ws`](https://github.com/enisdenjo/graphql-ws), a community-maintained WebSocket library. This guide focuses on schema-level implementation.
100+
To serve subscriptions over a network, you’ll also need a transport implementation. Two common options are [`graphql-ws`](https://github.com/enisdenjo/graphql-ws), a community-maintained WebSocket library, and [`graphql-sse`](https://github.com/enisdenjo/graphql-sse), a community-maintained Server-Sent Events library. This guide focuses on schema-level implementation.
99101

100102
### Set up a pub/sub instance
101103

102-
Create a `PubSub` instance to manage your in-memory event system:
104+
In production, subscriptions are typically backed by a robust pub/sub system
105+
that can span processes and servers. For this demonstration, you can use an
106+
in-memory pub/sub system of your choice, or an implementation such as the
107+
following:
103108

104-
```js
105-
import { PubSub } from 'graphql-subscriptions';
109+
```ts
110+
import { EventEmitter, on } from 'node:events';
111+
112+
export class InMemoryPubSub<T extends Record<string, unknown>> {
113+
private emitter = new EventEmitter();
114+
115+
publish<K extends keyof T & string>(topic: K, value: T[K]): boolean {
116+
return this.emitter.emit(topic, value);
117+
}
118+
119+
async *subscribe<K extends keyof T & string>(
120+
topic: K,
121+
signal?: AbortSignal,
122+
): AsyncGenerator<T[K], void, unknown> {
123+
for await (const [value] of on(this.emitter, topic, { signal })) {
124+
yield value as T[K];
125+
}
126+
}
127+
}
128+
```
129+
130+
Then create a typed pub/sub instance for the subscription events in your schema:
131+
132+
```ts
133+
type PubSubEvents = {
134+
MESSAGE_SENT: { messageSent: string };
135+
};
106136

107-
const pubsub = new PubSub();
137+
const pubsub = new InMemoryPubSub<PubSubEvents>();
108138
```
109139

110-
This `pubsub` object provides `publish` and `asyncIterator` methods, allowing
111-
you to broadcast and listen for events.
140+
This `pubsub` object provides `publish` and `subscribe` methods, allowing you to
141+
broadcast and listen for events.
112142

113143
### Define a subscription type
114144

@@ -124,7 +154,7 @@ const SubscriptionType = new GraphQLObjectType({
124154
fields: {
125155
messageSent: {
126156
type: GraphQLString,
127-
subscribe: () => pubsub.asyncIterator(['MESSAGE_SENT']),
157+
subscribe: () => pubsub.subscribe('MESSAGE_SENT'),
128158
},
129159
},
130160
});
@@ -166,8 +196,8 @@ Whenever your server publishes a `MESSAGE_SENT` event, clients subscribed to
166196

167197
## Planning for production
168198

169-
The in-memory `PubSub` used in this example is suitable for development only.
170-
It does not support multiple server instances or distributed environments.
199+
The in-memory pub/sub helper used in this example is suitable for development
200+
only. It does not support multiple server instances or distributed environments.
171201

172202
For production, consider using a more robust event system such as:
173203

0 commit comments

Comments
 (0)