> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tasteful.heka.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Dependency Injection

> Understanding Tasteful's dependency injection system and how it powers modular architecture

# Dependency Injection

Tasteful uses the powerful **`dependency-injector`** library to manage component relationships, lifecycles, and testing. This system is the foundation that makes Tasteful's modular architecture possible and maintainable.

<Note>
  Tasteful leverages the **dependency-injector** library for its IoC container implementation. For complete API reference and advanced features, visit the [official dependency-injector documentation](https://python-dependency-injector.ets-labs.org).
</Note>

## Why Dependency Injection?

Dependency injection solves several critical problems in application architecture:

### 🔧 **Testability**

Without DI, testing becomes a nightmare of tight coupling:

```python theme={null}
# ❌ Hard to test - tightly coupled
class UserService:
    def __init__(self):
        self.db = PostgreSQLConnection()  # Always connects to real DB
        self.email = SMTPEmailService()   # Always sends real emails
    
    def create_user(self, user_data):
        user = self.db.save(user_data)
        self.email.send_welcome_email(user.email)
        return user
```

With DI, testing becomes elegant:

```python theme={null}
# ✅ Easy to test - dependencies injected
class UserService:
    def __init__(self, repository: UserRepository, email_service: EmailService):
        self.repository = repository
        self.email_service = email_service
    
    def create_user(self, user_data):
        user = self.repository.save(user_data)
        self.email_service.send_welcome_email(user.email)
        return user

# In tests
def test_create_user():
    mock_repo = Mock(spec=UserRepository)
    mock_email = Mock(spec=EmailService)
    service = UserService(mock_repo, mock_email)
    # Test with complete control over dependencies
```

### 🏗️ **Modularity**

DI enables true modularity where components can be swapped without code changes:

```python theme={null}
# Same service, different implementations
production_app = TastefulApp(
    flavors=[UserFlavor],
    repository=PostgreSQLUserRepository,
    email_service=SendGridEmailService
)

development_app = TastefulApp(
    flavors=[UserFlavor],  
    repository=InMemoryUserRepository,
    email_service=ConsoleEmailService
)
```

### 🔄 **Lifecycle Management**

Automatically handles singleton patterns, lazy loading, and resource cleanup.

## How Tasteful's DI Works

Tasteful uses **declarative containers** from the `dependency-injector` library. Here's the architecture:

### Container Hierarchy

```python theme={null}
# Main application container
class TastefulContainer(containers.DeclarativeContainer):
    flavors = providers.Singleton(BaseFlavor)

# Each flavor has its own container  
class BaseFlavorContainer(containers.DeclarativeContainer):
    services_factory = providers.Factory()
    repository_factory = providers.Factory()
    
    services = providers.Singleton(ServiceDispatcher, __self__)
    repository = providers.Singleton(RepositoryDispatcher, __self__)
```

### Automatic Service Registration

When you define a flavor, Tasteful automatically registers your services using constructor-based dependency injection:

```python theme={null}
class UserController(BaseController):
    def __init__(self, user_service: UserService, email_service: EmailService):
        super().__init__(prefix="/users", tags=["users"])
        self.user_service = user_service
        self.email_service = email_service
    
    @Get("/{user_id}")
    def get_user(self, user_id: int):
        return self.user_service.get_user(user_id)

class UserFlavor(BaseFlavor):
    def __init__(self):
        super().__init__(
            controller=UserController,
            services=[UserService, EmailService],  # ← Automatically registered
            repositories=[UserRepository],         # ← Automatically registered
            config=UserConfig
        )
```

Behind the scenes, Tasteful:

1. **Analyzes constructor signatures** to understand dependencies
2. **Uses graph-based resolution** to determine dependency order
3. **Registers providers** in the container automatically
4. **Injects dependencies** into constructors
5. **Manages lifecycles** (singletons, factories, etc.)
