⚡ Section 8 — Mid-Level Masterclass

Dependency Injection & Testable Architecture

Decouple your services from concrete instantiation. Use FastAPI's Depends() to inject database sessions, repositories, and authentication contexts.

👁️ Views: 374 Page Views
💡 Mindset Shift

Hardcoded Instantiation vs FastAPI Dependency Injection

Hardcoding database connections inside functions prevents mock testing. Dependency injection turns dependencies into configurable parameters.

❌ Hardcoded Database Instantiation (Untestable)
# ❌ Creates real DB connection inside handler
@router.post("/users")
def create_user(data: UserCreate):
    db = SessionLocal() # Hardcoded dependency!
    repo = SqlAlchemyUserRepository(db)
    service = UserService(repo)
    return service.create_user(data)
✅ FastAPI Depends() Injection (100% Testable)
# ✅ Injected automatically via Depends() provider
@router.post("/users")
def create_user(
    data: UserCreate,
    service: UserService = Depends(get_user_service)
):
    return service.create_user(data)

⚡ The FastAPI Provider Chain

1. get_db()
➔
2. get_user_repository(db=Depends())
➔
3. get_user_service(repo=Depends())
➔
4. @router.post(service=Depends())

💻 Production Blueprint: Provider Factories & Pytest Overrides

Observe how `app.dependency_overrides` lets you swap out real database providers for mock implementations during automated testing.

# ─── 1. DEPENDENCY PROVIDER FACTORY (api/dependencies.py) ─────────────────
def get_user_service(repo: UserRepository = Depends(get_user_repository)) -> UserService:
    return UserService(repository=repo)

# ─── 2. FASTAPI ROUTE CONSUMPTION (api/routes.py) ──────────────────────────
@router.post("/users", status_code=201)
def create_user(data: UserCreate, service: UserService = Depends(get_user_service)):
    return service.create_user(data)

# ─── 3. PYTEST OVERRIDE IN MOCK TEST (tests/test_users.py) ─────────────────
def get_mock_user_service() -> UserService:
    mock_repo = InMemoryUserRepository()
    return UserService(repository=mock_repo)

# Override real database service with mock during test execution
app.dependency_overrides[get_user_service] = get_mock_user_service

def test_create_user_fast_mock():
    client = TestClient(app)
    res = client.post("/users", json={"email": "test@test.com", "password": "pass"})
    assert res.status_code == 201

⭐ Rate Section 8: Dependency Injection & Testable Architecture (1 to 5 Stars)

Your rating is stored directly in the database. Average: 5.0 / 5 (1 rating)

★ ★ ★ ★ ★
← Section 7: Service Layer 🏠 Masterclass Hub Section 9: Type Hints →