GraphQL subscription updates may broadcast data to multiple subscribers.
A broadcast is a subscription update which is executed once, then delivered to any number of subscribers. This reduces the time your server spends running GraphQL queries, since it doesn’t have to re-run the query for every subscriber.
But, take care: this approach risks leaking information to subscribers who shouldn’t receive it.
To enable broadcasts, add broadcast: true
to your subscription setup:
class MyAppSchema < GraphQL::Schema
# ...
use SomeSubscriptionImplementation,
broadcast: true # <----
end
Then, any broadcastable field can be configured with broadcastable: true
:
field :name, String, null: false,
broadcastable: true
When a subscription comes in where all of its fields are broadcastable: true
, then it will be handled as a broadcast.
Additionally, you can set default_broadcastable: true
:
class MyAppSchema < GraphQL::Schema
# ...
use SomeSubscriptionImplementation,
broadcast: true,
default_broadcastable: true # <----
end
With this setting, fields are broadcastable by default. Only a field with broadcastable: false
in its configuration will cause a subscription to be handled on a subscriber-by-subscriber basis.
GraphQL-Ruby can’t infer whether a field is broadcastable or not. You must configure it explicitly with broadcastable: true
or broadcastable: false
. (The subscription plugin also accepts default_broadcastable: true|false
.)
A field is broadcastable if all clients who request the field will see the same value. For example:
For fields like this, you can add broadcastable: true
.
A field is not broadcastable if its value is different for different clients. For example:
discussion { viewerCanModerate }
might be true for a moderator, but it shouldn’t be broadcasted to other viewers.These fields can be tagged with broadcastable: false
so that GraphQL-Ruby will handle them on a subscriber-by-subscriber basis.
If you want to use subscriptions but have a lot of non-broadcastable fields in your schema, consider building a new set of subscription fields with limited access to other schema objects. Instead, optimize those subscriptions for broacastability.
GraphQL-Ruby determines which subscribers can receive a broadcast by inspecting:
.trigger
. They must match the ones initially sent when subscribing. (Subscriptions always worked this way.)So, take care to set subscription_scope whenever a subscription should be implicitly scoped!
(See GraphQL::Subscriptions::Event#fingerprint
for the implementation of broadcast fingerprints.)
For testing purposes, you can confirm that a GraphQL query string is broadcastable by using Subscriptions#broadcastable?
:
subscription_string = "subscription { ... }"
MySchema.subscriptions.broadcastable?(subscription_string)
# => true or false
Use this in your application’s tests to make sure that broadcastable fields aren’t accidentally made non-broadcastable.
You can configure your generated Connection
and Edge
types to be broadcastable by setting default_broadcastable(true)
in their definition:
# app/types/base_connection.rb
class Types::BaseConnection < Types::BaseObject
include GraphQL::Types::Relay::ConnectionBehaviors
default_broadcastable(true)
end
# app/types/base_edge.rb
class Types::BaseEdge < Types::BaseObject
include GraphQL::Types::Relay::EdgeBehaviors
default_broadcastable(true)
end
(In your BaseObject
, you should also have connection_type_class(Types::BaseConnection)
and edge_type_class(Types::BaseEdge)
.)
PageInfo
is broadcastable by default.