Skip to main content

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

  1. Basic Usage - Service registration, dependency injection, container basics
  2. Lifecycle Management - SINGLETON, TRANSIENT, and SCOPED lifecycles
  3. Lazy Loading - Defer expensive initialization with Lazy[T]
  4. Factory Functions - Complex initialization and runtime configuration
  5. Testing and Mocking - Test patterns and mock implementations
  6. 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 routes
  • setup_di_middleware(app) - Add middleware for request-scoped services
  • DIMiddleware - The middleware class (auto-added by setup function)

Container

  • get_container() - Access the global DI container
  • container.register(service_type, factory, lifecycle, interface) - Manual registration
  • container.resolve(service_type) - Manual resolution
  • container.request_scope() - Context manager for request scope

Types

  • Lifecycle.SINGLETON - Single instance shared globally
  • Lifecycle.TRANSIENT - New instance on every resolution
  • Lifecycle.SCOPED - Single instance per request
  • Lazy[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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_di_kit-0.1.0.tar.gz (39.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_di_kit-0.1.0-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

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

Hashes for fastapi_di_kit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9ed0bedf5cc7f5fa319f849ddbc92b751a77f0e969cbd51d43046d611a8efbd1
MD5 fa910568defec5065fb461170f129adc
BLAKE2b-256 f2daac28aa89486ce09d76822d8b86a010a39d21451471fde30b50cce65807f2

See more details on using hashes here.

File details

Details for the file fastapi_di_kit-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_di_kit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 08a10a5f25baf2206916d740845368e3a256b45df7e8e342546c0a81bc26c0e9
MD5 ac8b1aa216c37d862e92523f0c264d8d
BLAKE2b-256 687528ac5bbe4cd9eb3f63dcf1bc973960c723d2ede6d2fc084c597447f4c238

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page