python-dependency-injector icon indicating copy to clipboard operation
python-dependency-injector copied to clipboard

How to make injection in middleware class of Fastapi/Starlette

Open Su57 opened this issue 3 years ago • 0 comments

Hi, i've been using this greate freamework in my project these days. In the docs of wiring, i see it's possible to wire a depedndency into a class directly,but in my project , which is based on fastapi, it's alwasy got an internal error when i try to inject the redis cliet into the middleware class (which is the feature provided by starlette).here is the simplified code :

(python3.9.5, | dependency-injector==4.38.0 | fastapi==0.74.1)

# main.py

from aioredis import from_url
from dependency_injector.containers import *
from dependency_injector.providers import *
from dependency_injector.wiring import Provide
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
from starlette.responses import Response


async def init_redis_pool():
    redis = from_url("redis://localhost:6379/0", max_connections=10)
    try:
        yield redis
    finally:
        await redis.close()


class Container(DeclarativeContainer):
    wiring_config = WiringConfiguration(modules=[__name__])

    redis = Resource(init_redis_pool)


class SomeMiddleware(BaseHTTPMiddleware):
    
    redis = Provide[Container.redis]

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
        print("========> hint SomeMiddleware <===========")
        await self.redis.set("some_key", "some_value")
        resp: Response = await call_next(request)
        return resp


def create_app():
    app = FastAPI()
    app.container = Container()

    @app.on_event("startup")
    def startup():
        app.container.init_resources()

    @app.on_event("shutdown")
    def shutdown():
        app.container.shutdown_resources()

    app.add_middleware(SomeMiddleware)

    return app


application = create_app()


@application.get("/")
async def root():
    return {"message": "Hello World"}

when i startup server with uvicorn main:application --reload and access http://127.0.0.1:8000/, i alwaye get such error msg:

...balblabla...
File ".\main.py", line 31, in dispatch
    await self.redis.set("some_key", "some_value")
AttributeError: '_asyncio.Task' object has no attribute 'set'

did i miss something? :(

Su57 avatar Mar 04 '22 06:03 Su57