More advanced example of usage with FastAPI - fastapi-sqlalchemy-template
- Install
modern-di-fastapi:
=== "uv"
```bash
uv add modern-di-fastapi
```
=== "pip"
```bash
pip install modern-di-fastapi
```
=== "poetry"
```bash
poetry add modern-di-fastapi
```
- Apply this code example to your application:
import datetime
import contextlib
import typing
import fastapi
import modern_di_fastapi
from modern_di import Container, Group, Scope, providers
app = fastapi.FastAPI()
def create_singleton() -> datetime.datetime:
return datetime.datetime.now(tz=datetime.timezone.utc)
class AppGroup(Group):
singleton = providers.Factory(
scope=Scope.APP,
creator=create_singleton,
cache_settings=providers.CacheSettings()
)
# Register your groups
ALL_GROUPS = [AppGroup]
# Setup DI with your groups
modern_di_fastapi.setup_di(app, Container(groups=ALL_GROUPS))
@app.get("/")
async def read_root(
instance: typing.Annotated[
datetime.datetime,
modern_di_fastapi.FromDI(datetime.datetime), # Resolve by type instead of provider
],
) -> datetime.datetime:
return instanceUsually our application uses only two scopes: APP and REQUEST.
But when websockets are used, SESSION scope is used as well:
- for the lifetime of websocket-connection we have
SESSIONscope - for each message we have
REQUESTscope
APP → SESSION → REQUEST
SESSION scope is entered automatically.
REQUEST scope must be entered manually:
import typing
import fastapi
import modern_di
import modern_di_fastapi
app = fastapi.FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(
websocket: fastapi.WebSocket,
session_container: typing.Annotated[modern_di.Container, fastapi.Depends(modern_di_fastapi.build_di_container)],
) -> None:
await websocket.accept()
request_container = session_container.build_child_container(scope=modern_di.Scope.REQUEST)
# REQUEST scope is entered here
try:
# You can resolve dependencies here
await websocket.send_text("test")
finally:
await request_container.close_async()
await websocket.close()Framework-specific context objects like fastapi.Request and fastapi.WebSocket are automatically made available by the integration.
You can reference these context providers in your factories either implicitly through type annotations or explicitly by importing them.
The following context providers are available for import:
fastapi_request_provider- Provides the currentfastapi.Requestobjectfastapi_websocket_provider- Provides the currentfastapi.WebSocketobject
In many cases, you can rely on automatic dependency resolution based on type annotations:
import fastapi
from modern_di import Group, Scope, providers
def create_request_info(request: fastapi.Request) -> dict[str, str]:
return {
"method": request.method,
"url": str(request.url),
"timestamp": "2023-01-01T00:00:00Z"
}
class AppGroup(Group):
# Factory automatically resolves the request dependency based on type annotation
request_info = providers.Factory(
scope=Scope.REQUEST,
creator=create_request_info,
)For more control, you can explicitly reference the context providers:
import fastapi
import modern_di_fastapi
from modern_di import Group, Scope, providers
def create_request_info(request: fastapi.Request) -> dict[str, str]:
return {
"method": request.method,
"url": str(request.url),
"timestamp": "2023-01-01T00:00:00Z"
}
class AppGroup(Group):
# Factory explicitly uses the request provider from the integration
request_info = providers.Factory(
scope=Scope.REQUEST,
creator=create_request_info,
kwargs={"request": modern_di_fastapi.fastapi_request_provider}
)