Skip to content
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

New transport AIOHTTPWebsocketsTransport #478

Merged
merged 64 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
c0b429b
expose all ws_connect arguments
May 7, 2024
c875fd8
wip: mirrroring websockets_base interface in aiohttp_websockets
May 8, 2024
1117d3a
black format
May 8, 2024
f3a927c
wip: add more methods in pursuit of parity
May 8, 2024
7378a53
WIP: aiohttp websockets parity
May 9, 2024
1c8eda5
answer improvements
May 30, 2024
34fc580
linting fixes
mpegman-scwx May 30, 2024
f5d208c
wip: initial tests
May 30, 2024
aa50d20
Merge branch 'aiohttp_websockets' of https://github.com/tlowery-scwx/…
May 30, 2024
b44fd45
wip: initial tests for aiohttp websockets
Jun 4, 2024
f438531
fix some minor import errors
Jun 4, 2024
8f44fc6
fix incorrect fixture
Jun 4, 2024
ef84507
update query tests to match AIOHTTPWebsocketsTransport behavior
Jun 4, 2024
9870336
wip: updating tests to follow AIOHTTPWebsockets protocol
Jun 4, 2024
6584f54
remove unnecessary websockets imports
Jun 5, 2024
fc73ba1
fix some tests
mpegman-scwx Jun 10, 2024
e4dbce8
more test fixes
mpegman-scwx Jun 10, 2024
e47ce3b
add ci test job for aiohttp_websockets
Jun 10, 2024
cd71e91
add aiohttp websocket tests for graphql websockets
Jun 14, 2024
bbddf25
update tests to AIOHTTPWebsocketsTransport
Jun 14, 2024
252969e
add missing import
Jun 14, 2024
1b729c2
set exceptions tests to expect the correct errors
Jun 14, 2024
3d99402
test updates
mpegman-scwx Jun 17, 2024
10e2172
get response headers from aiohttp client response
Jun 18, 2024
3bd3126
transport feature updates
mpegman-scwx Jun 18, 2024
2ad42ab
increase test coverage over edge cases
Jul 8, 2024
e5770c7
ran formatter
Jul 8, 2024
f28c4fe
remove unused import
Jul 8, 2024
2b25cb8
remove unnecessary timeout
Jul 12, 2024
b158614
remove hanging test
Jul 12, 2024
bae308f
re-add hanging test with skip marker and explanation
Jul 12, 2024
5acb518
Modify _receive method to be more like the websockets one
leszekhanusz Jul 13, 2024
4ec2516
Running make check
leszekhanusz Jul 13, 2024
6336eaa
Revert all code changes outside of the scope of this PR
leszekhanusz Jul 13, 2024
b6163c0
Merge branch 'master' into aiohttp_websockets
leszekhanusz Jul 13, 2024
0736dc0
Fix aiohttp_websocket ssl attribute typing
leszekhanusz Jul 13, 2024
172d65d
Revert all code changes outside of the scope of this PR - 2
leszekhanusz Jul 13, 2024
5653d56
Remove invalid aiohttp_websockets dependency from github workflow
leszekhanusz Jul 13, 2024
f1fb25d
Add the aiohttp AND websockets mark to the aiohttp_websocket tests
leszekhanusz Jul 13, 2024
3a762ae
Copy ListenerQueue in aiohttp_websockets.py
leszekhanusz Jul 13, 2024
fcd59dc
Fix importing Literal for Python 3.7
leszekhanusz Jul 13, 2024
64d6ffd
assertion instead of TransportClosed exception if websocket is None
leszekhanusz Jul 13, 2024
87b5573
small cleaning
leszekhanusz Jul 13, 2024
270d8ec
Close aiohttp session properly, inspired from aiohttp transport
leszekhanusz Jul 13, 2024
ddcc77f
Add test for ssl_close_timeout parameter
leszekhanusz Jul 14, 2024
05e61b8
Add test for client_session_args and connector_owner_false
leszekhanusz Jul 14, 2024
5e0beb2
Merge branch 'master' into aiohttp_websockets
leszekhanusz Jul 14, 2024
2af7d40
Fix handling of connection_error during init
leszekhanusz Jul 14, 2024
b529ea2
Fix RuntimeError event loop is closed exception shown during tests
leszekhanusz Jul 15, 2024
170846f
Revert "assertion instead of TransportClosed exception if websocket i…
leszekhanusz Jul 15, 2024
9a10f0d
Using _wait_closed.is_set() to determine if we need to wait or close …
leszekhanusz Jul 15, 2024
4aaf86a
Ignore low-level ping pong messages
leszekhanusz Jul 15, 2024
277fd5d
Rename timeout to websocket_close_timeout, reorder init params
leszekhanusz Jul 15, 2024
a8b276d
Modify transport init parameters
leszekhanusz Jul 15, 2024
6906ad2
Use connect_timeout param
leszekhanusz Jul 15, 2024
4ea698f
Add reference documentation + remove deprecated ssl_context param
leszekhanusz Jul 15, 2024
97ac985
Allow to use the new transport from the cli
leszekhanusz Jul 16, 2024
cfee44c
Adding a new ws test server using aiohttp to do some tests without we…
leszekhanusz Jul 16, 2024
d43224f
Try to fix ConnectionResetError exception
leszekhanusz Jul 16, 2024
04cd47c
Fix anext not existing on Python 3.8
leszekhanusz Jul 16, 2024
933348d
Adding the transport to the docs
leszekhanusz Jul 17, 2024
22e8a3a
Fix tests still using WebsocketsTransport instead of new transport
leszekhanusz Jul 17, 2024
db9f5db
Fix countdown server not closing properly in some cases
leszekhanusz Jul 17, 2024
9eaafa4
More resilient _close_coro cleanup
leszekhanusz Jul 17, 2024
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
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
Loading