|

FastAPI Depends 사용 기준

FastAPI Depends 글 대표 이미지
FastAPI Depends 사용 기준을 정리합니다. 인증, DB 세션, 서비스 객체, 테스트 대체 기준을 나누고 Depends 남용을 피하는 구조와 실무 예제, 테스트하기 쉬운 분리 기준과 흔한 실수까지 설명합니다.

FastAPI Depends는 FastAPI를 쓰면 거의 바로 만나게 되는 기능입니다. 인증 사용자, DB 세션, 설정 객체, pagination 조건처럼 요청 처리에 필요한 값을 깔끔하게 주입할 수 있습니다.

문제는 어디까지 Depends로 빼야 하는지입니다. Depends는 요청 주변의 의존성을 조립하는 도구이지, 모든 비즈니스 로직을 숨기는 장소가 아닙니다라는 기준을 잡으면 구조가 단순해집니다.

FastAPI Depends 사용 기준 요약 카드
FastAPI Depends는 요청 단위 의존성을 조립하는 데 좋지만 비즈니스 로직을 숨기는 도구는 아닙니다.

FastAPI Depends가 잘 맞는 일

Depends는 요청을 처리하기 전에 필요한 값을 만들어 path operation 함수에 넘겨줍니다. 같은 인증 확인, DB 세션 생성, 공통 query parameter 처리처럼 여러 API에서 반복되는 준비 작업에 잘 맞습니다.

이런 코드를 path operation 안에 직접 쓰면 endpoint가 금방 길어집니다. 반대로 Depends로 빼면 endpoint는 요청을 받고 서비스 함수를 호출하는 흐름에 집중할 수 있습니다.

  • 현재 로그인 사용자 가져오기
  • 요청 단위 DB session 열고 닫기
  • 공통 pagination parameter 파싱
  • 권한 확인을 위한 작은 policy check
  • 테스트에서 바꿔 끼울 외부 client 준비

DB session은 왜 Depends와 잘 맞을까

DB session은 요청 단위 생명주기를 갖는 경우가 많습니다. 요청이 시작될 때 만들고, 처리가 끝나면 닫아야 합니다. FastAPI의 dependency with yield 패턴은 이런 자원 정리에 잘 어울립니다.

from typing import Annotated
from fastapi import Depends
from sqlmodel import Session

def get_session():
    with Session(engine) as session:
        yield session

SessionDep = Annotated[Session, Depends(get_session)]

@app.get("/items/{item_id}")
def read_item(item_id: int, session: SessionDep):
    return item_service.get_item(session, item_id)

인증도 Depends로 분리하기 좋다

현재 사용자를 확인하는 로직도 Depends와 잘 맞습니다. token을 읽고, 검증하고, 사용자 객체를 가져오는 과정은 여러 endpoint에서 반복됩니다.

다만 인증 dependency 안에서 주문 생성, 게시글 수정 같은 도메인 로직까지 처리하면 안 됩니다. 인증 dependency는 현재 사용자가 누구인지와 최소 권한 조건까지만 책임지는 편이 좋습니다.

서비스 객체까지 Depends로 넣어도 될까

서비스 객체를 Depends로 주입하는 방식은 가능합니다. 특히 외부 API client나 repository를 테스트에서 바꿔야 한다면 dependency override가 유용합니다.

하지만 모든 service method 호출을 Depends 함수 안에 숨기면 endpoint가 실제로 무엇을 하는지 보이지 않습니다. Depends는 객체를 준비하고, 실제 유스케이스 실행은 endpoint나 application service에서 명시적으로 호출하는 편이 읽기 쉽습니다.

def get_current_user(token: TokenDep, session: SessionDep) -> User:
    return auth_service.authenticate(session, token)

@app.post("/orders")
def create_order(
    request: CreateOrderRequest,
    user: Annotated[User, Depends(get_current_user)],
    session: SessionDep,
):
    return order_service.create(session, user.id, request)

테스트 기준으로 구조를 점검하기

Depends 구조가 괜찮은지 확인하는 좋은 방법은 테스트에서 바꿔 끼우기 쉬운지 보는 것입니다. 외부 인증 서버, 결제 client, DB session을 테스트용으로 대체할 수 있다면 구조가 비교적 잘 나뉜 것입니다.

FastAPI는 app.dependency_overrides를 통해 특정 dependency를 테스트용 함수로 바꿀 수 있습니다. 이 기능은 인증 우회, fake repository, test session을 만들 때 유용합니다.

Depends 남용 신호

  • endpoint에 실제 유스케이스가 거의 보이지 않는다
  • Depends 함수 이름만 봐서는 DB write가 일어나는지 알 수 없다
  • dependency끼리 서로 깊게 물고 있어 호출 순서를 추적하기 어렵다
  • 테스트에서 override해야 할 대상이 너무 많다
  • 비즈니스 예외가 dependency 내부에서 조용히 처리된다

실무 추천 기준

  1. 요청 단위 준비 작업은 Depends로 뺀다
  2. 도메인 로직 실행은 명시적인 service 호출로 둔다
  3. DB session, current user, settings는 타입 alias로 반복을 줄인다
  4. 외부 client는 테스트 override가 필요할 때 dependency로 둔다
  5. dependency 내부에서 write 작업을 숨기지 않는다

정리

FastAPI Depends는 요청 처리에 필요한 의존성을 조립하는 데 강합니다. 인증, DB session, 설정, 외부 client처럼 반복되고 교체 가능한 준비 작업에 잘 맞습니다. 하지만 비즈니스 로직 전체를 Depends 안에 숨기면 endpoint의 의도가 흐려지고 테스트도 어려워집니다.

관련 글은 FastAPI JWT 인증은 어디서 나눠야 할까, 파이썬 map과 filter, list comprehension 차이, OAuth2 JWT를 따로 만드는 이유를 함께 보면 좋습니다. 외부 기준은 FastAPI docs – Dependencies, FastAPI docs – Testing dependencies, FastAPI docs – SQL databases를 확인했습니다.

함께보면 좋은 글