aiohttp¶
Though it is not required, you can use dishka-aiohttp integration. It features:
automatic REQUEST and SESSION scope management using middleware
passing
Requestobject as a context data to providers for both Websockets and HTTP requestsautomatic injection of dependencies into handler function.
How to use¶
Import
from dishka.integrations.aiohttp import (
DISHKA_CONTAINER_KEY,
FromDishka,
inject,
setup_dishka,
AiohttpProvider,
)
from dishka import make_async_container, Provider, provide, Scope
2. Create provider. You can use aiohttp.web.Request as a factory parameter to access HTTP or Websocket request.
It is available on SESSION and REQUEST scopes.
class YourProvider(Provider):
@provide(scope=Scope.REQUEST)
def create_x(self, request: Request) -> X:
...
Mark those of your handlers parameters which are to be injected with
FromDishka[]
@router.get('/')
async def endpoint(
request: str, gateway: FromDishka[Gateway],
) -> Response:
...
3a. (optional) decorate them using @inject
@router.get('/')
@inject
async def endpoint(
request: str, gateway: FromDishka[Gateway],
) -> Response:
...
(optional) Use
AiohttpProvider()when creating container if you are going to useaiohttp.web.Requestin providers.
container = make_async_container(YourProvider(), AiohttpProvider())
Setup
dishkaintegration.auto_inject=Trueis required unless you explicitly use@injectdecorator
setup_dishka(container=container, app=app, auto_inject=True)
Or pass your own inject decorator
setup_dishka(container=container, app=app, auto_inject=my_inject)
(optional) Close container on app termination
async def on_shutdown(app: Application):
await app[DISHKA_CONTAINER_KEY].close()
app.on_shutdown.append(on_shutdown)
Websockets¶
For most cases we operate single events like HTTP-requests. In this case we operate only 2 scopes: APP and REQUEST.
Websockets are different: for one application you have multiple connections (one per client) and each connection delivers multiple messages.
To support this we use additional scope: SESSION:
APP→SESSION→REQUEST
In aiohttp your view function is called once per connection and then you retrieve messages in loop.
So, inject decorator can be only used to retrieve SESSION-scoped objects.
To achieve REQUEST-scope you can enter in manually:
@inject
async def get_with_request(
request: Request,
a: FromDishka[A], # some object with Scope.SESSION
container: FromDishka[AsyncContainer], # container for Scope.SESSION
) -> web.WebsocketResponse:
websocket = web.WebsocketResponse()
await websocket.prepare(request)
async for message in websocket:
# enter the nested scope, which is Scope.REQUEST
async with container() as request_container:
b = await request_container.get(B) # object with Scope.REQUEST