Skip to content

Commit

Permalink
Pass extra request options to aiohttp (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
DoctorJohn authored Nov 12, 2023
1 parent 47651d9 commit 87481af
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 12 deletions.
3 changes: 2 additions & 1 deletion aiogqlc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ async def execute(
query: str,
variables: Optional[Dict[str, Any]] = None,
operation: Optional[str] = None,
**kwargs,
) -> aiohttp.ClientResponse:
nulled_variables, files_to_paths_mapping = self.prepare(variables)
data_param: Dict[str, Any]
Expand All @@ -182,7 +183,7 @@ async def execute(
json_data = serialize_payload(query, variables, operation)
data_param = {"json": json_data}

async with self.session.post(self.endpoint, **data_param) as response:
async with self.session.post(self.endpoint, **kwargs, **data_param) as response:
await response.read()
return response

Expand Down
23 changes: 23 additions & 0 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Advanced usage

## Passing request options to `aiohttp`

While you can set various default options on your `aiohttp.ClientSession` instance,
there's sometimes the need to pass extra options to the underlying request made by `aiohttp`.

For this purpose, any additional keyword argument passed to `GraphQLClient.execute` will be passed to `aiohttp.ClientSession.request`.

```python
import aiohttp
from aiogqlc import GraphQLClient

async def foo():
async with aiohttp.ClientSession() as session:
client = GraphQLClient("https://example.com/graphql/", session=session)

response = await client.execute(
document="query { someField }",
headers={"Authorization": "Bearer SomeToken"},
timeout=aiohttp.ClientTimeout(total=10),
)
```
20 changes: 19 additions & 1 deletion docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Take a look at the [aiohttp documentation][aiohttp-headers-url] to learn more.

[aiohttp-headers-url]: https://docs.aiohttp.org/en/stable/client_advanced.html#custom-request-headers

The following example shows how to set a default `Authorization` header for the whole session.

```python
import aiohttp
from aiogqlc import GraphQLClient
Expand All @@ -20,6 +22,22 @@ async def foo():
client = GraphQLClient("https://example.com/graphql/", session=session)
```

Instead of setting a default header for the whole session, you can also set a header for a single request.

```python
import aiohttp
from aiogqlc import GraphQLClient

headers = {
"Authorization": "Token <your-token-here>"
}

async def foo():
async with aiohttp.ClientSession() as session:
client = GraphQLClient("https://example.com/graphql/", session=session)
response = await client.execute("query { someField }", headers=headers)
```

## Authenticate `graphql-ws` connections

GraphQL servers _usualy_ don't support the authentication of WebSocket connections via
Expand All @@ -39,7 +57,7 @@ from aiogqlc import GraphQLClient
async def foo():
async with aiohttp.ClientSession() as session:
client = GraphQLClient("https://example.com/graphql/", session=session)

connection_params = {
"username": "john",
"password": "1234",
Expand Down
20 changes: 10 additions & 10 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
site_name: AIOGQLC
site_description: LUL
site_description: "Python aynchronous/IO GraphQL client with file upload and subscription support."
site_url: https://doctorjohn.github.io/aiogqlc/
repo_url: https://github.com/DoctorJohn/aiogqlc/

Expand All @@ -20,20 +20,20 @@ markdown_extensions:
use_pygments: true
anchor_linenums: true
- pymdownx.tabbed:
alternate_style: true
alternate_style: true
- pymdownx.superfences
- pymdownx.details


nav:
- Overview: index.md
- Getting started: getting-started.md
- Operations:
- Queries: queries.md
- Mutations: mutations.md
- File Uploads: file-uploads.md
- Subscriptions: subscriptions.md
- Authentication: authentication.md
- Queries: queries.md
- Mutations: mutations.md
- File Uploads: file-uploads.md
- Subscriptions: subscriptions.md
- Authentication: authentication.md
- Advanced Usage: advanced-usage.md
- Guides:
- Contributing: contributing.md
- Migrating: migrating.md
- Contributing: contributing.md
- Migrating: migrating.md
4 changes: 4 additions & 0 deletions tests/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def todos(self) -> typing.List[Todo]:
def todo(self, id: strawberry.ID) -> Todo:
return todos[int(id)]

@strawberry.field
def authorization_header(self, info: Info) -> str:
return info.context["request"].headers["Authorization"]


@strawberry.type
class Mutation:
Expand Down
37 changes: 37 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from aiogqlc import GraphQLClient
from tests.app import create_app


async def test_execute_extra_kwargs_are_passed_to_aiohttp(graphql_session):
query = """
query {
authorizationHeader
}
"""

client = GraphQLClient(endpoint="/graphql", session=graphql_session)
response = await client.execute(query, headers={"Authorization": "Bearer Token123"})

assert await response.json() == {"data": {"authorizationHeader": "Bearer Token123"}}


async def test_default_headers_can_be_overridden(aiohttp_client):
app = create_app()
graphql_session = await aiohttp_client(
app, headers={"Authorization": "Bearer DefaultToken"}
)

query = """
query {
authorizationHeader
}
"""

client = GraphQLClient(endpoint="/graphql", session=graphql_session)
response = await client.execute(
query, headers={"Authorization": "Bearer SpecialToken"}
)

result = await response.json()
assert result["data"]["authorizationHeader"] != "Bearer DefaultToken"
assert result["data"]["authorizationHeader"] == "Bearer SpecialToken"

0 comments on commit 87481af

Please sign in to comment.