Skip to content

Commit 0819418

Browse files
authored
Add HTTPX transport (#370)
1 parent f0150a8 commit 0819418

18 files changed

+2836
-6
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
strategy:
4141
fail-fast: false
4242
matrix:
43-
dependency: ["aiohttp", "requests", "websockets"]
43+
dependency: ["aiohttp", "requests", "httpx", "websockets"]
4444

4545
steps:
4646
- uses: actions/checkout@v3

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
SRC_PYTHON := gql tests docs/code_examples
44

55
dev-setup:
6-
python pip install -e ".[test]"
6+
python -m pip install -e ".[test]"
77

88
tests:
99
pytest tests --cov=gql --cov-report=term-missing -vv
@@ -17,6 +17,9 @@ tests_aiohttp:
1717
tests_requests:
1818
pytest tests --requests-only
1919

20+
tests_httpx:
21+
pytest tests --httpx-only
22+
2023
tests_websockets:
2124
pytest tests --websockets-only
2225

docs/code_examples/httpx_async.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import asyncio
2+
3+
from gql import Client, gql
4+
from gql.transport.httpx import HTTPXAsyncTransport
5+
6+
7+
async def main():
8+
9+
transport = HTTPXAsyncTransport(url="https://countries.trevorblades.com/graphql")
10+
11+
# Using `async with` on the client will start a connection on the transport
12+
# and provide a `session` variable to execute queries on this connection
13+
async with Client(
14+
transport=transport,
15+
fetch_schema_from_transport=True,
16+
) as session:
17+
18+
# Execute single query
19+
query = gql(
20+
"""
21+
query getContinents {
22+
continents {
23+
code
24+
name
25+
}
26+
}
27+
"""
28+
)
29+
30+
result = await session.execute(query)
31+
print(result)
32+
33+
34+
asyncio.run(main())

docs/code_examples/httpx_sync.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from gql import Client, gql
2+
from gql.transport.httpx import HTTPXTransport
3+
4+
transport = HTTPXTransport(url="https://countries.trevorblades.com/")
5+
6+
client = Client(transport=transport, fetch_schema_from_transport=True)
7+
8+
query = gql(
9+
"""
10+
query getContinents {
11+
continents {
12+
code
13+
name
14+
}
15+
}
16+
"""
17+
)
18+
19+
result = client.execute(query)
20+
print(result)

docs/intro.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ The corresponding between extra dependencies required and the GQL classes is:
4545
+---------------------+----------------------------------------------------------------+
4646
| requests | :ref:`RequestsHTTPTransport <requests_transport>` |
4747
+---------------------+----------------------------------------------------------------+
48+
| httpx | :ref:`HTTPTXTransport <httpx_transport>` |
49+
| | |
50+
| | :ref:`HTTPXAsyncTransport <httpx_async_transport>` |
51+
+---------------------+----------------------------------------------------------------+
4852
| botocore | :ref:`AppSyncIAMAuthentication <appsync_iam_auth>` |
4953
+---------------------+----------------------------------------------------------------+
5054

docs/modules/gql.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Sub-Packages
2626
transport_exceptions
2727
transport_phoenix_channel_websockets
2828
transport_requests
29+
transport_httpx
2930
transport_websockets
3031
transport_websockets_base
3132
dsl

docs/modules/transport_httpx.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
gql.transport.httpx
2+
===================
3+
4+
.. currentmodule:: gql.transport.httpx
5+
6+
.. automodule:: gql.transport.httpx
7+
:member-order: bysource

docs/transports/async_transports.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Async transports are transports which are using an underlying async library. The
1010
:maxdepth: 1
1111

1212
aiohttp
13+
httpx_async
1314
websockets
1415
phoenix
1516
appsync

docs/transports/httpx.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.. _httpx_transport:
2+
3+
HTTPXTransport
4+
==============
5+
6+
The HTTPXTransport is a sync transport using the `httpx`_ library
7+
and allows you to send GraphQL queries using the HTTP protocol.
8+
9+
Reference: :class:`gql.transport.httpx.HTTPXTransport`
10+
11+
.. literalinclude:: ../code_examples/httpx_sync.py
12+
13+
.. _httpx: https://www.python-httpx.org

docs/transports/httpx_async.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
.. _httpx_async_transport:
2+
3+
HTTPXAsyncTransport
4+
===================
5+
6+
This transport uses the `httpx`_ library and allows you to send GraphQL queries using the HTTP protocol.
7+
8+
Reference: :class:`gql.transport.httpx.HTTPXAsyncTransport`
9+
10+
.. note::
11+
12+
GraphQL subscriptions are not supported on the HTTP transport.
13+
For subscriptions you should use the :ref:`websockets transport <websockets_transport>`.
14+
15+
.. literalinclude:: ../code_examples/httpx_async.py
16+
17+
Authentication
18+
--------------
19+
20+
There are multiple ways to authenticate depending on the server configuration.
21+
22+
1. Using HTTP Headers
23+
24+
.. code-block:: python
25+
26+
transport = HTTPXAsyncTransport(
27+
url='https://SERVER_URL:SERVER_PORT/graphql',
28+
headers={'Authorization': 'token'}
29+
)
30+
31+
2. Using HTTP Cookies
32+
33+
You can manually set the cookies which will be sent with each connection:
34+
35+
.. code-block:: python
36+
37+
transport = HTTPXAsyncTransport(url=url, cookies={"cookie1": "val1"})
38+
39+
.. _httpx: https://www.python-httpx.org

docs/transports/sync_transports.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ They cannot be used asynchronously.
1010
:maxdepth: 1
1111

1212
requests
13+
httpx

docs/usage/file_upload.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
File uploads
22
============
33

4-
GQL supports file uploads with the :ref:`aiohttp transport <aiohttp_transport>`
5-
and the :ref:`requests transport <requests_transport>`
4+
GQL supports file uploads with the :ref:`aiohttp transport <aiohttp_transport>`, the
5+
:ref:`requests transport <requests_transport>`, the :ref:`httpx transport <httpx_transport>`,
6+
and the :ref:`httpx async transport <httpx_async_transport>`,
67
using the `GraphQL multipart request spec`_.
78

89
.. _GraphQL multipart request spec: https://github.com/jaydenseric/graphql-multipart-request-spec
@@ -20,6 +21,8 @@ In order to upload a single file, you need to:
2021
2122
transport = AIOHTTPTransport(url='YOUR_URL')
2223
# Or transport = RequestsHTTPTransport(url='YOUR_URL')
24+
# Or transport = HTTPXTransport(url='YOUR_URL')
25+
# Or transport = HTTPXAsyncTransport(url='YOUR_URL')
2326
2427
client = Client(transport=transport)
2528
@@ -48,6 +51,8 @@ It is also possible to upload multiple files using a list.
4851
4952
transport = AIOHTTPTransport(url='YOUR_URL')
5053
# Or transport = RequestsHTTPTransport(url='YOUR_URL')
54+
# Or transport = HTTPXTransport(url='YOUR_URL')
55+
# Or transport = HTTPXAsyncTransport(url='YOUR_URL')
5156
5257
client = Client(transport=transport)
5358

0 commit comments

Comments
 (0)