Skip to content

Step 2: IoC Registration

Understand how the dependency injection container wires services automatically with diwire.

What You'll Learn

  • How get_container builds the container
  • How recursive auto-wiring works
  • When to use add, add_factory_class, and add_instance

Concept Reference

See also: IoC Container concept

Container Creation

The container is created in src/fastdjango/ioc/container.py:

from diwire import Container, DependencyRegistrationPolicy, MissingPolicy


def get_container(
    *,
    configure_django: bool = True,
    configure_logging: bool = True,
    configure_logfire: bool = True,
    instrument_libraries: bool = True,
) -> Container:
    container = Container(
        missing_policy=MissingPolicy.REGISTER_RECURSIVE,
        dependency_registration_policy=DependencyRegistrationPolicy.REGISTER_RECURSIVE,
    )

    if configure_django:
        _configure_django(container)

    if configure_logging:
        _configure_logging(container)

    if configure_logfire:
        _configure_logfire(container)

    if instrument_libraries:
        _instrument_libraries(container)

    register_dependencies(container)
    return container

Configuration components (DjangoConfigurator, LoggingConfigurator, telemetry instrumentor) are also resolved from this same container.

Auto-Wiring Behavior

When you call container.resolve(TodoService), diwire:

  1. Inspects constructor type hints
  2. Recursively resolves dependencies
  3. Applies the container's lifetime/scope defaults
  4. Returns the instance
service = container.resolve(TodoService)
assert service is not None

FastAPIFactory Resolution by Type

The HTTP app resolves the factory by type from the bootstrap container:

from fastdjango.entrypoints.fastapi.bootstrap import container
from fastdjango.entrypoints.fastapi.factories import FastAPIFactory

api_factory = container.resolve(FastAPIFactory)

No string-key registration is used.

Manual Registration APIs

Use explicit registration only for special cases:

# Class registration
container.add(ConcreteService)

# Callable factory class registration
container.add_factory_class(ConcreteServiceFactory, provides=ServiceProtocol)

# Instance override (tests)
container.add_instance(mock_service, provides=ConcreteService)

Testing Rule: Override Early

Override before first resolve of anything that would cache the original dependency:

mock = MagicMock(spec=TodoService)
container.add_instance(mock, provides=TodoService)

controller = container.resolve(TodoController)

Summary

  • get_container uses diwire.Container with recursive registration policies
  • Dependencies are resolved by type, including FastAPIFactory
  • Test overrides use add_instance(..., provides=...) before first resolve