A simple, powerful dependency injection library for FastAPI supporting hexagonal architecture
Project description
fastapi-di-kit
A simple, powerful dependency injection library for FastAPI supporting hexagonal architecture.
Features
- 🎯 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
Installation
uv add fastapi-di-kit
Or with pip:
pip install fastapi-di-kit
Quick Start
1. Define Your Domain (Ports)
from 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:
...
2. Implement Infrastructure (Adapters)
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
...
3. Create Domain Services
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 user
4. Use in FastAPI Routes
from 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
Advanced Features
Lifecycle Management
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:
pass
Lazy Loading
from 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()
Factory Functions
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')
Examples
fastapi-di-kit includes comprehensive examples demonstrating all features:
Quick Examples
- 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
Complete Application
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.
Running Examples
# 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
API Reference
Decorators
@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)
FastAPI Integration
Inject[ServiceType]- Dependency marker for FastAPI routessetup_di_middleware(app)- Add middleware for request-scoped servicesDIMiddleware- The middleware class (auto-added by setup function)
Container
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
Types
Lifecycle.SINGLETON- Single instance shared globallyLifecycle.TRANSIENT- New instance on every resolutionLifecycle.SCOPED- Single instance per requestLazy[T]- Wrapper for lazy dependency loading
Testing
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)
Why fastapi-di-kit?
| Feature | fastapi-di-kit | dependency-injector | FastAPI native |
|---|---|---|---|
| Decorator-based | ✅ | ✅ | ❌ |
| Hexagonal architecture support | ✅ | ⚠️ Complex | ❌ |
| Request-scoped services | ✅ | ✅ | ✅ |
| Circular dependency detection | ✅ | ❌ | ❌ |
| Lazy loading | ✅ | ⚠️ Manual | ❌ |
| Learning curve | Low | High | Low |
License
MIT
Contributing
Contributions welcome! Please feel free to submit a Pull Request.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_di_kit-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_di_kit-0.1.0.tar.gz
- Upload date:
- Size: 39.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ed0bedf5cc7f5fa319f849ddbc92b751a77f0e969cbd51d43046d611a8efbd1
|
|
| MD5 |
fa910568defec5065fb461170f129adc
|
|
| BLAKE2b-256 |
f2daac28aa89486ce09d76822d8b86a010a39d21451471fde30b50cce65807f2
|
File details
Details for the file fastapi_di_kit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_di_kit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08a10a5f25baf2206916d740845368e3a256b45df7e8e342546c0a81bc26c0e9
|
|
| MD5 |
ac8b1aa216c37d862e92523f0c264d8d
|
|
| BLAKE2b-256 |
687528ac5bbe4cd9eb3f63dcf1bc973960c723d2ede6d2fc084c597447f4c238
|