FastAPI 의존성 주입(DI) 마스터 시리즈 (2부)
안녕하세요! 지난 1부에서는 우리가 API를 개발하며 겪는 문제점들과, 이를 해결하기 위한 의존성 주입(DI) 의 개념에 대해 알아보았습니다.
이번 2부에서는 FastAPI가 제공하는 강력한 도구인 Depends를 사용하여 직접 코드를 작성해 보겠습니다.
가장 기초적인 매개변수 주입부터 시작해서, 실무에서 필수적인 DB 세션 관리(yield)와 보안 인증까지 단계별로 정복해 봅시다!
1. 기초: Depends로 공통 매개변수 중복 없애기
API를 만들다 보면 페이징(Paging)이나 검색 기능처럼 여러 엔드포인트에서 똑같은 쿼리 매개변수를 받아야 할 때가 많습니다.
1.1. 기존 방식의 문제점
DI를 쓰지 않으면 모든 함수마다 똑같은 코드를 복사해야 합니다.
@app.get("/items/")
def read_items(q: str | None = None, skip: int = 0, limit: int = 100):
...
@app.get("/users/")
def read_users(q: str | None = None, skip: int = 0, limit: int = 100):
...
매개변수 조건이 바뀌면 모든 함수를 찾아가서 고쳐야 하죠.
1.2. Depends를 사용한 해결책
이 공통 로직을 별도의 의존성 함수로 분리하고, Depends로 주입받아 봅시다.
from fastapi import Depends, FastAPI
from typing import Annotated
app = FastAPI()
# 1. 의존성 함수 정의 (공통 로직 분리)
def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
# 2. 경로 함수에 주입
@app.get("/items/")
def read_items(commons: Annotated[dict, Depends(common_parameters)]):
# commons에는 {"q":..., "skip":..., "limit":...} 딕셔너리가 들어옵니다.
return commons
@app.get("/users/")
def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
작동 원리:
- 요청이 들어오면 FastAPI는 먼저
common_parameters함수를 실행합니다. - 쿼리 파라미터(
?skip=10&limit=5)를 처리하여 결과를 만듭니다. - 그 결과를
read_items함수의commons변수에 주입해 줍니다.
2. 심화: yield를 활용한 리소스 생애주기 관리 (Setup/Teardown)
기초를 익혔으니 이제 진짜 실무 영역입니다. 데이터베이스 연결(Session)이나 파일 열기와 같은 리소스는 사용 후 반드시 닫아주는(Close) 과정이 필요합니다.
FastAPI는 파이썬의 yield 키워드를 사용하여 이 복잡한 과정을 아주 우아하게 처리합니다.
2.1. yield 의존성의 흐름
yield를 사용하면 의존성 함수를 요청 전(Setup) 과 요청 후(Teardown) 두 부분으로 나눌 수 있습니다.
# database.py
from sqlalchemy.orm import Session
# DB 세션 생성 함수 (가정)
SessionLocal = ...
def get_db():
db = SessionLocal() # 1. Setup: DB 연결 생성
try:
yield db # 2. Inject: 연결된 db 객체를 경로 함수에 전달하고 대기
finally:
db.close() # 3. Teardown: 요청 처리가 끝나면 반드시 실행되어 연결 종료
2.2. 실제 적용 예시
# main.py
from fastapi import Depends
from sqlalchemy.orm import Session
from .database import get_db
@app.post("/users/")
def create_user(user_name: str, db: Annotated[Session, Depends(get_db)]):
# db 객체 사용 (이미 연결된 상태)
# fake_save_user(db, user_name)
return {"message": "User created"}
# 함수가 종료되면 get_db의 finally 블록이 실행되어 db.close()가 자동으로 호출됩니다.
개발자는 이제 "DB 연결을 닫았나?" 걱정할 필요 없이, 비즈니스 로직에만 집중하면 됩니다.
3. 활용: 중복 없는 보안 인증 시스템 구현
모든 API 요청마다 토큰을 검사해야 한다면? 이 또한 Depends의 완벽한 사용처입니다.
3.1. 인증 의존성 만들기
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
user = fake_decode_token(token) # 토큰 해독 로직
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user
3.2. 보안 적용하기
@app.get("/users/me")
def read_users_me(current_user: Annotated[User, Depends(get_current_user)]):
# 이 함수는 토큰 검증이 통과된 경우에만 실행됩니다.
return current_user
단 한 줄의 코드로 토큰 추출 -> 검증 -> 에러 처리 -> 사용자 정보 조회의 모든 과정을 재사용할 수 있게 되었습니다.
2부를 마치며
이번 포스팅에서는 Depends의 가장 기초적인 사용법부터, yield를 이용한 리소스 관리, 그리고 보안 시스템 구현까지 실제 코드를 중심으로 살펴보았습니다.
이제 여러분의 FastAPI 프로젝트는 중복 코드가 사라지고 구조적으로 훨씬 탄탄해졌을 것입니다.
하지만 의존성 주입의 장점은 여기서 끝이 아닙니다. 다음 [3부: 테스트와 확장] 편에서는 이렇게 분리한 의존성을 활용해 DB 없이도 테스트하는 방법(Override)에 대해 다뤄보겠습니다. 기대해 주세요!
https://ye-seul0-0.tistory.com/15
[FastAPI - DI 마스터 3부] 의존성 오버라이드(Override)와 고급 패턴
FastAPI 의존성 주입(DI) 마스터 시리즈 (3부 / 완결)안녕하세요! FastAPI DI 시리즈의 마지막 편입니다.. 생각 없이 쓰던걸 정리해보니 새롭고, 더 효율적인 코드를 짤 수 있겠다는 생각이 듭니다. 지난
ye-seul0-0.tistory.com
'ServerDev > FastAPI' 카테고리의 다른 글
| [FastAPI - CORS 마스터 2부] 쿠키 인증(Credential) 이슈 해결과 보안을 위한 정교한 허용 전략 (0) | 2025.12.11 |
|---|---|
| FastAPI - CORS 마스터 1부] 프론트엔드 연동 첫걸음, CORS 에러 (0) | 2025.12.10 |
| [FastAPI] 웹 프레임워크가 아니라 'AI 모델 서빙기'로 사용하기 (feat. Spring Boot) (0) | 2025.12.09 |
| [FastAPI - DI 마스터 3부] 의존성 오버라이드(Override)와 고급 패턴 (0) | 2025.12.09 |
| [FastAPI - DI 마스터 01부] 복잡성 증가를 해결하는 의존성 주입(DI) 개념과 필요성 (0) | 2025.12.04 |