@@ -34,6 +34,8 @@ ExecuteRequest(schema, document, operationName, variableValues, initialValue):
34
34
* Return {ExecuteQuery(operation, schema, coercedVariableValues, initialValue)}.
35
35
* Otherwise if {operation} is a mutation operation:
36
36
* Return {ExecuteMutation(operation, schema, coercedVariableValues, initialValue)}.
37
+ * Otherwise if {operation} is a subscription operation:
38
+ * Return {Subscribe(operation, schema, coercedVariableValues, initialValue)}.
37
39
38
40
GetOperation(document, operationName):
39
41
@@ -103,8 +105,10 @@ Note: This algorithm is very similar to {CoerceArgumentValues()}.
103
105
## Executing Operations
104
106
105
107
The type system, as described in the “Type System” section of the spec, must
106
- provide a query root object type. If mutations are supported, it must also
107
- provide a mutation root object type.
108
+ provide a query root object type. If mutations or subscriptions are supported,
109
+ it must also provide a mutation or subscription root object type, respectively.
110
+
111
+ ### Query
108
112
109
113
If the operation is a query, the result of the operation is the result of
110
114
executing the query’s top level selection set with the query root object type.
@@ -123,6 +127,8 @@ ExecuteQuery(query, schema, variableValues, initialValue):
123
127
selection set.
124
128
* Return an unordered map containing {data} and {errors}.
125
129
130
+ ### Mutation
131
+
126
132
If the operation is a mutation, the result of the operation is the result of
127
133
executing the mutation’s top level selection set on the mutation root
128
134
object type. This selection set should be executed serially.
@@ -143,6 +149,143 @@ ExecuteMutation(mutation, schema, variableValues, initialValue):
143
149
selection set.
144
150
* Return an unordered map containing {data} and {errors}.
145
151
152
+ ### Subscription
153
+
154
+ If the operation is a subscription, the result is an event stream called the
155
+ "Response Stream" where each event in the event stream is the result of
156
+ executing the operation for each new event on an underlying "Source Stream".
157
+
158
+ Executing a subscription creates a persistent function on the server that
159
+ maps an underlying Source Stream to a returned Response Stream.
160
+
161
+ Subscribe(subscription, schema, variableValues, initialValue):
162
+
163
+ * Let {sourceStream} be the result of running {CreateSourceEventStream(subscription, schema, variableValues, initialValue)}.
164
+ * Let {responseStream} be the result of running {MapSourceToResponseEvent(sourceStream, subscription, schema, variableValues)}
165
+ * Return {responseStream}.
166
+
167
+ Note: In large scale subscription systems, the {Subscribe} and {ExecuteSubscriptionEvent}
168
+ algorithms may be run on separate services to maintain predictable scaling
169
+ properties. See the section below on Supporting Subscriptions at Scale.
170
+
171
+ ** Event Streams**
172
+
173
+ An event stream represents a sequence of discrete events over time which can be
174
+ observed. As an example, a "Pub-Sub" system may produce an event stream when
175
+ "subscribing to a topic", with an event occurring on that event stream for each
176
+ "publish" to that topic. Event streams may produce an infinite sequence of
177
+ events or may complete at any point. Event streams may complete in response to
178
+ an error or simply because no more events will occur. An observer may at any
179
+ point decide to stop observing an event stream by cancelling it, after which it
180
+ must receive no more events from that event stream.
181
+
182
+ As an example, consider a chat application. To subscribe to new messages posted
183
+ to the chat room, the client sends a request like so:
184
+
185
+ ``` graphql
186
+ subscription NewMessages {
187
+ newMessage (roomId : 123 ) {
188
+ sender
189
+ text
190
+ }
191
+ }
192
+ ```
193
+
194
+ While the client is subscribed, whenever new messages are posted to chat room
195
+ with ID "123", the selection for "sender" and "text" will be evaluated and
196
+ published to the client, for example:
197
+
198
+ ``` js
199
+ {
200
+ " data" : {
201
+ " newMessage" : {
202
+ " sender" : " Hagrid" ,
203
+ " text" : " You're a wizard!"
204
+ }
205
+ }
206
+ }
207
+ ```
208
+
209
+ The "new message posted to chat room" could use a "Pub-Sub" system where the
210
+ chat room ID is the "topic" and each "publish" contains the sender and text.
211
+
212
+ ** Supporting Subscriptions at Scale**
213
+
214
+ Supporting subscriptions is a significant change for any GraphQL server. Query
215
+ and mutation operations are stateless, allowing scaling via cloning of GraphQL
216
+ server instances. Subscriptions, by contrast, are stateful and require
217
+ maintaining the GraphQL document, variables, and other context over the lifetime
218
+ of the subscription.
219
+
220
+ Consider the behavior of your system when state is lost due to the failure of a
221
+ single machine in a service. Durability and availability may be improved by
222
+ having separate dedicated services for managing subscription state and client
223
+ connectivity.
224
+
225
+ #### Source Stream
226
+
227
+ A Source Stream represents the sequence of events, each of which will
228
+ trigger a GraphQL execution corresponding to that event. Like field value
229
+ resolution, the logic to create a Source Stream is application-specific.
230
+
231
+ CreateSourceEventStream(subscription, schema, variableValues, initialValue):
232
+
233
+ * Let {subscriptionType} be the root Subscription type in {schema}.
234
+ * Assert: {subscriptionType} is an Object type.
235
+ * Let {selectionSet} be the top level Selection Set in {subscription}.
236
+ * Let {rootField} be the first top level field in {selectionSet}.
237
+ * Let {argumentValues} be the result of {CoerceArgumentValues(subscriptionType, rootField, variableValues)}.
238
+ * Let {fieldStream} be the result of running {ResolveFieldEventStream(subscriptionType, initialValue, rootField, argumentValues)}.
239
+ * Return {fieldStream}.
240
+
241
+ ResolveFieldEventStream(subscriptionType, rootValue, fieldName, argumentValues):
242
+ * Let {resolver} be the internal function provided by {subscriptionType} for
243
+ determining the resolved event stream of a subscription field named {fieldName}.
244
+ * Return the result of calling {resolver}, providing {rootValue} and {argumentValues}.
245
+
246
+ Note: This {ResolveFieldEventStream} algorithm is intentionally similar
247
+ to {ResolveFieldValue} to enable consistency when defining resolvers
248
+ on any operation type.
249
+
250
+ #### Response Stream
251
+
252
+ Each event in the underlying Source Stream triggers execution of the subscription
253
+ selection set using that event as a root value.
254
+
255
+ MapSourceToResponseEvent(sourceStream, subscription, schema, variableValues):
256
+
257
+ * Return a new event stream {responseStream} which yields events as follows:
258
+ * For each {event} on {sourceStream}:
259
+ * Let {response} be the result of running
260
+ {ExecuteSubscriptionEvent(subscription, schema, variableValues, event)}.
261
+ * Yield an event containing {response}.
262
+ * When {responseStream} completes: complete this event stream.
263
+
264
+ ExecuteSubscriptionEvent(subscription, schema, variableValues, initialValue):
265
+
266
+ * Let {subscriptionType} be the root Subscription type in {schema}.
267
+ * Assert: {subscriptionType} is an Object type.
268
+ * Let {selectionSet} be the top level Selection Set in {subscription}.
269
+ * Let {data} be the result of running
270
+ {ExecuteSelectionSet(selectionSet, subscriptionType, initialValue, variableValues)}
271
+ * normally* (allowing parallelization).
272
+ * Let {errors} be any * field errors* produced while executing the
273
+ selection set.
274
+ * Return an unordered map containing {data} and {errors}.
275
+
276
+ Note: The {ExecuteSubscriptionEvent} algorithm is intentionally similar to
277
+ {ExecuteQuery} since this is how the each event result is produced.
278
+
279
+ #### Unsubscribe
280
+
281
+ Unsubscribe cancels the Response Stream when a client no longer wishes to receive
282
+ payloads for a subscription. This may in turn also cancel the Source Stream.
283
+ This is also a good opportunity to clean up any other resources used by
284
+ the subscription.
285
+
286
+ Unsubscribe(responseStream)
287
+
288
+ * Cancel {responseStream}
146
289
147
290
## Executing Selection Sets
148
291
0 commit comments