In GraphQL you can use subscriptions to stream data from a server. To enable
this with Strawberry your server must support ASGI and websockets or use the
AIOHTTP integration.
This is how you define a subscription-capable resolver:
Like queries and mutations, subscriptions are defined in a class and passed to
the Schema function. Here we create a rudimentary counting function which counts
from 0 to the target sleeping between each loop iteration.
Note
The return type of count is AsyncGenerator where the first generic argument
is the actual type of the response, in most cases the second argument should be
left as None (more about Generator typing
here ).
We would send the following GraphQL document to our server to subscribe to this
data stream:
In this example, the data looks like this as it passes over the websocket:
This is a very short example of what is possible. Like with queries and
mutations the subscription can return any GraphQL type, not only scalars as
demonstrated here.
Without going into detail on why ,
custom headers cannot be set on websocket requests that originate in browsers.
Therefore, when making any GraphQL requests that rely on a websocket connection,
header-based authentication is impossible.
Other popular GraphQL solutions, like Apollo for example, implement
functionality to pass information from the client to the server at the point of
websocket connection initialisation. In this way, information that is relevant
to the websocket connection initialisation and to the lifetime of the connection
overall can be passed to the server before any data is streamed back by the
server. As such, it is not limited to only authentication credentials!
Strawberry's implementation follows that of Apollo's, which as documentation for
client
and
server
implementations, by reading the contents of the initial websocket connection
message into the info.context object.
With Apollo-client as an example of how to send this initial connection
information, one defines a ws-link as:
and then, upon the establishment of the Susbcription request and underlying
websocket connection, Strawberry injects this connectionParams object as
follows:
Strawberry expects the connection_params object to be any type, so the client
is free to send any valid JSON object as the initial message of the websocket
connection, which is abstracted as connectionParams in Apollo-client, and it
will be successfully injected into the info.context object. It is then up to
you to handle it correctly!
Typically a GraphQL subscription is streaming something more interesting back.
With that in mind your subscription function can return one of:
AsyncIterator , or
AsyncGenerator
Both of these types are documented in PEP-525 . Anything yielded from
these types of resolvers will be shipped across the websocket. Care needs to be
taken to ensure the returned values conform to the GraphQL schema.
The benefit of an AsyncGenerator, over an iterator, is that the complex business
logic can be broken out into a separate module within your codebase. Allowing
you to keep the resolver logic succinct.
The following example is similar to the one above, except it returns an
AsyncGenerator to the ASGI server which is responsible for streaming
subscription results until the Generator exits.
The graphql-transport-ws protocols repository is called graphql-ws . However,
graphql-ws is also the name of the legacy protocol. This documentation always
refers to the protocol names.
Note that the graphql-ws sub-protocol is mainly supported for backwards
compatibility. Read the
graphql-ws-transport protocols announcement
to learn more about why the newer protocol is preferred.
Strawberry allows you to choose which protocols you want to accept. All
integrations supporting subscriptions can be configured with a list of
subscription_protocols to accept. By default, all protocols are accepted.
In addition to streaming operations (i.e. subscriptions), the
graphql-transport-ws protocol supports so called single result operations
(i.e. queries and mutations).
This enables clients to use one protocol and one connection for queries,
mutations and subscriptions. Take a look at the
protocols repository to learn how to
correctly set up the graphql client of your choice.
Strawberry supports single result operations out of the box when the
graphql-transport-ws protocol is enabled. Single result operations are normal
queries and mutations, so there is no need to adjust any resolvers.