A simple, powerful dependency injection library for FastAPI supporting hexagonal architecture.
- 🎯 Decorator-based Registration - Simply decorate classes with
@service,@repository, or@factory - 🔄 Lifecycle Management - Support for singleton, transient, and request-scoped services
- 🏗️ Hexagonal Architecture - Interface-to-implementation binding for ports and adapters pattern
- ⚡ FastAPI Integration - Seamless integration with FastAPI's dependency injection via
Inject[ServiceType] - 🔍 Circular Dependency Detection - Automatic detection and clear error messages
- 💤 Lazy Loading - Defer dependency resolution with
Lazy[T]wrapper - 🧪 Test-Friendly - Easy mocking and dependency overriding
uv add fastapi-di-kitOr with pip:
pip install fastapi-di-kitfrom typing import Protocol
class IUserRepository(Protocol):
def get_user(self, id: int) -> User:
...
class IEmailService(Protocol):
def send_email(self, to: str, subject: str) -> bool:
...from fastapi_di_kit import repository, Lifecycle
@repository(interface=IUserRepository, lifecycle=Lifecycle.SINGLETON)
class PostgresUserRepository:
def get_user(self, id: int) -> User:
# Database logic here
...
@repository(interface=IEmailService)
class SendGridEmailService:
def send_email(self, to: str, subject: str) -> bool:
# Email sending logic
...from fastapi_di_kit import service
@service()
class UserService:
def __init__(self, repository: IUserRepository, email: IEmailService):
self.repository = repository
self.email = email
def register_user(self, name: str, email: str) -> User:
user = self.repository.create_user(name, email)
self.email.send_email(email, "Welcome!")
return userfrom fastapi import FastAPI, Depends
from fastapi_di_kit import Inject, setup_di_middleware
app = FastAPI()
setup_di_middleware(app) # Enable request-scoped services
@app.post("/users")
def create_user(
name: str,
email: str,
service: UserService = Depends(Inject[UserService])
):
return service.register_user(name, email)That's it! The DI container automatically:
✅ Resolves dependencies based on type hints
✅ Injects the correct implementations
✅ Manages lifecycles
✅ Detects circular dependencies
from fastapi_di_kit import service, Lifecycle
@service(lifecycle=Lifecycle.SINGLETON) # One instance for the entire app
class ConfigService:
pass
@service(lifecycle=Lifecycle.TRANSIENT) # New instance every time
class RequestLogger:
pass
@service(lifecycle=Lifecycle.SCOPED) # One instance per HTTP request
class AuthContext:
passfrom fastapi_di_kit import service, Lazy
@service()
class ReportGenerator:
def __init__(self, heavy_analyzer: Lazy[HeavyAnalyzer]):
self._analyzer_factory = heavy_analyzer
def generate(self):
if self.needs_analysis:
# Only load when needed
analyzer = self._analyzer_factory()
analyzer.analyze()from fastapi_di_kit import factory
import boto3
@factory(service_type=boto3.client, lifecycle=Lifecycle.SINGLETON)
def create_s3_client():
return boto3.client('s3', region_name='us-east-1')fastapi-di-kit includes comprehensive examples demonstrating all features:
- Basic Usage - Service registration, dependency injection, container basics
- Lifecycle Management - SINGLETON, TRANSIENT, and SCOPED lifecycles
- Lazy Loading - Defer expensive initialization with
Lazy[T] - Factory Functions - Complex initialization and runtime configuration
- Testing and Mocking - Test patterns and mock implementations
- Async Services - Async/await support with FastAPI
Hexagonal Architecture App - Full application demonstrating:
- Domain-driven design
- Port/adapter pattern
- Repository pattern with interface binding
- Clean architecture principles
See examples/README.md for detailed documentation and instructions.
# From repository root
uv run python examples/01_basic_usage.py
uv run python examples/03_lazy_loading.py
uv run python examples/05_testing_and_mocking.py
# Web server examples (runs on http://localhost:8000)
uv run python examples/02_lifecycle_management.py
uv run python examples/06_async_services.py@service(lifecycle=Lifecycle.SINGLETON, interface=None)- Register a service class@repository(interface, lifecycle=Lifecycle.SINGLETON)- Register a repository with interface binding@factory(service_type, lifecycle=Lifecycle.TRANSIENT)- Register a factory function@inject- Optional marker for dependency injection (auto-detected via type hints)
Inject[ServiceType]- Dependency marker for FastAPI routessetup_di_middleware(app)- Add middleware for request-scoped servicesDIMiddleware- The middleware class (auto-added by setup function)
get_container()- Access the global DI containercontainer.register(service_type, factory, lifecycle, interface)- Manual registrationcontainer.resolve(service_type)- Manual resolutioncontainer.request_scope()- Context manager for request scope
Lifecycle.SINGLETON- Single instance shared globallyLifecycle.TRANSIENT- New instance on every resolutionLifecycle.SCOPED- Single instance per requestLazy[T]- Wrapper for lazy dependency loading
Override dependencies for testing:
from fastapi_di_kit import get_container
def test_user_service():
container = get_container()
# Register a mock
container.register(IEmailService, factory=MockEmailService)
# Now UserService will use MockEmailService
service = container.resolve(UserService)
assert isinstance(service.email, MockEmailService)| Feature | fastapi-di-kit | dependency-injector | FastAPI native |
|---|---|---|---|
| Decorator-based | ✅ | ✅ | ❌ |
| Hexagonal architecture support | ✅ | ❌ | |
| Request-scoped services | ✅ | ✅ | ✅ |
| Circular dependency detection | ✅ | ❌ | ❌ |
| Lazy loading | ✅ | ❌ | |
| Learning curve | Low | High | Low |
MIT
Contributions welcome! Please feel free to submit a Pull Request.