Now, let's create a simple PubSub instance - it is a simple pubsub implementation, based on EventEmitter. Alternative EventEmitter implementations can be passed by an options object
to the PubSub constructor.
Subscriptions resolvers are not a function, but an object with subscribe method, that returns AsyncIterable.
Now, the GraphQL engine knows that somethingChanged is a subscription, and every time we use pubsub.publish over this topic - it will publish it using the transport we use:
Note that the default PubSub implementation is intended for demo purposes. It only works if you have a single instance of your server and doesn't scale beyond a couple of connections.
For production usage you'll want to use one of the PubSub implementations backed by an external store. (e.g. Redis)
Filters
When publishing data to subscribers, we need to make sure that each subscriber gets only the data it needs.
To do so, we can use withFilter helper from this package, which wraps AsyncIterator with a filter function, and lets you control each publication for each user.
withFilter API:
asyncIteratorFn: (rootValue, args, context, info) => AsyncIterator<any> : A function that returns AsyncIterator you got from your pubsub.asyncIterator.
filterFn: (payload, variables, context, info) => boolean | Promise<boolean> - A filter function, executed with the payload (the published value), variables, context and operation info, must return boolean or Promise<boolean> indicating if the payload should pass to the subscriber.
For example, if somethingChanged would also accept a variable with the ID that is relevant, we can use the following code to filter according to it:
Note that when using withFilter, you don't need to wrap your return value with a function.
Channels Mapping
You can map multiple channels into the same subscription, for example when there are multiple events that trigger the same subscription in the GraphQL engine.
You can also manipulate the published payload, by adding resolve methods to your subscription:
constSOMETHING_UPDATED='something_updated';exportconstresolvers={Subscription: {somethingChanged: {resolve: (payload,args,context,info)=>{// Manipulate and return the new valuereturnpayload.somethingChanged;},subscribe: ()=>pubsub.asyncIterator(SOMETHING_UPDATED),},},}
Note that resolve methods execute aftersubscribe, so if the code in subscribe depends on a manipulated payload field, you will need to factor out the manipulation and call it from both subscribe and resolve.
Usage with callback listeners
Your database might have callback-based listeners for changes, for example something like this:
constlistenToNewMessages=(callback)=>{returndb.table('messages').listen(newMessage=>callback(newMessage));}// Kick off the listenerlistenToNewMessages(message=>{console.log(message);})
The callback function would be called every time a new message is saved in the database. Unfortunately, that doesn't play very well with async iterators out of the box because callbacks are push-based, where async iterators are pull-based.
We recommend using the callback-to-async-iterator module to convert your callback-based listener into an async iterator:
You can also implement a PubSub of your own, by using the exported abstract class PubSubEngine from this package. By using extends PubSubEngine you use the default asyncIterator method implementation; by using implements PubSubEngine you must implement your own AsyncIterator.
SubscriptionManager @deprecated
SubscriptionManager is the previous alternative for using graphql-js subscriptions directly, and it's now deprecated.
请发表评论