의존성 주입(DI, Dependency Injection)은 객체가 직접 다른 객체를 생성하지 않고, 외부에서 생성된 객체를 주입받아 사용하는 개념이다.
이를 통해 코드의 결합도를 낮추고, 테스트 용이성을 높이며, 유지보수를 쉽게 할 수 있다.
또한, FastAPI와 같은 프레임워크에서는 레이어드 아키텍처(Layered Architecture)와 함께 사용하면 더욱 효과적으로 관리할 수 있다.
추가로, FastAPI는 내장된 DI 시스템(Depends)을 제공하여, 객체 간의 의존성을 쉽게 관리할 수 있다.
FastAPI에서 레이어드 아키텍처(Layered Architecture)는 코드의 유지보수성, 확장성 및 테스트 용이성을 높이는 중요한 구조이다.
레이어드 아키텍처는 일반적으로 3계층 구조를 사용하며, 각 계층의 역할을 분리한다. 이를 통해 코드의 명확한 책임 분담과 독립성을 보장한다.
| 계층 | 역할 |
|---|---|
Presentation Layer (routers/book.py) | 클라이언트 요청을 받아 Service Layer로 전달 |
Service Layer (src/book/service.py) | 비즈니스 로직을 처리하고 Repository Layer와 통신 |
Persistence Layer (src/book/repository.py) | 데이터베이스와 직접 연결하여 데이터 저장 및 조회 |
이 아키텍처에서 의존성 주입(DI)은 중요한 역할을 한다. DI를 사용하면 각 계층 간의 의존성을 외부에서 관리할 수 있기 때문에 계층 간 결합도를 낮추고 각 계층을 독립적으로 테스트하고 유지보수할 수 있다.
다음은 FastAPI의 레이어드 아키텍처에서 의존성 주입(DI)이 이루어지는 흐름을 시각적으로 표현한 Mermaid 다이어그램입니다.

Presentation Layer (라우터): 클라이언트 요청을 받아 Depends(BookService)를 통해 Service Layer에 요청을 전달한다.Service Layer: 비즈니스 로직을 처리하며, Depends(BookRepository)를 사용하여 Repository Layer에 데이터 요청을 보낸다.Repository Layer: 실제 데이터베이스와 연결하여 데이터를 저장 및 조회하며, 주입받은 DB 세션(Session)을 활용한다.💡 위 다이어그램을 기반으로, 의존성 주입이 어떻게 이루어져야 하는지, 한눈에 쉽게 파악할 수 있다!
의존성 주입은 Service Layer와 Repository Layer 간의 의존성을 관리하는 중요한 도구가 된다.
예를 들어, Service Layer는 Repository Layer를 직접 생성하지 않고 외부에서 주입받아 사용한다. 이는 각 계층의 독립성을 높이고, 테스트 시 Mock 객체를 사용하기 용이하게 만든다.
의존성이란 하나의 객체가 다른 객체를 필요로 하는 관계를 의미한다.
예를 들어, 서비스(Service)가 리포지토리(Repository)에 의존한다고 가정해보자.
from sqlalchemy.orm import Session
from src.book.models import Book
class BookRepository:
def __init__(self):
self.db = Session() # ❌ 여기서 직접 Session 객체를 생성 (잘못된 예시)
def list_books(self):
return self.db.query(Book).all()
❌ 문제점
1. BookRepository가 데이터베이스 세션(Session)에 직접 의존하고 있음 (self.db = Session())
Session의 구현이 변경되면, BookRepository도 함께 수정해야 한다. AsyncSession)으로 바꾸려면 BookRepository를 전면 수정해야 한다. BookRepository를 테스트할 때, 항상 실제 데이터베이스가 필요하다. Session이 네트워크를 사용하거나 실제 데이터베이스를 필요로 하면, 빠른 단위 테스트(Unit Test)를 수행하기 어려워진다. 의존성 주입을 사용하면 BookRepository가 직접 Session을 생성하지 않고, 외부에서 주입받도록 개선할 수 있다.
from sqlalchemy.orm import Session
from src.book.models import Book
class BookRepository:
def __init__(self, db: Session): # ✅ Session을 외부에서 주입받음
self.db = db
def list_books(self):
return self.db.query(Book).all()
✅ Repository는 더 이상 Session을 직접 생성하지 않음
✅ db: Session을 외부에서 주입받아 관리
✅ Session이 변경되더라도 BookRepository를 수정할 필요 없음
💡 즉, BookRepository가 Session에 직접 의존하지 않고, 외부에서 주입받아 사용하도록 개선되었다.
Depends()를 활용한 DI 적용FastAPI에서는 Depends()를 활용하여 의존성을 자동으로 주입할 수 있다.
이를 통해 객체 생성을 직접 관리하지 않아도 되고, 유지보수가 쉬워진다.
Depends()를 활용한 DI 적용 예시from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
class Database:
def query(self):
return "데이터 조회 완료"
class BookRepository:
def __init__(self, db: Database):
self.db = db
def list_books(self):
return self.db.query()
def get_database() -> Database:
return Database()
def get_repository(db: Database = Depends(get_database)) -> BookRepository:
return BookRepository(db)
app = FastAPI()
@app.get("/")
def read_root(repository: BookRepository = Depends(get_repository)):
return {"data": repository.list_books()}
✅ Depends(get_repository)를 사용하여 Repository 객체를 자동으로 주입
✅ Depends(get_database)를 사용하여 Database 객체를 자동으로 주입
✅ FastAPI가 의존성을 자동으로 관리하여 코드의 유지보수성을 높임
💡 즉, FastAPI의 Depends()를 활용하면 객체 생성을 직접 관리하지 않아도 되고, 테스트 시에도 유연하게 Mock 객체를 주입할 수 있다.
from fastapi import APIRouter, Depends
from src.book.service import BookService
from dependencies.dependency import dependency_book_service
router = APIRouter(prefix="/books", tags=["Books"])
@router.get("/")
async def list_books(book_service: BookService = Depends(dependency_book_service)):
return await book_service.list_books()
✅ 라우터에서는 Depends(dependency_book_service)를 활용하여 서비스만 주입받음
✅ Service는 Repository를, Repository는 Database를 주입받아 레이어 간 결합도를 낮춤
✅ FastAPI가 의존성을 관리하므로, 객체 생성 및 관리를 직접 할 필요가 없음
| 기존 방식 | DI 방식 |
|---|---|
| 객체가 직접 다른 객체를 생성 | 객체가 외부에서 제공받음 |
| 코드가 강하게 결합됨 | 코드의 결합도가 낮아짐 (유지보수 쉬움) |
| 테스트하기 어려움 | 가짜(Mock) 객체를 쉽게 주입 가능 |
✅ DI를 사용하면 코드가 더 유연해지고, 유지보수가 쉬워지며, 테스트가 용이해진다. 🚀
Python 및 FastAPI를 활용하는 프로젝트에서 DI를 적극적으로 활용하면 더 효율적이고 유지보수하기 쉬운 코드를 작성할 수 있다.