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

Possibility to inject FastAPI Request object as argument of router dependency

Open AshurovRustam opened this issue 3 years ago • 7 comments

Hi mates, trying use this beautiful lib with FastApi as better IoC container but not sure whether it is possible to inject http Request object as argument of FastApi router dependency.

So let's say I have a router where a Service is injected: @router.get('/') @inject async def get(search_service: SearchService = Depends(Provide[Container.service])):...

Service itself has ctor parameter of http Request type: class Service: def __init__(self, request: Request):...

And in container it is registered via Factory provider: service=providers.Factory(Service)

As result during http request argument is not given and exception is thrown. However FastApi framework without DependencyInjector able to analyze constructor parameters and provide instance of http request in case it is required via Depends built in DI mechanism: @router.get('/') async def get(search_service: SearchService = Depends(SearchService)):... But for sure in future Service could have other dependencies and I prefer to use dedicated IoC container with its separated bindings So yeah the question is: is it possible to get http Request object somehow automatically?

Many thanks

AshurovRustam avatar Jan 18 '21 21:01 AshurovRustam

Hi @AshurovRustam , right now it's not possible. I'm not sure if that's gonna work, but I could try to implement this.

As a temporary solution you can use Provider marker to inject service provider and initialize service inside the handler:

from dependency_injector import providers
from dependency_injector.wiring import inject, Provider


@router.get('/', response_model=Response)
@inject
async def index(
        request: Request,
        service_provider: providers.Factory[Service] = Depends(Provider[Container.service]),
):
    service = service_provider(request)
    ...

I will get back after running some experiments.

rmk135 avatar Jan 19 '21 02:01 rmk135

Thanks for your quick response @rmk135 Roman, it is exactly how I'm using it now. Probably having usage of providers only in routers is not a big problem for me while these DI concepts don't leak to the lower layers of the application.

Plus maybe I should consider to organize access to the request data via some static contextvars collection that will be populated in FastApi middleware per request. Probably DI Factory provider being something like "transient" type of DI binding will also access this static contextvars collection per request and pass its value as argument of Service ctor parameter properly?

AshurovRustam avatar Jan 19 '21 09:01 AshurovRustam

👍 I think having contextvar scope would a good idea anyway.

sonthonaxrk avatar Mar 29 '21 13:03 sonthonaxrk

Any further thoughts on this? Would be hugely helpful.

dandiep avatar Oct 06 '21 01:10 dandiep

I didn't get to these experiments yet, my apologies. I still believe that the closest solution to this problem should be in using contextvars + middleware + special provider for context vars.

As of now I can share this piece of code: https://gist.github.com/rmk135/ddc45d2cd1981bfe3d4486dbfbba0b1a This is based on aiohttp. Server gets some data from the request and pushes it into contextvars, that are later used for making the injections in the container.

rmk135 avatar Oct 06 '21 02:10 rmk135

Thanks. On a related note, I also found this which was super helpful: https://gist.github.com/ddanier/ead419826ac6c3d75c96f9d89bea9bd0

dandiep avatar Oct 06 '21 02:10 dandiep

Hi guys 👋 Any news on this? It'd be very nice to have it out of the box, without using ContextVars to work around this. Thanks a lot

ale7canna avatar Apr 11 '22 18:04 ale7canna