Skip to content

Commit

Permalink
New transport AIOHTTPWebsocketsTransport (graphql-python#478)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlowery-scwx authored Jul 25, 2024
1 parent ede1350 commit 00b61d5
Show file tree
Hide file tree
Showing 15 changed files with 4,619 additions and 21 deletions.
50 changes: 50 additions & 0 deletions docs/code_examples/aiohttp_websockets_async.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import asyncio
import logging

from gql import Client, gql
from gql.transport.aiohttp_websockets import AIOHTTPWebsocketsTransport

logging.basicConfig(level=logging.INFO)


async def main():

transport = AIOHTTPWebsocketsTransport(
url="wss://countries.trevorblades.com/graphql"
)

# Using `async with` on the client will start a connection on the transport
# and provide a `session` variable to execute queries on this connection
async with Client(
transport=transport,
) as session:

# Execute single query
query = gql(
"""
query getContinents {
continents {
code
name
}
}
"""
)
result = await session.execute(query)
print(result)

# Request subscription
subscription = gql(
"""
subscription {
somethingChanged {
id
}
}
"""
)
async for result in session.subscribe(subscription):
print(result)


asyncio.run(main())
40 changes: 21 additions & 19 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,27 @@ which needs the :code:`aiohttp` dependency, then you can install GQL with::

The corresponding between extra dependencies required and the GQL classes is:

+---------------------+----------------------------------------------------------------+
| Extra dependencies | Classes |
+=====================+================================================================+
| aiohttp | :ref:`AIOHTTPTransport <aiohttp_transport>` |
+---------------------+----------------------------------------------------------------+
| websockets | :ref:`WebsocketsTransport <websockets_transport>` |
| | |
| | :ref:`PhoenixChannelWebsocketsTransport <phoenix_transport>` |
| | |
| | :ref:`AppSyncWebsocketsTransport <appsync_transport>` |
+---------------------+----------------------------------------------------------------+
| requests | :ref:`RequestsHTTPTransport <requests_transport>` |
+---------------------+----------------------------------------------------------------+
| httpx | :ref:`HTTPTXTransport <httpx_transport>` |
| | |
| | :ref:`HTTPXAsyncTransport <httpx_async_transport>` |
+---------------------+----------------------------------------------------------------+
| botocore | :ref:`AppSyncIAMAuthentication <appsync_iam_auth>` |
+---------------------+----------------------------------------------------------------+
+---------------------+------------------------------------------------------------------+
| Extra dependencies | Classes |
+=====================+==================================================================+
| aiohttp | :ref:`AIOHTTPTransport <aiohttp_transport>` |
| | |
| | :ref:`AIOHTTPWebsocketsTransport <aiohttp_websockets_transport>` |
+---------------------+------------------------------------------------------------------+
| websockets | :ref:`WebsocketsTransport <websockets_transport>` |
| | |
| | :ref:`PhoenixChannelWebsocketsTransport <phoenix_transport>` |
| | |
| | :ref:`AppSyncWebsocketsTransport <appsync_transport>` |
+---------------------+------------------------------------------------------------------+
| requests | :ref:`RequestsHTTPTransport <requests_transport>` |
+---------------------+------------------------------------------------------------------+
| httpx | :ref:`HTTPTXTransport <httpx_transport>` |
| | |
| | :ref:`HTTPXAsyncTransport <httpx_async_transport>` |
+---------------------+------------------------------------------------------------------+
| botocore | :ref:`AppSyncIAMAuthentication <appsync_iam_auth>` |
+---------------------+------------------------------------------------------------------+

.. note::

Expand Down
1 change: 1 addition & 0 deletions docs/modules/gql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Sub-Packages
client
transport
transport_aiohttp
transport_aiohttp_websockets
transport_appsync_auth
transport_appsync_websockets
transport_exceptions
Expand Down
7 changes: 7 additions & 0 deletions docs/modules/transport_aiohttp_websockets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
gql.transport.aiohttp_websockets
================================

.. currentmodule:: gql.transport.aiohttp_websockets

.. automodule:: gql.transport.aiohttp_websockets
:member-order: bysource
4 changes: 3 additions & 1 deletion docs/transports/aiohttp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ Reference: :class:`gql.transport.aiohttp.AIOHTTPTransport`
.. note::

GraphQL subscriptions are not supported on the HTTP transport.
For subscriptions you should use the :ref:`websockets transport <websockets_transport>`.
For subscriptions you should use a websockets transport:
:ref:`WebsocketsTransport <websockets_transport>` or
:ref:`AIOHTTPWebsocketsTransport <aiohttp_websockets_transport>`.

.. literalinclude:: ../code_examples/aiohttp_async.py

Expand Down
31 changes: 31 additions & 0 deletions docs/transports/aiohttp_websockets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.. _aiohttp_websockets_transport:

AIOHTTPWebsocketsTransport
==========================

The AIOHTTPWebsocketsTransport is an alternative to the :ref:`websockets_transport`,
using the `aiohttp` dependency instead of the `websockets` dependency.

It also supports both:

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

It will propose both subprotocols to the backend and detect the supported protocol
from the response http headers returned by the backend.

.. note::
For some backends (graphql-ws before `version 5.6.1`_ without backwards compatibility), it may be necessary to specify
only one subprotocol to the backend. It can be done by using
:code:`subprotocols=[AIOHTTPWebsocketsTransport.GRAPHQLWS_SUBPROTOCOL]`
or :code:`subprotocols=[AIOHTTPWebsocketsTransport.APOLLO_SUBPROTOCOL]` in the transport arguments.

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

Reference: :class:`gql.transport.aiohttp_websockets.AIOHTTPWebsocketsTransport`

.. literalinclude:: ../code_examples/aiohttp_websockets_async.py

.. _version 5.6.1: https://github.com/enisdenjo/graphql-ws/releases/tag/v5.6.1
.. _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
1 change: 1 addition & 0 deletions docs/transports/async_transports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ Async transports are transports which are using an underlying async library. The
aiohttp
httpx_async
websockets
aiohttp_websockets
phoenix
appsync
13 changes: 12 additions & 1 deletion gql/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def get_parser(with_examples: bool = False) -> ArgumentParser:
"aiohttp",
"phoenix",
"websockets",
"aiohttp_websockets",
"appsync_http",
"appsync_websockets",
],
Expand Down Expand Up @@ -286,7 +287,12 @@ def autodetect_transport(url: URL) -> str:
"""Detects which transport should be used depending on url."""

if url.scheme in ["ws", "wss"]:
transport_name = "websockets"
try:
import websockets # noqa: F401

transport_name = "websockets"
except ImportError: # pragma: no cover
transport_name = "aiohttp_websockets"

else:
assert url.scheme in ["http", "https"]
Expand Down Expand Up @@ -338,6 +344,11 @@ def get_transport(args: Namespace) -> Optional[AsyncTransport]:

return WebsocketsTransport(url=args.server, **transport_args)

elif transport_name == "aiohttp_websockets":
from gql.transport.aiohttp_websockets import AIOHTTPWebsocketsTransport

return AIOHTTPWebsocketsTransport(url=args.server, **transport_args)

else:

from gql.transport.appsync_auth import AppSyncAuthentication
Expand Down
Loading

0 comments on commit 00b61d5

Please sign in to comment.