Skip to content

Commit 3bc7205

Browse files
committed
WIP: GraphQL SSE Single Connection mode
1 parent 53b92b1 commit 3bc7205

File tree

4 files changed

+203
-136
lines changed

4 files changed

+203
-136
lines changed

packages/graphql-yoga/src/plugins/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ export interface OnResultProcessEventPayload {
152152
resultProcessor: ResultProcessor,
153153
acceptedMediaType: string,
154154
): void
155+
fetchAPI: FetchAPI
156+
endResponse(response: Response): void
155157
}
156158

157159
export type OnResponseHook<TServerContext> = (

packages/graphql-yoga/src/process-request.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export async function processResult({
2727
const acceptableMediaTypes: string[] = []
2828
let acceptedMediaType = '*/*'
2929

30+
let earlyResponse: Response | undefined
3031
for (const onResultProcessHook of onResultProcessHooks) {
3132
await onResultProcessHook({
3233
request,
@@ -37,7 +38,14 @@ export async function processResult({
3738
resultProcessor = newResultProcessor
3839
acceptedMediaType = newAcceptedMimeType
3940
},
41+
fetchAPI,
42+
endResponse(response) {
43+
earlyResponse = response
44+
},
4045
})
46+
if (earlyResponse) {
47+
return earlyResponse
48+
}
4149
}
4250

4351
// If no result processor found for this result, return an error

packages/plugins/graphql-sse/__tests__/graphql-sse.spec.ts

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -33,37 +33,46 @@ describe('graphql-sse', () => {
3333
const yoga = createYoga({
3434
schema,
3535
plugins: [useGraphQLSSE()],
36+
sse: {
37+
graphqlSSEDistinctConnections: true,
38+
},
3639
maskedErrors: false,
3740
})
3841

42+
let client: ReturnType<typeof createClient>
43+
44+
afterEach(() => {
45+
client?.dispose()
46+
})
47+
3948
it('should stream using distinct connection mode', async () => {
40-
const client = createClient({
41-
url: 'http://yoga/graphql/stream',
49+
client = createClient({
50+
url: 'http://yoga/graphql',
4251
fetchFn: yoga.fetch,
4352
abortControllerImpl: yoga.fetchAPI.AbortController,
4453
singleConnection: false, // distinct connection mode
4554
retryAttempts: 0,
4655
})
4756

48-
await expect(
49-
new Promise((resolve, reject) => {
50-
const msgs: unknown[] = []
51-
client.subscribe(
52-
{
53-
query: /* GraphQL */ `
54-
subscription {
55-
greetings
56-
}
57-
`,
58-
},
59-
{
60-
next: (msg) => msgs.push(msg),
61-
error: reject,
62-
complete: () => resolve(msgs),
63-
},
64-
)
65-
}),
66-
).resolves.toMatchInlineSnapshot(`
57+
const result = await new Promise((resolve, reject) => {
58+
const msgs: unknown[] = []
59+
client.subscribe(
60+
{
61+
query: /* GraphQL */ `
62+
subscription {
63+
greetings
64+
}
65+
`,
66+
},
67+
{
68+
next: (msg) => msgs.push(msg),
69+
error: reject,
70+
complete: () => resolve(msgs),
71+
},
72+
)
73+
})
74+
75+
expect(result).toMatchInlineSnapshot(`
6776
[
6877
{
6978
"data": {
@@ -92,39 +101,37 @@ describe('graphql-sse', () => {
92101
},
93102
]
94103
`)
95-
96-
client.dispose()
97104
})
98105

99106
it('should stream using single connection and lazy mode', async () => {
100-
const client = createClient({
101-
url: 'http://yoga/graphql/stream',
107+
client = createClient({
108+
url: 'http://yoga/graphql',
102109
fetchFn: yoga.fetch,
103110
abortControllerImpl: yoga.fetchAPI.AbortController,
104111
singleConnection: true, // single connection mode
105112
lazy: true,
106113
retryAttempts: 0,
107114
})
108115

109-
await expect(
110-
new Promise((resolve, reject) => {
111-
const msgs: unknown[] = []
112-
client.subscribe(
113-
{
114-
query: /* GraphQL */ `
115-
subscription {
116-
greetings
117-
}
118-
`,
119-
},
120-
{
121-
next: (msg) => msgs.push(msg),
122-
error: reject,
123-
complete: () => resolve(msgs),
124-
},
125-
)
126-
}),
127-
).resolves.toMatchInlineSnapshot(`
116+
const result = await new Promise((resolve, reject) => {
117+
const msgs: unknown[] = []
118+
client.subscribe(
119+
{
120+
query: /* GraphQL */ `
121+
subscription {
122+
greetings
123+
}
124+
`,
125+
},
126+
{
127+
next: (msg) => msgs.push(msg),
128+
error: reject,
129+
complete: () => resolve(msgs),
130+
},
131+
)
132+
})
133+
134+
expect(result).toMatchInlineSnapshot(`
128135
[
129136
{
130137
"data": {
@@ -153,39 +160,37 @@ describe('graphql-sse', () => {
153160
},
154161
]
155162
`)
156-
157-
client.dispose()
158163
})
159164

160165
it('should stream using single connection and non-lazy mode', async () => {
161-
const client = createClient({
162-
url: 'http://yoga/graphql/stream',
166+
client = createClient({
167+
url: 'http://yoga/graphql',
163168
fetchFn: yoga.fetch,
164169
abortControllerImpl: yoga.fetchAPI.AbortController,
165170
singleConnection: true, // single connection mode
166171
lazy: false,
167172
retryAttempts: 0,
168173
})
169174

170-
await expect(
171-
new Promise((resolve, reject) => {
172-
const msgs: unknown[] = []
173-
client.subscribe(
174-
{
175-
query: /* GraphQL */ `
176-
subscription {
177-
greetings
178-
}
179-
`,
180-
},
181-
{
182-
next: (msg) => msgs.push(msg),
183-
error: reject,
184-
complete: () => resolve(msgs),
185-
},
186-
)
187-
}),
188-
).resolves.toMatchInlineSnapshot(`
175+
const result = await new Promise((resolve, reject) => {
176+
const msgs: unknown[] = []
177+
client.subscribe(
178+
{
179+
query: /* GraphQL */ `
180+
subscription {
181+
greetings
182+
}
183+
`,
184+
},
185+
{
186+
next: (msg) => msgs.push(msg),
187+
error: reject,
188+
complete: () => resolve(msgs),
189+
},
190+
)
191+
})
192+
193+
expect(result).toMatchInlineSnapshot(`
189194
[
190195
{
191196
"data": {
@@ -214,8 +219,6 @@ describe('graphql-sse', () => {
214219
},
215220
]
216221
`)
217-
218-
client.dispose()
219222
})
220223

221224
it('should use CORS settings from the server', async () => {
@@ -231,7 +234,7 @@ describe('graphql-sse', () => {
231234
maskedErrors: false,
232235
})
233236

234-
const res = await yoga.fetch('http://yoga/graphql/stream', {
237+
const res = await yoga.fetch('http://yoga/graphql', {
235238
method: 'OPTIONS',
236239
headers: {
237240
origin: 'http://yoga',

0 commit comments

Comments
 (0)