Skip to content

Implementation of graphql-ws protocol #242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/modules/transport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ gql.transport
.. autoclass:: gql.transport.aiohttp.AIOHTTPTransport

.. autoclass:: gql.transport.websockets.WebsocketsTransport

.. autoclass:: gql.transport.phoenix_channel_websockets.PhoenixChannelWebsocketsTransport
2 changes: 2 additions & 0 deletions docs/transports/aiohttp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ AIOHTTPTransport

This transport uses the `aiohttp`_ library and allows you to send GraphQL queries using the HTTP protocol.

Reference: :py:class:`gql.transport.aiohttp.AIOHTTPTransport`

.. note::

GraphQL subscriptions are not supported on the HTTP transport.
Expand Down
2 changes: 2 additions & 0 deletions docs/transports/requests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ RequestsHTTPTransport
The RequestsHTTPTransport is a sync transport using the `requests`_ library
and allows you to send GraphQL queries using the HTTP protocol.

Reference: :py:class:`gql.transport.requests.RequestsHTTPTransport`

.. literalinclude:: ../code_examples/requests_sync.py

.. _requests: https://requests.readthedocs.io
63 changes: 57 additions & 6 deletions docs/transports/websockets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@
WebsocketsTransport
===================

The websockets transport implements the `Apollo websockets transport protocol`_.
The websockets transport supports both:

- the `Apollo websockets transport protocol`_.
- the `GraphQL-ws websockets transport protocol`_

It will detect the backend supported protocol from the response http headers returned.

This transport allows to do multiple queries, mutations and subscriptions on the same websocket connection.

Reference: :py:class:`gql.transport.websockets.WebsocketsTransport`

.. literalinclude:: ../code_examples/websockets_async.py

Websockets SSL
--------------

If you need to connect to an ssl encrypted endpoint:

* use _wss_ instead of _ws_ in the url of the transport
* use :code:`wss` instead of :code:`ws` in the url of the transport

.. code-block:: python

sample_transport = WebsocketsTransport(
transport = WebsocketsTransport(
url='wss://SERVER_URL:SERVER_PORT/graphql',
headers={'Authorization': 'token'}
)
Expand All @@ -34,7 +41,7 @@ If you have a self-signed ssl certificate, you need to provide an ssl_context wi
localhost_pem = pathlib.Path(__file__).with_name("YOUR_SERVER_PUBLIC_CERTIFICATE.pem")
ssl_context.load_verify_locations(localhost_pem)

sample_transport = WebsocketsTransport(
transport = WebsocketsTransport(
url='wss://SERVER_URL:SERVER_PORT/graphql',
ssl=ssl_context
)
Expand All @@ -54,7 +61,7 @@ There are two ways to send authentication tokens with websockets depending on th

.. code-block:: python

sample_transport = WebsocketsTransport(
transport = WebsocketsTransport(
url='wss://SERVER_URL:SERVER_PORT/graphql',
headers={'Authorization': 'token'}
)
Expand All @@ -63,9 +70,53 @@ There are two ways to send authentication tokens with websockets depending on th

.. code-block:: python

sample_transport = WebsocketsTransport(
transport = WebsocketsTransport(
url='wss://SERVER_URL:SERVER_PORT/graphql',
init_payload={'Authorization': 'token'}
)

Keep-Alives
-----------

Apollo protocol
^^^^^^^^^^^^^^^

With the Apollo protocol, the backend can optionally send unidirectional keep-alive ("ka") messages
(only from the server to the client).

It is possible to configure the transport to close if we don't receive a "ka" message
within a specified time using the :code:`keep_alive_timeout` parameter.

Here is an example with 60 seconds::

transport = WebsocketsTransport(
url='wss://SERVER_URL:SERVER_PORT/graphql',
keep_alive_timeout=60,
)

One disadvantage of the Apollo protocol is that because the keep-alives are only sent from the server
to the client, it can be difficult to detect the loss of a connection quickly from the server side.

GraphQL-ws protocol
^^^^^^^^^^^^^^^^^^^

With the GraphQL-ws protocol, it is possible to send bidirectional ping/pong messages.
Pings can be sent either from the client or the server and the other party should answer with a pong.

As with the Apollo protocol, it is possible to configure the transport to close if we don't
receive any message from the backend within the specified time using the :code:`keep_alive_timeout` parameter.

But there is also the possibility for the client to send pings at a regular interval and verify
that the backend sends a pong within a specified delay.
This can be done using the :code:`ping_interval` and :code:`pong_timeout` parameters.

Here is an example with a ping sent every 60 seconds, expecting a pong within 10 seconds::

transport = WebsocketsTransport(
url='wss://SERVER_URL:SERVER_PORT/graphql',
ping_interval=60,
pong_timeout=10,
)

.. _Apollo websockets transport protocol: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md
.. _GraphQL-ws websockets transport protocol: https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
Loading