Provides a context generator parameter
Maximilien-R opened this issue · 2 comments
I think it could be a good idea to add a new context_factory
optional parameter to the register_graphql_handlers
function.
The aim of this function would be to generate a new context on each request instead of the actual executor_context
parameter which only allow to provide a context at engine and endpoints initialization time.
This parameter could take a (async?) callable which could implements the following implementation:
from typing import Any, Dict
def context_factory(req: "aiohttp.web.Request", context: Dict[str, Any]) -> Dict[str, Any]:
"""
Generates a new context.
:param req: the incoming aiohttp request instance
:param context: the value filled in through the `executor_context` parameter
:type req: aiohttp.web.Request
:type context: Dict[str, Any]
:return: the context for the incoming request
:rtype: Dict[str, Any]
"""
pass
To be retro-compatible, the default implementation could be:
from copy import copy
from typing import Any, Dict
def default_context_factory(req: "aiohttp.web.Request", context: Dict[str, Any]) -> Dict[str, Any]:
"""
Generates a new context.
:param req: the incoming aiohttp request instance
:param context: the value filled in through the `executor_context` parameter
:type req: aiohttp.web.Request
:type context: Dict[str, Any]
:return: the context for the incoming request
:rtype: Dict[str, Any]
"""
return copy(context)
Also, having access to the request
through this callable could allow to build a more complex et useful context by reading headers
for example.
Finally, both executor_context
and context_factory
could be used at the same time to build a dynamic/static context:
from typing import Any, Dict
def custom_context_factory(req: "aiohttp.web.Request", context: Dict[str, Any]) -> Dict[str, Any]:
"""
Generates a new context.
:param req: the incoming aiohttp request instance
:param context: the value filled in through the `executor_context` parameter
:type req: aiohttp.web.Request
:type context: Dict[str, Any]
:return: the context for the incoming request
:rtype: Dict[str, Any]
"""
return {
**context,
# request contextualized data
"authorization_token": req.headers.get("Authorization"),
}
register_graphql_handlers(
app=web.Application(),
engine_sdl="/sdl",
executor_context={
"redis_client": RedisCient(), # not request contextualized
},
context_factory=custom_context_factory,
)
@abusi @tsunammis what do you think of it?
Liking it very much. Go for it.
Should it be async
? Its always a plus, isn't? 😆 Or maybe we should handle both with a check before calling the factory?