Skip to content

Commit 387b41a

Browse files
authored
Simplify subscriptions. (#860)
There was a secondary function in subscribe.js which doesn't correspond to a spec function or provide much value. It was an artifact of an earlier implementation. Collapsing it into the defined createSourceEventStream makes the alignment to spec more clear. It also moves this function below `subscribe` in the file, making its purpose more clear.
1 parent d657e99 commit 387b41a

File tree

1 file changed

+43
-52
lines changed

1 file changed

+43
-52
lines changed

src/subscription/subscribe.js

Lines changed: 43 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -25,51 +25,8 @@ import { GraphQLSchema } from '../type/schema';
2525
import invariant from '../jsutils/invariant';
2626
import mapAsyncIterator from './mapAsyncIterator';
2727

28-
import type {
29-
ExecutionContext,
30-
ExecutionResult,
31-
} from '../execution/execute';
32-
import type {
33-
DocumentNode,
34-
OperationDefinitionNode,
35-
} from '../language/ast';
36-
37-
/**
38-
* Implements the "CreateSourceEventStream" algorithm described in the
39-
* GraphQL specification, resolving the subscription source event stream.
40-
*
41-
* Returns an AsyncIterable
42-
*
43-
* A Source Stream represents the sequence of events, each of which is
44-
* expected to be used to trigger a GraphQL execution for that event.
45-
*/
46-
export function createSourceEventStream(
47-
schema: GraphQLSchema,
48-
document: DocumentNode,
49-
rootValue?: mixed,
50-
contextValue?: mixed,
51-
variableValues?: ?{[key: string]: mixed},
52-
operationName?: ?string,
53-
): AsyncIterable<mixed> {
54-
// If a valid context cannot be created due to incorrect arguments,
55-
// this will throw an error.
56-
const exeContext = buildExecutionContext(
57-
schema,
58-
document,
59-
rootValue,
60-
contextValue,
61-
variableValues,
62-
operationName
63-
);
64-
65-
// Call the `subscribe()` resolver or the default resolver to produce an
66-
// AsyncIterable yielding raw payloads.
67-
return resolveSubscription(
68-
exeContext,
69-
exeContext.operation,
70-
rootValue
71-
);
72-
}
28+
import type { ExecutionResult } from '../execution/execute';
29+
import type { DocumentNode } from '../language/ast';
7330

7431
/**
7532
* Implements the "Subscribe" algorithm described in the GraphQL specification.
@@ -97,6 +54,10 @@ export function subscribe(
9754

9855
// For each payload yielded from a subscription, map it over the normal
9956
// GraphQL `execute` function, with `payload` as the rootValue.
57+
// This implements the "MapSourceToResponseEvent" algorithm described in
58+
// the GraphQL specification. The `execute` function provides the
59+
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
60+
// "ExecuteQuery" algorithm, for which `execute` is also used.
10061
return mapAsyncIterator(
10162
subscription,
10263
payload => execute(
@@ -110,12 +71,40 @@ export function subscribe(
11071
);
11172
}
11273

113-
function resolveSubscription(
114-
exeContext: ExecutionContext,
115-
operation: OperationDefinitionNode,
116-
rootValue: mixed
74+
/**
75+
* Implements the "CreateSourceEventStream" algorithm described in the
76+
* GraphQL specification, resolving the subscription source event stream.
77+
*
78+
* Returns an AsyncIterable, may through a GraphQLError.
79+
*
80+
* A Source Stream represents the sequence of events, each of which is
81+
* expected to be used to trigger a GraphQL execution for that event.
82+
*
83+
* This may be useful when hosting the stateful subscription service in a
84+
* different process or machine than the stateless GraphQL execution engine,
85+
* or otherwise separating these two steps. For more on this, see the
86+
* "Supporting Subscriptions at Scale" information in the GraphQL specification.
87+
*/
88+
export function createSourceEventStream(
89+
schema: GraphQLSchema,
90+
document: DocumentNode,
91+
rootValue?: mixed,
92+
contextValue?: mixed,
93+
variableValues?: ?{[key: string]: mixed},
94+
operationName?: ?string,
11795
): AsyncIterable<mixed> {
118-
const type = getOperationRootType(exeContext.schema, exeContext.operation);
96+
// If a valid context cannot be created due to incorrect arguments,
97+
// this will throw an error.
98+
const exeContext = buildExecutionContext(
99+
schema,
100+
document,
101+
rootValue,
102+
contextValue,
103+
variableValues,
104+
operationName
105+
);
106+
107+
const type = getOperationRootType(schema, exeContext.operation);
119108
const fields = collectFields(
120109
exeContext,
121110
type,
@@ -131,12 +120,14 @@ function resolveSubscription(
131120
const responseName = responseNames[0];
132121
const fieldNodes = fields[responseName];
133122
const fieldNode = fieldNodes[0];
134-
const fieldDef = getFieldDef(exeContext.schema, type, fieldNode.name.value);
123+
const fieldDef = getFieldDef(schema, type, fieldNode.name.value);
135124
invariant(
136125
fieldDef,
137126
'This subscription is not defined by the schema.'
138127
);
139128

129+
// Call the `subscribe()` resolver or the default resolver to produce an
130+
// AsyncIterable yielding raw payloads.
140131
const resolveFn = fieldDef.subscribe || defaultFieldResolver;
141132

142133
const info = buildResolveInfo(
@@ -148,7 +139,7 @@ function resolveSubscription(
148139
);
149140

150141
// resolveFieldValueOrError implements the "ResolveFieldEventStream"
151-
// algorithm from GraphQL specification. It differs from
142+
// algorithm from GraphQL specification. It differs from
152143
// "ResolveFieldValue" due to providing a different `resolveFn`.
153144
const subscription = resolveFieldValueOrError(
154145
exeContext,

0 commit comments

Comments
 (0)