diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f89a2238..45f01d82 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,7 +9,7 @@ assignees: '' **Common problems** - If you receive a TransportQueryError, it means the error is coming from the backend (See [Error Handling](https://gql.readthedocs.io/en/latest/advanced/error_handling.html)) and has probably nothing to do with gql -- If you use IPython (Jupyter, Spyder), then [you need to use the async version](https://gql.readthedocs.io/en/latest/async/async_usage.html#ipython) +- If you use IPython (Jupyter, Spyder), then [you need to use the async version](https://gql.readthedocs.io/en/latest/usage/async_usage.html#ipython) - Before sending a bug report, please consider [activating debug logs](https://gql.readthedocs.io/en/latest/advanced/logging.html) to see the messages exchanged between the client and the backend **Describe the bug** diff --git a/README.md b/README.md index e79a63d2..86f380f3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # GQL -This is a GraphQL client for Python 3.8+. -Plays nicely with `graphene`, `graphql-core`, `graphql-js` and any other GraphQL implementation compatible with the spec. +This is a GraphQL client for Python. +Plays nicely with `graphene`, `graphql-core`, `graphql-js` and any other GraphQL implementation +compatible with the [GraphQL specification](https://spec.graphql.org). GQL architecture is inspired by `React-Relay` and `Apollo-Client`. @@ -37,7 +38,7 @@ The complete documentation for GQL can be found at * AWS AppSync realtime protocol (experimental) * Possibility to [validate the queries locally](https://gql.readthedocs.io/en/latest/usage/validation.html) using a GraphQL schema provided locally or fetched from the backend using an instrospection query * Supports GraphQL queries, mutations and [subscriptions](https://gql.readthedocs.io/en/latest/usage/subscriptions.html) -* Supports [sync or async usage](https://gql.readthedocs.io/en/latest/async/index.html), [allowing concurrent requests](https://gql.readthedocs.io/en/latest/advanced/async_advanced_usage.html#async-advanced-usage) +* Supports [sync](https://gql.readthedocs.io/en/latest/usage/sync_usage.html) or [async](https://gql.readthedocs.io/en/latest/usage/async_usage.html) usage, [allowing concurrent requests](https://gql.readthedocs.io/en/latest/advanced/async_advanced_usage.html#async-advanced-usage) * Supports [File uploads](https://gql.readthedocs.io/en/latest/usage/file_upload.html) * Supports [Custom scalars / Enums](https://gql.readthedocs.io/en/latest/usage/custom_scalars_and_enums.html) * Supports [Batching requests](https://gql.readthedocs.io/en/latest/advanced/batching_requests.html) @@ -57,17 +58,17 @@ pip install "gql[all]" ## Usage -### Basic usage +### Sync usage ```python -from gql import gql, Client +from gql import Client, gql from gql.transport.aiohttp import AIOHTTPTransport # Select your transport with a defined url endpoint transport = AIOHTTPTransport(url="https://countries.trevorblades.com/") # Create a GraphQL client using the defined transport -client = Client(transport=transport, fetch_schema_from_transport=True) +client = Client(transport=transport) # Provide a GraphQL query query = gql( @@ -95,7 +96,48 @@ $ python basic_example.py > **WARNING**: Please note that this basic example won't work if you have an asyncio event loop running. In some > python environments (as with Jupyter which uses IPython) an asyncio event loop is created for you. In that case you -> should use instead the [async usage example](https://gql.readthedocs.io/en/latest/async/async_usage.html#async-usage). +> should use instead the [async usage example](https://gql.readthedocs.io/en/latest/usage/async_usage.html#async-usage). + +### Async usage + +```python +import asyncio + +from gql import Client, gql +from gql.transport.aiohttp import AIOHTTPTransport + + +async def main(): + + # Select your transport with a defined url endpoint + transport = AIOHTTPTransport(url="https://countries.trevorblades.com/graphql") + + # Create a GraphQL client using the defined transport + client = Client(transport=transport) + + # Provide a GraphQL query + query = gql( + """ + query getContinents { + continents { + code + name + } + } + """ + ) + + # 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 as session: + + # Execute the query + result = await session.execute(query) + print(result) + + +asyncio.run(main()) +``` ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/docs/async/async_intro.rst b/docs/async/async_intro.rst deleted file mode 100644 index 6d4fea37..00000000 --- a/docs/async/async_intro.rst +++ /dev/null @@ -1,18 +0,0 @@ -On previous versions of GQL, the code was `sync` only , it means that when you ran -`execute` on the Client, you could do nothing else in the current Thread and had to wait for -an answer or a timeout from the backend to continue. The only http library was `requests`, allowing only sync usage. - -From the version 3 of GQL, we support `sync` and `async` :ref:`transports ` using `asyncio`_. - -With the :ref:`async transports `, there is now the possibility to execute GraphQL requests -asynchronously, :ref:`allowing to execute multiple requests in parallel if needed `. - -If you don't care or need async functionality, it is still possible, with :ref:`async transports `, -to run the `execute` or `subscribe` methods directly from the Client -(as described in the :ref:`Basic Usage ` example) and GQL will execute the request -in a synchronous manner by running an asyncio event loop itself. - -This won't work though if you already have an asyncio event loop running. In that case you should use -:ref:`Async Usage ` - -.. _asyncio: https://docs.python.org/3/library/asyncio.html diff --git a/docs/async/index.rst b/docs/async/index.rst deleted file mode 100644 index 3f3d2a8a..00000000 --- a/docs/async/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Async vs Sync -============= - -.. include:: async_intro.rst - -.. toctree:: - :hidden: - :maxdepth: 1 - - async_usage diff --git a/docs/code_examples/aiohttp_async.py b/docs/code_examples/aiohttp_async.py index 0c1d10dd..bc615fa8 100644 --- a/docs/code_examples/aiohttp_async.py +++ b/docs/code_examples/aiohttp_async.py @@ -6,27 +6,29 @@ async def main(): + # Select your transport with a defined url endpoint transport = AIOHTTPTransport(url="https://countries.trevorblades.com/graphql") + # Create a GraphQL client using the defined transport + client = Client(transport=transport) + + # Provide a GraphQL query + query = gql( + """ + query getContinents { + continents { + code + name + } + } + """ + ) + # 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, - fetch_schema_from_transport=True, - ) as session: - - # Execute single query - query = gql( - """ - query getContinents { - continents { - code - name - } - } - """ - ) + async with client as session: + # Execute the query result = await session.execute(query) print(result) diff --git a/docs/code_examples/aiohttp_sync.py b/docs/code_examples/aiohttp_sync.py index 8b1cf899..18dab8ae 100644 --- a/docs/code_examples/aiohttp_sync.py +++ b/docs/code_examples/aiohttp_sync.py @@ -5,7 +5,7 @@ transport = AIOHTTPTransport(url="https://countries.trevorblades.com/") # Create a GraphQL client using the defined transport -client = Client(transport=transport, fetch_schema_from_transport=True) +client = Client(transport=transport) # Provide a GraphQL query query = gql( diff --git a/docs/conf.py b/docs/conf.py index 8289ef4b..024dd9e6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,8 +17,8 @@ # -- Project information ----------------------------------------------------- -project = 'gql 3' -copyright = '2020, graphql-python.org' +project = 'gql' +copyright = '2025, graphql-python.org' author = 'graphql-python.org' # The full version, including alpha/beta/rc tags diff --git a/docs/index.rst b/docs/index.rst index ecb2f0e1..d0ab36f2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ -Welcome to GQL 3 documentation! -=============================== +GQL documentation +================= Contents -------- @@ -9,7 +9,6 @@ Contents intro usage/index - async/index transports/index advanced/index gql-cli/intro diff --git a/docs/intro.rst b/docs/intro.rst index 3151755d..f47166f6 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -1,7 +1,7 @@ Introduction ============ -`GQL 3`_ is a `GraphQL`_ Client for Python 3.8+ which plays nicely with other +`GQL`_ is a `GraphQL`_ Client for Python which plays nicely with other graphql implementations compatible with the spec. Under the hood, it uses `GraphQL-core`_ which is a Python port of `GraphQL.js`_, @@ -10,7 +10,7 @@ the JavaScript reference implementation for GraphQL. Installation ------------ -You can install GQL 3 and all the extra dependencies using pip_:: +You can install GQL and all the extra dependencies using pip_:: pip install "gql[all]" @@ -93,7 +93,7 @@ Please check the `Contributing`_ file to learn how to make a good pull request. .. _GraphQL: https://graphql.org/ .. _GraphQL-core: https://github.com/graphql-python/graphql-core .. _GraphQL.js: https://github.com/graphql/graphql-js -.. _GQL 3: https://github.com/graphql-python/gql +.. _GQL: https://github.com/graphql-python/gql .. _pip: https://pip.pypa.io/ .. _GitHub repository for gql: https://github.com/graphql-python/gql .. _Contributing: https://github.com/graphql-python/gql/blob/master/CONTRIBUTING.md diff --git a/docs/async/async_usage.rst b/docs/usage/async_usage.rst similarity index 52% rename from docs/async/async_usage.rst rename to docs/usage/async_usage.rst index e0e9ee02..a83c4767 100644 --- a/docs/async/async_usage.rst +++ b/docs/usage/async_usage.rst @@ -1,8 +1,28 @@ .. _async_usage: -Async Usage +Async usage =========== +On previous versions of GQL, the code was `sync` only , it means that when you ran +`execute` on the Client, you could do nothing else in the current Thread and had to wait for +an answer or a timeout from the backend to continue. The only http library was `requests`, allowing only sync usage. + +From the version 3 of GQL, we support `sync` and `async` :ref:`transports ` using `asyncio`_. + +With the :ref:`async transports `, there is now the possibility to execute GraphQL requests +asynchronously, :ref:`allowing to execute multiple requests in parallel if needed `. + +If you don't care or need async functionality, it is still possible, with :ref:`async transports `, +to run the `execute` or `subscribe` methods directly from the Client +(as described in the :ref:`Sync Usage ` example) and GQL will execute the request +in a synchronous manner by running an asyncio event loop itself. + +This won't work though if you already have an asyncio event loop running. In that case you should use the async +methods. + +Example +------- + If you use an :ref:`async transport `, you can use GQL asynchronously using `asyncio`_. * put your code in an asyncio coroutine (method starting with :code:`async def`) @@ -10,8 +30,6 @@ If you use an :ref:`async transport `, you can use GQL asynchr * use the :code:`await` keyword to execute requests: :code:`await session.execute(...)` * then run your coroutine in an asyncio event loop by running :code:`asyncio.run` -Example: - .. literalinclude:: ../code_examples/aiohttp_async.py IPython diff --git a/docs/usage/index.rst b/docs/usage/index.rst index f73ac75a..5fb3480f 100644 --- a/docs/usage/index.rst +++ b/docs/usage/index.rst @@ -4,7 +4,8 @@ Usage .. toctree:: :maxdepth: 2 - basic_usage + sync_usage + async_usage validation subscriptions variables diff --git a/docs/usage/subscriptions.rst b/docs/usage/subscriptions.rst index 9448328d..549054b9 100644 --- a/docs/usage/subscriptions.rst +++ b/docs/usage/subscriptions.rst @@ -1,29 +1,76 @@ Subscriptions ============= -Using the :ref:`websockets transport `, it is possible to execute GraphQL subscriptions: +Using the :ref:`websockets transport `, it is possible to execute GraphQL subscriptions, +either using the sync or async usage. + +The async usage is recommended for any non-trivial tasks (it allows efficient concurrent queries and subscriptions). + +See :ref:`Async permanent session ` and :ref:`Async advanced usage ` +for more advanced examples. + +.. note:: + + The websockets transport can also execute queries or mutations, it is not restricted to subscriptions. + +Sync +---- .. code-block:: python - from gql import gql, Client + from gql import Client, gql from gql.transport.websockets import WebsocketsTransport + # Select your transport with a defined url endpoint transport = WebsocketsTransport(url='wss://your_server/graphql') - client = Client( - transport=transport, - fetch_schema_from_transport=True, - ) + # Create a GraphQL client using the defined transport + client = Client(transport=transport) + # Provide a GraphQL subscription query query = gql(''' subscription yourSubscription { ... } ''') + # Connect and subscribe to the results using a simple 'for' for result in client.subscribe(query): print (result) -.. note:: +Async +----- + +.. code-block:: python + + import asyncio + + from gql import Client, gql + from gql.transport.websockets import WebsocketsTransport + + + async def main(): + + # Select your transport with a defined url endpoint + transport = WebsocketsTransport(url='wss://your_server/graphql') + + # Create a GraphQL client using the defined transport + client = Client(transport=transport) + + # Provide a GraphQL subscription query + query = gql(''' + subscription yourSubscription { + ... + } + ''') + + # 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 as session: + + # Then get the results using 'async for' + async for result in client.subscribe(query): + print (result) + - The websockets transport can also execute queries or mutations, it is not restricted to subscriptions + asyncio.run(main()) diff --git a/docs/usage/basic_usage.rst b/docs/usage/sync_usage.rst similarity index 86% rename from docs/usage/basic_usage.rst rename to docs/usage/sync_usage.rst index d53c18d5..f1551618 100644 --- a/docs/usage/basic_usage.rst +++ b/docs/usage/sync_usage.rst @@ -1,9 +1,9 @@ -.. _basic_usage: +.. _sync_usage: -Basic usage ------------ +Sync usage +========== -In order to execute a GraphQL request against a GraphQL API: +To execute a GraphQL request against a GraphQL API: * create your gql :ref:`transport ` in order to choose the destination url and the protocol used to communicate with it @@ -18,4 +18,3 @@ In order to execute a GraphQL request against a GraphQL API: Please note that this basic example won't work if you have an asyncio event loop running. In some python environments (as with Jupyter which uses IPython) an asyncio event loop is created for you. In that case you should use instead the :ref:`Async Usage example`. -