Skip to content

Latest commit

 

History

History
91 lines (67 loc) · 3.02 KB

File metadata and controls

91 lines (67 loc) · 3.02 KB

Context Providers

Often, scopes are connected with external events: HTTP requests, messages from a queue, callbacks from a framework. These events can be represented by objects which can be used for dependency creation.

ContextProvider is a provider type that allows injecting context values into dependencies. This is particularly useful for injecting framework-specific objects like requests, websockets, etc.

ContextProvider makes context data available to other providers in your dependency graph by extracting values from the container's context.

In integrations, some context objects (like fastapi.Request, litestar.WebSocket, etc.) are automatically provided.

Basic Usage with FastAPI

from modern_di import Group, Container, Scope, providers
import fastapi
import modern_di_fastapi


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 Dependencies(Group):
    # Factory uses the request from context (automatically provided by the integration)
    request_info = providers.Factory(
        scope=Scope.REQUEST,
        creator=create_request_info,
    )


# Create container with context
ALL_GROUPS = [Dependencies]
# Setup DI with your groups
app = fastapi.FastAPI()
container = Container(groups=ALL_GROUPS)
modern_di_fastapi.setup_di(app, container)
# The integration creates a REQUEST-scoped child container per request and
# automatically injects the fastapi.Request into its context. The factory
# is resolved from the child container, not the APP-scope container.

Manual ContextProvider Usage

You may still need to define ContextProviders manually in cases where you want to inject custom context objects that are not automatically provided by the integration:

from modern_di import Group, Container, Scope, providers

# Custom context type
class CustomContext:
    def __init__(self, user_id: str, tenant_id: str) -> None:
        self.user_id = user_id
        self.tenant_id = tenant_id


def create_user_info(custom_context: CustomContext) -> dict[str, str]:
    return {
        "user_id": custom_context.user_id,
        "tenant_id": custom_context.tenant_id,
    }


class Dependencies(Group):
    # Manually defined ContextProvider for custom context
    custom_context = providers.ContextProvider(scope=Scope.REQUEST, context_type=CustomContext)

    # Factory uses the custom context
    user_info = providers.Factory(
        scope=Scope.REQUEST,
        creator=create_user_info,
    )


# Provide custom context when building container
container = Container(groups=[Dependencies])
custom_context = CustomContext(user_id="123", tenant_id="abc")
request_container = container.build_child_container(
    scope=Scope.REQUEST,
    context={CustomContext: custom_context}
)

# Now resolve the factory — it will receive the custom context automatically
user_info = request_container.resolve_provider(Dependencies.user_info)
# {"user_id": "123", "tenant_id": "abc"}