diff --git a/docs/transports/websockets.rst b/docs/transports/websockets.rst index 689cc136..23e4735a 100644 --- a/docs/transports/websockets.rst +++ b/docs/transports/websockets.rst @@ -8,7 +8,14 @@ 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. +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=[WebsocketsTransport.GRAPHQLWS_SUBPROTOCOL]` + or :code:`subprotocols=[WebsocketsTransport.APOLLO_SUBPROTOCOL]` in the transport arguments. This transport allows to do multiple queries, mutations and subscriptions on the same websocket connection. @@ -118,5 +125,6 @@ Here is an example with a ping sent every 60 seconds, expecting a pong within 10 pong_timeout=10, ) +.. _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 diff --git a/gql/transport/websockets.py b/gql/transport/websockets.py index 04983ef8..1650624e 100644 --- a/gql/transport/websockets.py +++ b/gql/transport/websockets.py @@ -3,7 +3,7 @@ import logging from contextlib import suppress from ssl import SSLContext -from typing import Any, Dict, Optional, Tuple, Union, cast +from typing import Any, Dict, List, Optional, Tuple, Union, cast from graphql import DocumentNode, ExecutionResult, print_ast from websockets.datastructures import HeadersLike @@ -46,6 +46,7 @@ def __init__( pong_timeout: Optional[Union[int, float]] = None, answer_pings: bool = True, connect_args: Dict[str, Any] = {}, + subprotocols: Optional[List[Subprotocol]] = None, ) -> None: """Initialize the transport with the given parameters. @@ -71,6 +72,9 @@ def __init__( (for the graphql-ws protocol). By default: True :param connect_args: Other parameters forwarded to websockets.connect + :param subprotocols: list of subprotocols sent to the + backend in the 'subprotocols' http header. + By default: both apollo and graphql-ws subprotocols. """ super().__init__( @@ -105,10 +109,13 @@ def __init__( """pong_received is an asyncio Event which will fire each time a pong is received with the graphql-ws protocol""" - self.supported_subprotocols = [ - self.APOLLO_SUBPROTOCOL, - self.GRAPHQLWS_SUBPROTOCOL, - ] + if subprotocols is None: + self.supported_subprotocols = [ + self.APOLLO_SUBPROTOCOL, + self.GRAPHQLWS_SUBPROTOCOL, + ] + else: + self.supported_subprotocols = subprotocols async def _wait_ack(self) -> None: """Wait for the connection_ack message. Keep alive messages are ignored""" diff --git a/tests/conftest.py b/tests/conftest.py index d433c1ca..fbb881ec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -465,7 +465,9 @@ async def client_and_graphqlws_server(graphqlws_server): # Generate transport to connect to the server fixture path = "/graphql" url = f"ws://{graphqlws_server.hostname}:{graphqlws_server.port}{path}" - sample_transport = WebsocketsTransport(url=url) + sample_transport = WebsocketsTransport( + url=url, subprotocols=[WebsocketsTransport.GRAPHQLWS_SUBPROTOCOL], + ) async with Client(transport=sample_transport) as session: