Skip to content

Latest commit

 

History

History
171 lines (119 loc) · 4.12 KB

File metadata and controls

171 lines (119 loc) · 4.12 KB

Usage with FastAPI

More advanced example of usage with FastAPI - fastapi-sqlalchemy-template

How to use

  1. 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
  ```
  1. 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 instance

Websockets

Usually 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 SESSION scope
  • for each message we have REQUEST scope

APPSESSIONREQUEST

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 Context Objects

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 current fastapi.Request object
  • fastapi_websocket_provider - Provides the current fastapi.WebSocket object

Implicit Usage (Type-based Resolution)

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,
    )

Explicit Usage (Provider-based Resolution)

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}
    )