Skip to content

Commit a69635f

Browse files
committed
WIP: GraphQL SSE Single Connection mode
1 parent 09d23a4 commit a69635f

File tree

4 files changed

+201
-136
lines changed

4 files changed

+201
-136
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ export interface OnResultProcessEventPayload {
146146
resultProcessor: ResultProcessor,
147147
acceptedMediaType: string,
148148
): void
149+
fetchAPI: FetchAPI
150+
endResponse(response: Response): void
149151
}
150152

151153
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,
@@ -40,7 +41,14 @@ export async function processResult({
4041
resultProcessor = newResultProcessor
4142
acceptedMediaType = newAcceptedMimeType
4243
},
44+
fetchAPI,
45+
endResponse(response) {
46+
earlyResponse = response
47+
},
4348
})
49+
if (earlyResponse) {
50+
return earlyResponse
51+
}
4452
}
4553

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

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

Lines changed: 71 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -33,37 +33,44 @@ describe('graphql-sse', () => {
3333
const yoga = createYoga({
3434
schema,
3535
plugins: [useGraphQLSSE()],
36+
legacySse: false,
3637
maskedErrors: false,
3738
})
3839

40+
let client: ReturnType<typeof createClient>
41+
42+
afterEach(() => {
43+
client?.dispose()
44+
})
45+
3946
it('should stream using distinct connection mode', async () => {
40-
const client = createClient({
41-
url: 'http://yoga/graphql/stream',
47+
client = createClient({
48+
url: 'http://yoga/graphql',
4249
fetchFn: yoga.fetch,
4350
abortControllerImpl: yoga.fetchAPI.AbortController,
4451
singleConnection: false, // distinct connection mode
4552
retryAttempts: 0,
4653
})
4754

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(`
55+
const result = await new Promise((resolve, reject) => {
56+
const msgs: unknown[] = []
57+
client.subscribe(
58+
{
59+
query: /* GraphQL */ `
60+
subscription {
61+
greetings
62+
}
63+
`,
64+
},
65+
{
66+
next: (msg) => msgs.push(msg),
67+
error: reject,
68+
complete: () => resolve(msgs),
69+
},
70+
)
71+
})
72+
73+
expect(result).toMatchInlineSnapshot(`
6774
[
6875
{
6976
"data": {
@@ -92,39 +99,37 @@ describe('graphql-sse', () => {
9299
},
93100
]
94101
`)
95-
96-
client.dispose()
97102
})
98103

99104
it('should stream using single connection and lazy mode', async () => {
100-
const client = createClient({
101-
url: 'http://yoga/graphql/stream',
105+
client = createClient({
106+
url: 'http://yoga/graphql',
102107
fetchFn: yoga.fetch,
103108
abortControllerImpl: yoga.fetchAPI.AbortController,
104109
singleConnection: true, // single connection mode
105110
lazy: true,
106111
retryAttempts: 0,
107112
})
108113

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(`
114+
const result = await new Promise((resolve, reject) => {
115+
const msgs: unknown[] = []
116+
client.subscribe(
117+
{
118+
query: /* GraphQL */ `
119+
subscription {
120+
greetings
121+
}
122+
`,
123+
},
124+
{
125+
next: (msg) => msgs.push(msg),
126+
error: reject,
127+
complete: () => resolve(msgs),
128+
},
129+
)
130+
})
131+
132+
expect(result).toMatchInlineSnapshot(`
128133
[
129134
{
130135
"data": {
@@ -153,39 +158,37 @@ describe('graphql-sse', () => {
153158
},
154159
]
155160
`)
156-
157-
client.dispose()
158161
})
159162

160163
it('should stream using single connection and non-lazy mode', async () => {
161-
const client = createClient({
162-
url: 'http://yoga/graphql/stream',
164+
client = createClient({
165+
url: 'http://yoga/graphql',
163166
fetchFn: yoga.fetch,
164167
abortControllerImpl: yoga.fetchAPI.AbortController,
165168
singleConnection: true, // single connection mode
166169
lazy: false,
167170
retryAttempts: 0,
168171
})
169172

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(`
173+
const result = await new Promise((resolve, reject) => {
174+
const msgs: unknown[] = []
175+
client.subscribe(
176+
{
177+
query: /* GraphQL */ `
178+
subscription {
179+
greetings
180+
}
181+
`,
182+
},
183+
{
184+
next: (msg) => msgs.push(msg),
185+
error: reject,
186+
complete: () => resolve(msgs),
187+
},
188+
)
189+
})
190+
191+
expect(result).toMatchInlineSnapshot(`
189192
[
190193
{
191194
"data": {
@@ -214,8 +217,6 @@ describe('graphql-sse', () => {
214217
},
215218
]
216219
`)
217-
218-
client.dispose()
219220
})
220221

221222
it('should use CORS settings from the server', async () => {
@@ -231,7 +232,7 @@ describe('graphql-sse', () => {
231232
maskedErrors: false,
232233
})
233234

234-
const res = await yoga.fetch('http://yoga/graphql/stream', {
235+
const res = await yoga.fetch('http://yoga/graphql', {
235236
method: 'OPTIONS',
236237
headers: {
237238
origin: 'http://yoga',

0 commit comments

Comments
 (0)