Skip to content

Commit

Permalink
Merge pull request #74 from tartiflette/bubu/add_tests_to_header_feature
Browse files Browse the repository at this point in the history
feat(response_headers): Add the ability to modify response headers using contextvars
  • Loading branch information
abusi authored Jan 29, 2020
2 parents ba1875a + f9a7426 commit 1e53380
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 6 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,23 @@ web.run_app(
- **endpoint** *(Optional[str] = "/graphiql")*: allows to customize the GraphiQL interface endpoint path
- **default_query** *(Optional[str] = None)*: allows you to pre-fill the GraphiQL interface with a default query
- **default_variables** *(Optional[dict] = None)*: allows you to pre-fill the GraphiQL interface with default variables
- **default_headers** *(Optional[dict] = None)*: allows you to add default headers to each request sent through the GraphiQL instance
- **default_headers** *(Optional[dict] = None)*: allows you to add default headers to each request sent through the GraphiQL instance


## Advance Use Case

### Response header manipulation from resolver

It is possible to set header to the response directly from the resolver using `set_response_headers` method like:

```python
from tartiflette_aiohttp import set_response_headers

@Resolver("Query.X")
async def resolver_x(parent_result, args, ctx, info):
# do things
set_response_headers({"Header": "Value", "AnotherHeader": "AnotherValue"})
return result
```

> Note that this feature uses ContextVar and will only works for python 3.7.1 and later.
22 changes: 22 additions & 0 deletions changelogs/1.2.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [1.2.0] - 2020-01-29

## Added

- Possibility to set header to the response directly from the resolver using `set_response_headers` method.

```python
from tartiflette_aiohttp import set_response_headers

@Resolver("Query.X")
async def resolver_x(parent_result, args, ctx, info):
# do things
set_response_headers({"Header": "Value", "AnotherHeader": "AnotherValue"})
return result
```

> Note that this feature uses ContextVar and will only works for python 3.7.1 and later.
## Changed

- pytest updated to 5.3.4
- pylint updated to 2.4.4
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from setuptools import find_packages, setup

_TEST_REQUIRE = [
"pytest==5.3.2",
"pytest==5.3.4",
"pytest-cov==2.8.1",
"pytest-asyncio==0.10.0",
"pytest-aiohttp==0.3.0",
Expand All @@ -13,7 +13,7 @@
"isort==4.3.21",
]

_VERSION = "1.1.1"
_VERSION = "1.2.0"

_PACKAGES = find_packages(exclude=["tests*"])

Expand Down
3 changes: 2 additions & 1 deletion tartiflette_aiohttp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from tartiflette_aiohttp._context_factory import default_context_factory
from tartiflette_aiohttp._graphiql import graphiql_handler
from tartiflette_aiohttp._handler import Handlers
from tartiflette_aiohttp._reponse_headers import set_response_headers
from tartiflette_aiohttp._subscription_ws_handler import (
AIOHTTPSubscriptionHandler,
)
Expand Down Expand Up @@ -210,4 +211,4 @@ def register_graphql_handlers(
return app


__all__ = ["register_graphql_handlers"]
__all__ = ["register_graphql_handlers", "set_response_headers"]
5 changes: 3 additions & 2 deletions tartiflette_aiohttp/_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from aiohttp import web

from ._reponse_headers import get_response_headers

logger = logging.getLogger(__name__)


Expand All @@ -27,8 +29,7 @@ class BadRequestError(Exception):


def prepare_response(data):
headers = {}
# TODO Do things with header here
headers = get_response_headers()
return web.json_response(data, headers=headers, dumps=json.dumps)


Expand Down
24 changes: 24 additions & 0 deletions tartiflette_aiohttp/_reponse_headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
_RESPONSE_HEADERS_VAR = None
try:
import contextvars

_RESPONSE_HEADERS_VAR = contextvars.ContextVar(
"response_headers", default={}
)
except ImportError:
pass


def set_response_headers(headers: dict):
if _RESPONSE_HEADERS_VAR is not None:
_RESPONSE_HEADERS_VAR.get().update(headers)
else:
print(
"This feature < set_response_headers > only works with python 3.7"
)


def get_response_headers():
if _RESPONSE_HEADERS_VAR is not None:
return _RESPONSE_HEADERS_VAR.get()
return {}
42 changes: 42 additions & 0 deletions tests/functional/test_headers_context_vars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import contextvars
import json

import pytest

from aiohttp import web

from tartiflette import Engine, Resolver, create_engine
from tartiflette_aiohttp import register_graphql_handlers, set_response_headers


async def test_header_context_var(aiohttp_client, loop):
@Resolver("Query.bob", schema_name="test_header_context_var")
async def resolver_lol(*args, **kwargs):
set_response_headers({"X-Test": "Lol", "Z-Test": "Ninja"})
return {"name": "a", "surname": "b"}

class myEngine(Engine):
def __init__(self):
super().__init__()

async def cook(self, *args, **kwargs):
await super().cook(*args, **kwargs)

app = register_graphql_handlers(
app=web.Application(),
engine=myEngine(),
engine_sdl="""type Query { bob: Ninja } type Ninja { name: String surname: String }""",
engine_schema_name="test_header_context_var",
)

client = await aiohttp_client(app)
resp = await client.post(
"/graphql",
data=json.dumps({"query": "query lol { bob { name surname } }"}),
headers={"content-type": "application/json"},
)
assert resp.status == 200
result = await resp.json()
assert result == {"data": {"bob": {"name": "a", "surname": "b"}}}
assert resp.headers["X-Test"] == "Lol"
assert resp.headers["Z-Test"] == "Ninja"

0 comments on commit 1e53380

Please sign in to comment.