-
-
Notifications
You must be signed in to change notification settings - Fork 340
Description
Hi.
Docs inlcude the FastAPI example, python-dependency-injector itself works with FastAPI, but I found a case when it doesn't. Let's consider a simple FastAPI application with two dependencies:
from fastapi import Depends, FastAPI
async def service_process():
return "foo"
async def dep1():
await service_process()
print("dep1 - A")
yield
print("dep1 - B")
async def dep2():
print("dep2 - A")
yield
print("dep2 - B")
app = FastAPI(dependencies=[Depends(dep1), Depends(dep2)])
@app.api_route("/")
async def index():
returnThe result of calling / would be:
dep1 - A
dep2 - A
dep2 - B
dep1 - BIt's because of how yield works in FastAPI dependencies - everything that happens before yield happens at the beginning of an endpoint, everything after -> happens after a response is returned.
Okay, let's throw python-dependency-injector into the mix. I took this example from examples/miniapps/fastapi-simple/fastapi_di_example.py and added dependencies - one with @inject. The example itself contains meaningless prints, but in the real app that I'm working on, the app configuration is injected in the dependencies.
from fastapi import FastAPI, Depends
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Service:
async def process(self) -> str:
return "OK"
class Container(containers.DeclarativeContainer):
service = providers.Factory(Service)
@inject
async def dep1(service: Service = Depends(Provide[Container.service])):
await service.process()
print("dep1 - A")
yield
print("dep1 - B")
async def dep2():
print("dep2 - A")
yield
print("dep2 - B")
app = FastAPI(dependencies=[Depends(dep1), Depends(dep2)])
@app.api_route("/")
async def index():
return
container = Container()
container.wire(modules=[__name__])The output is:
dep2 - A
dep2 - BHowever, if I remove yield from dep1:
@inject
async def dep1(service: Service = Depends(Provide[Container.service])):
await service.process()
print("dep1 - A")
print("dep1 - B"), the output is:
dep1 - A
dep1 - B
dep2 - A
dep2 - BThe different order here is because without yield, the prints in dep1 happen at the beginning of def index(), in case of dep2 one happens right after the prints from dep1, the other after the response is returned.
But this doesn't matter. What I'm curious about is why does it happen? Why is yield an issue here. It looks like the dependency is not applied at all (no code from dep1 gets executed). I'm not aware of the internals of @inject, so I'm not really sure what happens here. Before you ask - I got to have this yield for various reasons - for example I set a logger context at the beginning of the request and reset it and the end (after the response is returned).
So my question would be: is it possible to use @inject with FastAPI dependencies that with yield?