400 Bad Request for websockets endpoint
leszekhanusz opened this issue · 5 comments
Hi,
I am the maintainer of the graphql-python/gql client and we make a great use of your countries website for our examples in our documentation. A big thanks for your website which provides a stable backend when we need to do some simple tests sometimes.
It has been brought to my attention recently that all the examples involving the websockets protocol are not working anymore (the http protocol continues to work fine).
Now we always receive a 400 Bad Request response when trying to connect to the websockets endpoint.
If I try to run the following code with gql version 3.1.0:
import asyncio
import logging
from gql import Client, gql
from gql.transport.websockets import WebsocketsTransport
logging.basicConfig(level=logging.DEBUG)
async def main():
transport = WebsocketsTransport(
url="wss://countries.trevorblades.com/graphql",
subprotocols=[WebsocketsTransport.APOLLO_SUBPROTOCOL],
)
async with Client(
transport=transport, fetch_schema_from_transport=True,
) as session:
# Execute single query
query = gql(
"""
query getContinents {
continents {
code
name
}
}
"""
)
result = await session.execute(query)
print(result)
asyncio.run(main())
Then I receive the following result:
DEBUG:asyncio:Using selector: EpollSelector
DEBUG:gql.transport.websockets:connect: starting
DEBUG:websockets.client:= connection is CONNECTING
DEBUG:websockets.client:> GET /graphql HTTP/1.1
DEBUG:websockets.client:> Host: countries.trevorblades.com
DEBUG:websockets.client:> Upgrade: websocket
DEBUG:websockets.client:> Connection: Upgrade
DEBUG:websockets.client:> Sec-WebSocket-Key: ZK9W8vXCkiwnBMzyG0UnSA==
DEBUG:websockets.client:> Sec-WebSocket-Version: 13
DEBUG:websockets.client:> Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
DEBUG:websockets.client:> Sec-WebSocket-Protocol: graphql-ws
DEBUG:websockets.client:> User-Agent: Python/3.8 websockets/10.2
DEBUG:websockets.client:< HTTP/1.1 400 Bad Request
DEBUG:websockets.client:< access-control-allow-origin: *
DEBUG:websockets.client:< content-type: text/html; charset=utf-8
DEBUG:websockets.client:< content-length: 18
DEBUG:websockets.client:< etag: W/"12-7JEJwpG8g89ii7CR/6hhfN27Q+k"
DEBUG:websockets.client:< date: Mon, 11 Apr 2022 19:33:55 GMT
DEBUG:websockets.client:< connection: keep-alive
DEBUG:websockets.client:< keep-alive: timeout=5
DEBUG:websockets.client:< server: Fly/523fc696 (2022-04-06)
DEBUG:websockets.client:< via: 1.1 fly.io
DEBUG:websockets.client:< fly-request-id: 01G0D1X9FAAFXFHY58RRYJ6WGX-fra
DEBUG:websockets.client:! failing connection with code 1006
DEBUG:websockets.client:x closing TCP connection
DEBUG:websockets.client:= connection is CLOSED
Traceback (most recent call last):
File "docs/code_examples/websockets_async.py", line 36, in <module>
asyncio.run(main())
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "docs/code_examples/websockets_async.py", line 17, in main
async with Client(
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/site-packages/gql/client.py", line 580, in __aenter__
await self.transport.connect()
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/site-packages/gql/transport/websockets_base.py", line 491, in connect
self.websocket = await asyncio.wait_for(
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/asyncio/tasks.py", line 483, in wait_for
return fut.result()
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/asyncio/tasks.py", line 684, in _wrap_awaitable
return (yield from awaitable.__await__())
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/site-packages/websockets/legacy/client.py", line 650, in __await_impl_timeout__
return await asyncio.wait_for(self.__await_impl__(), self.open_timeout)
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/asyncio/tasks.py", line 483, in wait_for
return fut.result()
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/site-packages/websockets/legacy/client.py", line 658, in __await_impl__
await protocol.handshake(
File "/home/leszek/miniconda3/envs/gql-dev/lib/python3.8/site-packages/websockets/legacy/client.py", line 328, in handshake
raise InvalidStatusCode(status_code, response_headers)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 400
It has been a while that I tested this so this could have been the case for a long time already.
This API doesn't currently support GraphQL subscriptions, and there's no plan for any. What do you need to connect via websockets for?
I know you don't have any subscriptions. It was used to test the apollo websockets transport for the client. Queries and mutations were working on the websockets endpoint, check this test file which used to work perfectly fine.
But if you don't plan to bring back the websockets support back, no worries, I'll try to find another always-on backend for our websockets examples.
I just tested a local version of countries and the websockets endpoint is working, so it should be a configuration issue in the hosting environment.
$ echo 'query { continent(code:"AF") { name } }' | gql-cli ws://localhost:4000/graphql
{"continent": {"name": "Africa"}}
Hey @leszekhanusz, oh my goodness I'm replying so late, I'm sorry. I just wanted to follow up on this and let you know that due to some recent changes in the way this API is hosted (I'm using Cloudflare Workers now), it won't support WS connections.
Hope you found another API to use an example! Out of curiosity, what API did you go with?