aiohttp

Though it is not required, you can use dishka-aiohttp integration. It features:

  • automatic REQUEST and SESSION scope management using middleware

  • passing Request object as a context data to providers for both Websockets and HTTP requests

  • automatic injection of dependencies into handler function.

How to use

  1. 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:
         ...
  1. 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:
    ...
  1. (optional) Use AiohttpProvider() when creating container if you are going to use aiohttp.web.Request in providers.

container = make_async_container(YourProvider(), AiohttpProvider())
  1. Setup dishka integration. auto_inject=True is required unless you explicitly use @inject decorator

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)
  1. (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:

APPSESSIONREQUEST

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