FastAPI 레이어드 아키텍처(Layered Architecture)

박병현·2025년 2월 9일

🔎 FastAPI 레이어드 아키텍처(Layered Architecture)란?

FastAPI로 웹 애플리케이션을 개발할 때, 코드의 유지보수성과 확장성을 높이기 위해 레이어드 아키텍처(Layered Architecture)를 적용하는 것이 일반적이다.
레이어드 아키텍처는 기능별로 계층을 분리하여 각 계층이 독립적으로 동작하도록 설계하는 방식으로,
이를 통해 코드의 결합도를 낮추고, 가독성과 재사용성을 높일 수 있다.

또한, FastAPI의 의존성 주입(Dependency Injection, DI) 기능을 활용하면 레이어 간의 결합도를 줄이고 테스트가 용이한 구조를 만들 수 있다.
이를 위해 의존성 주입을 관리하는 dependency.py를 추가하여 객체 생성을 통합적으로 관리하도록 한다.


1️⃣ 레이어드 아키텍처의 기본 개념

FastAPI에서 일반적으로 3계층 아키텍처로 나눈다.
폴더의 구성은 예시로 아래와같은 구조를 갖는다고 가정 후 설명하겠습니다.

📂 src/
 ├── 📂 book/            # Book 도메인 관련 코드
 │   ├── models.py       # (Entity Layer) 데이터베이스 모델 정의
 │   ├── repository.py   # (Persistence Layer) 데이터베이스와 직접 통신
 │   ├── service.py      # (Service Layer) 비즈니스 로직 처리
 ├── 📂 routers/         # (Presentation Layer) API 요청을 처리
 │   ├── book.py         # Book API 엔드포인트
 ├── 📂 dependencies/    # 의존성 주입을 관리
 │   ├── dependency.py   # DI 관련 메서드 정의
 ├── 📂 database/        # 데이터베이스 연결 및 세션 관리
 │   ├── database.py     # Async DB 세션 및 연결 관리
계층역할
Presentation Layer (routers/book.py)API 요청을 받아 Service Layer로 전달
Service Layer (src/book/service.py)비즈니스 로직을 처리하고 Repository Layer와 통신
Persistence Layer (src/book/repository.py)데이터베이스와 직접 연결되어 데이터를 저장 및 조회
Entity Layer (src/book/models.py)데이터베이스 테이블을 정의

각 계층은 독립적으로 동작하며, Service Layer는 Repository를 통해 데이터에 접근한다.
FastAPI의 Depends()dependency.py를 활용하여, 객체 생성을 통합 관리할 수 있도록 한다.
Session 관리를 위한 database.py를 추가하여, 라우터에서 직접 Session을 다루지 않도록 개선


2️⃣ FastAPI 레이어드 아키텍처 디렉터리 구조

FastAPI에서 레이어드 아키텍처를 적용한 디렉터리 구조는 다음과 같다.

fastapi_project/
│── webapp/
│   ├── app.py               # FastAPI 애플리케이션 생성
│   ├── routers/
│   │   ├── book.py          # API 라우터 (Presentation Layer)
│── src/
│   ├── book/
│   │   ├── models.py        # 데이터베이스 모델 (Entity Layer)
│   │   ├── repository.py    # Repository Layer
│   │   ├── service.py       # Service Layer
│── dependencies/
│   ├── dependency.py        # 의존성 관리 (Repository, Service)
│── database/
│   ├── database.py          # Async DB 세션 관리
│── db.py                    # 데이터베이스 설정
│── main.py                  # FastAPI 실행 파일

3️⃣ 레이어별 코드 구현 예제

1) Models Layer (데이터 모델 계층) - models.py

from sqlalchemy import Column, Integer, String
from src.database.base import Base

class Book(Base):
    __tablename__ = "books"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    author = Column(String, index=True)
    published_year = Column(Integer)

2) Repository Layer (데이터 접근 계층) - repository.py

from sqlalchemy.ext.asyncio import AsyncSession
from src.book.models import Book

class BookRepository:
    async def list_books(self, db: AsyncSession):
        result = await db.execute("SELECT * FROM books")
        return result.fetchall()

    async def create_book(self, db: AsyncSession, title: str, author: str, published_year: int):
        book = Book(title=title, author=author, published_year=published_year)
        db.add(book)
        await db.commit()
        await db.refresh(book)
        return book

3) Service Layer (비즈니스 로직 계층) - service.py

from src.book.repository import BookRepository
from src.book.dto import BookCreateDTO, BookResponseDTO
from sqlalchemy.ext.asyncio import AsyncSession

class BookService:
    def __init__(self, repository: BookRepository):
        self.repository = repository

    async def list_books(self, db: AsyncSession):
        books = await self.repository.list_books(db)
        return [BookResponseDTO.model_validate(book) for book in books]

    async def create_book(self, db: AsyncSession, book_data: BookCreateDTO):
        book = await self.repository.create_book(db, book_data.title, book_data.author, book_data.published_year)
        return BookResponseDTO.model_validate(book)

4) Dependency Management (의존성 관리) - dependency.py

from fastapi import Depends
from src.database.database import get_async_db
from src.book.repository import BookRepository
from src.book.service import BookService

def dependency_book_repository(db=Depends(get_async_db)) -> BookRepository:
    return BookRepository()

def dependency_book_service(
    repository: BookRepository = Depends(dependency_book_repository)
) -> BookService:
    return BookService(repository)

모든 의존성을 dependency.py에서 관리하여 객체 생성을 통합적으로 관리
라우터에서는 Service만 주입받고, Repository 및 DB 관련 객체를 직접 다루지 않도록 함


5) Async Database Management - database.py

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker

DATABASE_URL = "sqlite+aiosqlite:///./test.db"

engine = create_async_engine(DATABASE_URL, echo=True)
SessionLocal = async_sessionmaker(autocommit=False, autoflush=False, bind=engine, class_=AsyncSession)

async def get_async_db():
    async with SessionLocal() as session:
        yield session

AsyncSession을 사용하여 비동기 DB 관리
라우터에서는 직접 Session을 다루지 않고, dependency.py에서 관리


6) Presentation Layer (API 계층) - routers/book.py

from fastapi import APIRouter, Depends
from src.book.service import BookService
from src.book.dto import BookCreateDTO, BookResponseDTO
from typing import List
from dependencies.dependency import dependency_book_service

router = APIRouter(prefix="/books", tags=["Books"])

@router.get("/", response_model=List[BookResponseDTO])
async def list_books(
    book_service: BookService = Depends(dependency_book_service)
):
    return await book_service.list_books()

@router.post("/", response_model=BookResponseDTO)
async def create_book(
    book_data: BookCreateDTO, 
    book_service: BookService = Depends(dependency_book_service)
):
    return await book_service.create_book(book_data)

라우터에서는 Depends(dependency_book_service)를 활용하여 서비스만 주입받음
Repository 및 DB 관련 의존성은 dependency.py에서 관리하여 직접 참조하지 않도록 개선


4️⃣ 결론: FastAPI에서 레이어드 아키텍처를 적용해야 하는 이유

  1. 각 계층이 독립적으로 동작하여 유지보수성이 향상됨
  2. 비즈니스 로직과 데이터 접근 로직을 분리하여 가독성이 개선됨
  3. FastAPI의 Depends()를 활용하여 객체 생성을 자동으로 관리할 수 있음
  4. Async DB 관리(database.py 추가)로 인해 확장성이 뛰어남

FastAPI에서 레이어드 아키텍처 + Dependency Injection(DI) + Async DB 관리를 적용하면
보다 효율적이고 유지보수하기 쉬운 프로젝트를 개발할 수 있다.

profile
AI Application Engineer

0개의 댓글