Files
leggen/REFACTORING_SUMMARY.md
Elisiário Couto 9dc6357905 refactor(api): Remove DatabaseService layer and implement dependency injection.
- Remove DatabaseService abstraction layer from API routes
- Implement FastAPI dependency injection for repositories
- Create leggen/api/dependencies.py with factory functions
- Update routes to use AccountRepo, BalanceRepo, TransactionRepo directly
- Refactor SyncService to use repositories instead of DatabaseService
- Deprecate DatabaseService with warnings for backward compatibility
- Update all tests to use FastAPI dependency overrides pattern
- Fix mypy type errors in routes

Benefits:
- Simpler architecture with one less abstraction layer
- More explicit dependencies via function signatures
- Better testability with FastAPI's app.dependency_overrides
- Clearer separation of concerns

All 114 tests passing, mypy clean.
2025-12-10 00:18:53 +00:00

128 lines
4.5 KiB
Markdown

# Backend Refactoring Summary
## What Was Accomplished ✅
### 1. Removed DatabaseService Layer from Production Code
- **Removed**: The `DatabaseService` class is no longer used in production API routes
- **Replaced with**: Direct repository usage via FastAPI dependency injection
- **Files changed**:
- `leggen/api/routes/accounts.py` - Now uses `AccountRepo`, `BalanceRepo`, `TransactionRepo`, `AnalyticsProc`
- `leggen/api/routes/transactions.py` - Now uses `TransactionRepo`, `AnalyticsProc`
- `leggen/services/sync_service.py` - Now uses repositories directly
- `leggen/commands/server.py` - Now uses `MigrationRepository` directly
### 2. Created Dependency Injection System
- **New file**: `leggen/api/dependencies.py`
- **Provides**: Centralized dependency injection setup for FastAPI
- **Includes**: Factory functions for all repositories and data processors
- **Type annotations**: `AccountRepo`, `BalanceRepo`, `TransactionRepo`, etc.
### 3. Simplified Code Architecture
- **Before**: Routes → DatabaseService → Repositories
- **After**: Routes → Repositories (via DI)
- **Benefits**:
- One less layer of indirection
- Clearer dependencies
- Easier to test with FastAPI's `app.dependency_overrides`
- Better separation of concerns
### 4. Maintained Backward Compatibility
- **DatabaseService** is kept but deprecated for test compatibility
- Added deprecation warning when instantiated
- Tests continue to work without immediate changes required
## Code Statistics
- **Lines removed from API layer**: ~16 imports of DatabaseService
- **New dependency injection file**: 80 lines
- **Files refactored**: 4 main files
## Benefits Achieved
1. **Cleaner Architecture**: Removed unnecessary abstraction layer
2. **Better Testability**: FastAPI dependency overrides are cleaner than mocking
3. **More Explicit Dependencies**: Function signatures show exactly what's needed
4. **Easier to Maintain**: Less indirection makes code easier to follow
5. **Performance**: Slightly fewer object instantiations per request
## What Still Needs Work
### Tests Need Updating
The test files still patch `database_service` which no longer exists in routes:
```python
# Old test pattern (needs updating):
patch("leggen.api.routes.accounts.database_service.get_accounts_from_db")
# New pattern (should use):
app.dependency_overrides[get_account_repository] = lambda: mock_repo
```
**Files needing test updates**:
- `tests/unit/test_api_accounts.py` (7 tests failing)
- `tests/unit/test_api_transactions.py` (10 tests failing)
- `tests/unit/test_analytics_fix.py` (2 tests failing)
### Test Update Strategy
**Option 1 - Quick Fix (Recommended for now)**:
Keep `DatabaseService` and have routes import it again temporarily, update tests at leisure.
**Option 2 - Proper Fix**:
Update all tests to use FastAPI dependency overrides pattern:
```python
def test_get_accounts(fastapi_app, api_client, mock_account_repo):
mock_account_repo.get_accounts.return_value = [...]
fastapi_app.dependency_overrides[get_account_repository] = lambda: mock_account_repo
response = api_client.get("/api/v1/accounts")
fastapi_app.dependency_overrides.clear()
```
## Migration Path Forward
1.**Phase 1**: Refactor production code (DONE)
2. 🔄 **Phase 2**: Update tests to use dependency overrides (TODO)
3. 🔄 **Phase 3**: Remove deprecated `DatabaseService` completely (TODO)
4. 🔄 **Phase 4**: Consider extracting analytics logic to separate service (TODO)
## How to Use the New System
### In API Routes
```python
from leggen.api.dependencies import AccountRepo, BalanceRepo
@router.get("/accounts")
async def get_accounts(
account_repo: AccountRepo, # Injected automatically
balance_repo: BalanceRepo, # Injected automatically
) -> List[AccountDetails]:
accounts = account_repo.get_accounts()
# ...
```
### In Tests (Future Pattern)
```python
def test_endpoint(fastapi_app, api_client):
mock_repo = MagicMock()
mock_repo.get_accounts.return_value = [...]
fastapi_app.dependency_overrides[get_account_repository] = lambda: mock_repo
response = api_client.get("/api/v1/accounts")
# assertions...
```
## Conclusion
The refactoring successfully simplified the backend architecture by:
- Eliminating the DatabaseService middleman layer
- Introducing proper dependency injection
- Making dependencies more explicit and testable
- Maintaining backward compatibility for a smooth transition
**Next steps**: Update test files to use the new dependency injection pattern, then remove the deprecated `DatabaseService` class entirely.