Hi,
I have released a new version of Dependency Injector 4.4. It allows you to use Dependency Injector with FastAPI . In this post I will show you how it works.
The main task of the integration is to make friends with the
Depends
FastAPI directive with markers Provide
and the Provider
Dependency Injector.
This did not work out of the box prior to DI 4.4. FastAPI uses typing and Pydantic for input and response validation. Dependency Injector markers puzzled him.
The solution came after examining the internals of FastAPI. I had to make several changes in the wiring module of the Dependency Injector. The directive
Depends
now works with markers Provide
and Provider
.
Example
Create a file
fastapi_di_example.py
and put the following lines in it:
import sys
from fastapi import FastAPI, Depends
from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide
class Service:
async def process(self) -> str:
return 'Ok'
class Container(containers.DeclarativeContainer):
service = providers.Factory(Service)
app = FastAPI()
@app.api_route('/')
@inject
async def index(service: Service = Depends(Provide[Container.service])):
result = await service.process()
return {'result': result}
container = Container()
container.wire(modules=[sys.modules[__name__]])
To run the example, install the dependencies:
pip install fastapi dependency-injector uvicorn
and run
uvicorn
:
uvicorn fastapi_di_example:app --reload
The terminal should display something like:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [11910] using watchgod
INFO: Started server process [11912]
INFO: Waiting for application startup.
INFO: Application startup complete.
but
http://127.0.0.1:8000
should return:
{
"result": "Ok"
}
How to test?
Create a file next
tests.py
to it and put the following lines in it:
from unittest import mock
import pytest
from httpx import AsyncClient
from fastapi_di_example import app, container, Service
@pytest.fixture
def client(event_loop):
client = AsyncClient(app=app, base_url='http://test')
yield client
event_loop.run_until_complete(client.aclose())
@pytest.mark.asyncio
async def test_index(client):
service_mock = mock.AsyncMock(spec=Service)
service_mock.process.return_value = 'Foo'
with container.service.override(service_mock):
response = await client.get('/')
assert response.status_code == 200
assert response.json() == {'result': 'Foo'}
To run the tests, install the dependencies:
pip install pytest pytest-asyncio httpx
and run
pytest
:
pytest tests.py
The terminal should display:
======= test session starts =======
platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: ...
plugins: asyncio-0.14.0
collected 1 item
tests.py . [100%]
======= 1 passed in 0.17s =======
What does integration give?
FastAPI is a cool API building framework. The basic dependency injection mechanism is built into it.
This integration improves the FastAPI dependency injection experience. It allows you to use providers, overrides, config and resources of the Dependency Injector in it.
What's next?
- Check out the project's Github
- Check out the documentation
- See an example FastAPI with multiple modules