-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathgraphql-subscriptions.graphqljs.txt
144 lines (128 loc) · 9.97 KB
/
graphql-subscriptions.graphqljs.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ GRAPHQL-SUBSCRIPTIONS ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
VERSION ==> #0.3.0
#Implements graphQL subscriptions:
# - SubscriptionManager:
# - handles client "subscription" requests
# - push responses when desired
# - PubSubEngine is underlying event emitter interface
┌─────────────────────────┐
│ SUBSCRIPTIONMANAGER │
└─────────────────────────┘
new SubscriptionManager([OPTS]) #OPTS:
# - schema SCHEMA: must contain subscription definitions
# - pubsub PUBSUB: underlying event emitter
# - setupFunctions.CHANNEL(OPTS2, ARGS, 'EVENT')->{ EVENT: EVENT_OPTS }
# - fired on SUBMANAGER.subscribe(), to provide EVENT_OPTS
# - same OPTS2 as SUBMANAGER.subscribe()
# - ARGS: passed to EVENT(...)
#EVENT_OPTS:
# - filter(PAYLOAD, CONTEXT)->BOOL: fired when event triggered. If false, ignores that event
# - channelOptions OBJ: passed to PUBSUBENGINE.subscribe() OPTS
SUBMANAGR.publish('EVENT',PAYLOAD)#Calls PUBSUBENGINE.publish(...)
SUBMANAGER.subscribe(OPTS) #Does PUBSUBENGINE.subscribe('EVENT', FUNC(PAYLOAD)):
->PROMISE(SUB_ID) # - FUNC fires graphql(...) like a normal query:
# - using OPTS:
# - query 'QUERY': must be subscription query
# - operationName 'OPNAME'
# - variables VARIABLE
# - context [PROMISE_]CONTEXT[()]
# - using PAYLOAD as root value
# - query return value is passed to OPTS.callback(ERROR, OBJ)
# - can e.g. communicate it back to client using WebSocket
SUBMANAGER.unsubscribe(SUB_ID) #
┌──────────────────┐
│ PUBSUBENGINE │
└──────────────────┘
new PubSubEngine() #Event emitter interface, to be implemented
PUBSUBENGINE.publish
('EVENT', PAYLOAD) #
PUBSUBENGINE.subscribe
('EVENT', FUNC(PAYLOAD), OPTS)
->PROMISE(SUB_ID) #
PUBSUBENGINE.unsubscribe(SUB_ID) #
PubSub #Implementation that uses a local Event emitter
new RedisPubSub(OPTS) ##Implementation that uses Redis PubSub (using the main Node.js client)
##Package graphql-redis-subscriptions (1.1.5)
##OPTS:
## - redisConnection OBJ: passed to REDIS.createClient()
## - connectionListener([ERROR]):
## - listens to connection and error events
## - def: console.error on error event
## - triggerTransform('EVENT')->'EVENT'
┌───────────────┐
│ TRANSPORT │
└───────────────┘
SUBSCRIPTIONS-TRANSPORT-WS ==> ##Communicates using WebSocket (using "ws" package, see its doc)
##Uses WebSocket subchannel 'graphql-subscriptions'
##Is not a PubSubEngine, but uses SUBMANAGER
##Summary:
## - client initiates WebSocket connection
## - can pass COPTS.connectionParams, which the server uses to generate INIT_VAL, used as connection-wide context
## - client subscribes to channel, i.e. to GraphQL subscription, providing PAYLOAD.query|variables|operationName
## - server pushes message, i.e. execute GraphQL query, passing result to client callback
##Version 0.5.3
new SubscriptionServer ##Must specify:
(SOPTS, WS_OPTS) ## - SOPTS.subscriptionManager SUBMANAGER
## - WS_OPTS: passed to WS.Server()
##Automatically starts serving
new SubscriptionClient ##Can specify WEBSOCKET (def: WINDOW.WebSocket), e.g. for mocking. Available at SUB_CLIENT.client
(WS[S]_URL[, COPTS][, WEBSOCKET])##Automatically connects
##Sent messages are buffered while connecting
FLOW ==> ##New connection:
## - (client) SUB_CLIENT.onConnect(FUNC())
## - (client sends) type 'init', payload COPTS.connectionParams
## - (server) SOPTS.onConnect(COPTS.connectionParams, WSOCKET)->PROMISE(INIT_VAL)
## - if INIT_VAL false:
## - (server sends) type 'init_fail', error 'MESSAGE', and closes socket
## - (client) COPTS.connectionCallback('ERROR_MESSAGE')
## - otherwise:
## - (server sends) type 'init_success'
## - (client) COPTS.connectionCallback()
##Reconnection:
## - done on client disconnection, providing COPTS.reconnect true (def: false)
## - redo "New connection" except:
## - fires SUB_CLIENT.onReconnect(FUNC()) instead
## - resubscribe to channels
## - retries COPTS.reconnectionAttempts NUM times, with exponential backoff
##New channel:
## - (client) SUB_CLIENT.subscribe(PAYLOAD, CHANDLER(ERROR, OBJ))
## - (client sends) type 'subscription_start', id SUB_ID, payload PAYLOAD
## - (server) SOPTS.onSubscribe(PAYLOAD, OBJ, WSOCKET)->PROMISE(SUB_OPTS), with OBJ:
## - query|variables|operationName: from PAYLOAD
## - context INIT_VAL
## - (server) SUBMANAGER.subscribe(SOPTS)
## - (server sends) type 'subscription_success', id SUB_ID
## - (client) waits for max COPTS.timeout NUM (def: 5000)
##New server->client message:
## - i.e. after SUBMANAGER.subscribe() SOPTS.callback(ERROR[_STR], OBJ) gets triggered by SUBMANAGER.publish()
## - if ERROR:
## - (server sends) if ERROR, type 'subscription_data', id SUB_ID, payload {errors: ERROR.errors or OBJ_ARR: message ERROR_STR}
## - (client) CHANDLER(ERRORS_OBJ_ARR)
## - otherwise:
## - (server sends) otherwise, type 'subscription_data', id SUB_ID, payload OBJ
## - (client) CHANDLER(null, OBJ)
##New client->server message: not possible
##End channel:
## - (client) SUB_CLIENT.unsubscribe(SUB_ID) or SUB_CLIENT.unsubscribeAll()
## - (client sends) type 'subscription_end', id SUB_ID
## - (server) SUBMANAGER.unsubscribe(SUB_ID)
## - (server) SOPTS.onUnsubscribe(SUB_ID)
##Wront client message errors:
## - (server sends) type 'subscription_fail', id SUB_ID, payload {errors OBJ_ARR: message STR}
## - (client) CHANDLER(ERRORS_OBJ_ARR)
##Ping:
## - (server) sends type 'keepalive'
## - only if SOPTS.keepAlive NUM (in ms)
##End connection:
## - (client) SUB_CLIENT.onDisconnect(FUNC())
## - (server) SOPTS.onDisconnect(WSOCKET)
addGraphQLSubscriptions
(NETWORKINTERFACE, SUB_CLIENT) ##Helper for apollo client
┌───────────┐
│ TOOLS │
└───────────┘
autopublishMutationResults ##Wraps top-level mutation resolvers, so that PUBSUB.publish('ATTR', RPARENT) is fired each time resolver is called.
(SCHEMA, PUBSUB) ##I.e. if subscriptions have same shape and resolvers as mutation, will return same value as mutation, each time mutation is performed.
##From GraphQL-tools package