DependencyInjection 완벽 마스터
DependencyInjection의 핵심 개념과 실전 활용법
학습 항목
이미지 로딩 중...
FastAPI 디자인 패턴 완벽 가이드
FastAPI에서 자주 사용되는 디자인 패턴들을 실제 코드와 함께 알아봅니다. Repository, Dependency Injection, Factory 등 고급 개발자를 위한 실전 패턴을 다룹니다.
들어가며
이 글에서는 FastAPI 디자인 패턴 완벽 가이드에 대해 상세히 알아보겠습니다. 총 10가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- Repository_Pattern
- Dependency_Injection
- Service_Layer_Pattern
- Factory_Pattern
- DTO_Pattern
- Unit_of_Work_Pattern
- Middleware_Pattern
- Strategy_Pattern
- Observer_Pattern
- Builder_Pattern
1. Repository_Pattern
개요
데이터 액세스 로직을 비즈니스 로직과 분리하여 유지보수성을 높이는 패턴입니다.
코드 예제
from abc import ABC, abstractmethod
class UserRepository(ABC):
@abstractmethod
async def get_by_id(self, user_id: int):
pass
class SQLUserRepository(UserRepository):
async def get_by_id(self, user_id: int):
return {"id": user_id, "name": "John"}
설명
Repository 인터페이스를 정의하고 구체적인 구현체를 분리하여 데이터베이스 변경 시 비즈니스 로직 수정 없이 대응할 수 있습니다.
2. Dependency_Injection
개요
FastAPI의 Depends를 활용하여 의존성을 주입하고 코드 재사용성을 높입니다.
코드 예제
from fastapi import Depends, FastAPI
async def get_db():
db = Database()
try:
yield db
finally:
await db.close()
@app.get("/users/{user_id}")
async def get_user(user_id: int, db = Depends(get_db)):
return await db.fetch_user(user_id)
설명
Depends를 사용하여 데이터베이스 연결을 자동으로 주입하고 요청 후 정리 작업을 수행합니다.
3. Service_Layer_Pattern
개요
비즈니스 로직을 서비스 계층으로 분리하여 컨트롤러를 간결하게 유지합니다.
코드 예제
class UserService:
def __init__(self, repo: UserRepository):
self.repo = repo
async def get_user_with_posts(self, user_id: int):
user = await self.repo.get_by_id(user_id)
posts = await self.repo.get_user_posts(user_id)
return {**user, "posts": posts}
설명
복잡한 비즈니스 로직을 서비스 클래스로 캡슐화하여 라우터는 요청/응답 처리만 담당하게 합니다.
4. Factory_Pattern
개요
설정에 따라 다른 구현체를 반환하는 팩토리 패턴으로 유연성을 확보합니다.
코드 예제
def create_repository(db_type: str) -> UserRepository:
if db_type == "postgres":
return PostgresUserRepository()
elif db_type == "mongodb":
return MongoUserRepository()
return InMemoryUserRepository()
repo = create_repository(settings.DB_TYPE)
설명
환경 설정에 따라 적절한 Repository 구현체를 생성하여 다양한 데이터베이스를 지원합니다.
5. DTO_Pattern
개요
데이터 전송 객체를 사용하여 API 입출력을 명확하게 정의하고 검증합니다.
코드 예제
from pydantic import BaseModel, EmailStr
class UserCreateDTO(BaseModel):
email: EmailStr
password: str
name: str
class UserResponseDTO(BaseModel):
id: int
email: str
name: str
설명
Pydantic 모델을 활용하여 요청 데이터 검증과 응답 데이터 직렬화를 자동으로 처리합니다.
6. Unit_of_Work_Pattern
개요
여러 Repository 작업을 하나의 트랜잭션으로 묶어 데이터 일관성을 보장합니다.
코드 예제
class UnitOfWork:
async def __aenter__(self):
self.session = await create_session()
return self
async def __aexit__(self, *args):
await self.session.rollback()
async def commit(self):
await self.session.commit()
설명
Context manager로 트랜잭션을 관리하여 여러 작업이 모두 성공하거나 모두 실패하도록 보장합니다.
7. Middleware_Pattern
개요
요청/응답 처리 전후에 공통 로직을 실행하는 미들웨어 패턴입니다.
코드 예제
from starlette.middleware.base import BaseHTTPMiddleware
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
logger.info(f"Request: {request.method} {request.url}")
response = await call_next(request)
logger.info(f"Response: {response.status_code}")
return response
설명
모든 요청/응답에 대해 로깅, 인증, CORS 등의 공통 처리를 중복 없이 구현할 수 있습니다.
8. Strategy_Pattern
개요
알고리즘을 캡슐화하여 런타임에 동적으로 선택할 수 있게 합니다.
코드 예제
class PaymentStrategy(ABC):
@abstractmethod
async def process(self, amount: float): pass
class CreditCardPayment(PaymentStrategy):
async def process(self, amount: float):
return f"Charged ${amount} to credit card"
def get_payment(method: str) -> PaymentStrategy:
return CreditCardPayment() if method == "card" else PayPalPayment()
설명
결제 방식, 알림 채널 등 여러 구현 중 하나를 선택해야 할 때 전략 패턴으로 확장성을 확보합니다.
9. Observer_Pattern
개요
이벤트 발생 시 여러 핸들러에게 자동으로 알림을 전송하는 패턴입니다.
코드 예제
class EventBus:
def __init__(self):
self.listeners = {}
def subscribe(self, event: str, handler):
self.listeners.setdefault(event, []).append(handler)
async def publish(self, event: str, data):
for handler in self.listeners.get(event, []):
await handler(data)
설명
사용자 생성, 주문 완료 등의 이벤트 발생 시 이메일 발송, 알림 전송 등 여러 작업을 자동으로 트리거합니다.
10. Builder_Pattern
개요
복잡한 객체를 단계적으로 생성하는 빌더 패턴으로 가독성을 높입니다.
코드 예제
class QueryBuilder:
def __init__(self):
self.filters = []
def where(self, field: str, value):
self.filters.append(f"{field} = {value}")
return self
def build(self):
return " AND ".join(self.filters)
query = QueryBuilder().where("age", 25).where("city", "Seoul").build()
설명
메서드 체이닝으로 복잡한 쿼리나 설정 객체를 직관적으로 생성할 수 있습니다.
마치며
이번 글에서는 FastAPI 디자인 패턴 완벽 가이드에 대해 알아보았습니다. 총 10가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#Python #FastAPI #DesignPatterns #DependencyInjection #Repository