Study/fastapi

depends() 함수를 정의하는 방법들

bluebamus 2025. 2. 19.

1. Pydantic 모델 사용

   - 가장 일반적인 방법은 Pydantic 모델을 사용하여 의존성을 정의하는 것이다. 이 방법은 데이터 유효성 검사와 함께 데이터 변환을 처리할 수 있어 매우 편리하다.

from fastapi import Depends
from pydantic import BaseModel

class User(BaseModel):
    username: str
    password: str

def get_current_user(user: User = Depends()):
    return user.username

# 사용 예제
@app.get("/users/me")
async def read_current_user(username: str = Depends(get_current_user)):
    return {"username": username}

 

2. 함수 사용 - yield를 사용한 의존성

   - 간단한 경우에는 함수를 직접 사용하여 의존성을 정의할 수 있습니다. 이 경우 함수의 반환값이 의존성으로 주입된다.

from fastapi import Depends

async def get_db():
    db = SomeDatabase()
    try:
        yield db
    finally:
        db.close()

# 사용 예제
@app.get("/items/")
async def read_items(db: Database = Depends(get_db)):
    return {"db_connection": db}

 

3. 직접 의존성 정의 -  일반적인 의존성 주입

   - 필요에 따라 직접 의존성을 정의할 수도 있다. 이 경우 Depends()를 직접 호출하여 의존성을 제공할 함수를 전달한다.

from fastapi import Depends

async def get_current_user(token: str = Depends(get_token)):
    user = await get_user_from_db(token)
    return user

# 사용 예제
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

 

4. Annotated 사용

   - 파라미터에 타입 어노테이션을 이용하여 의존성을 정의하는 방법이다.

from fastapi import Depends, FastAPI

app = FastAPI()

async def get_token():
    token = "exampletoken"
    return token

async def get_current_user(token: str = Depends(get_token)):
    user = await fetch_user_from_token(token)
    return user

@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

 

5. 기본적인 클래스 의존성 주입

   - 작동 방식

      - get_service() 함수가 실행되어 Service 클래스의 인스턴스를 반환한다.
      - Depends(get_service)를 통해 Service 인스턴스가 read_root 함수의 service 매개변수에 전달된다.
      - read_root 엔드포인트에서 service.get_value()를 호출하여 응답을 반환한다.

from fastapi import FastAPI, Depends

app = FastAPI()

# 의존성으로 사용할 클래스
class Service:
    def __init__(self):
        self.value = "Hello, FastAPI!"

    def get_value(self):
        return self.value

# Depends를 사용하여 클래스 인스턴스를 주입
async def get_service():
    return Service()

@app.get("/")
async def read_root(service: Service = Depends(get_service)):
    return {"message": service.get_value()}

 

6. 싱글톤 패턴 적용 (한 번만 생성하여 사용)

   - FastAPI는 기본적으로 요청이 들어올 때마다 새로운 의존성을 생성하지만, 싱글톤 패턴을 적용하면 애플리케이션이 실행되는 동안 하나의 인스턴스를 재사용할 수 있다.

 

   - 작동 방식

      - Service 인스턴스를 service_instance로 한 번만 생성하고 get_service()가 항상 같은 인스턴스를 반환하도록 한다.
      - 모든 요청이 같은 Service 객체를 공유하여 싱글톤 방식으로 동작한다.

from fastapi import FastAPI, Depends

app = FastAPI()

# 싱글톤 인스턴스 생성
class Service:
    def __init__(self):
        self.value = "Singleton Instance"

    def get_value(self):
        return self.value

service_instance = Service()  # 전역적으로 인스턴스를 한 번만 생성

async def get_service():
    return service_instance  # 항상 같은 인스턴스를 반환

@app.get("/")
async def read_root(service: Service = Depends(get_service)):
    return {"message": service.get_value()}

 

7. 싱글톤 패턴 적용 - __call__을 활용한 클래스 의존성

   - FastAPI에서는 클래스 자체를 Depends()로 사용할 수도 있다.
   - 이를 위해 __call__ 메서드를 정의하면 된다.

 

   - 작동 방식

      - Depends(Service)는 Service()를 호출하여 인스턴스를 생성하고 주입한다.

      - __call__이 정의되어 있기 때문에 Depends(Service)는 자동으로 Service의 인스턴스를 반환한다.
      - 이 방식은 __call__을 정의한 클래스가 자동으로 인스턴스를 반환하도록 만들기 때문에, 별도의 get_service() 함수를 만들 필요가 없다.

from fastapi import FastAPI, Depends

app = FastAPI()

class Service:
    def __init__(self):
        self.value = "Service with __call__"

    def __call__(self):
        return self  # 자기 자신을 반환

@app.get("/")
async def read_root(service: Service = Depends(Service)):
    return {"message": service.value}

 

8. 옵션을 사용한 의존성 선언

   - Depends()를 호출할 때 옵션을 추가하여 의존성을 선언할 수 있다. 예를 들어, 의존성의 이름을 지정하거나, 의존성을 캐싱하거나, 의존성의 범위를 제한하는 등의 설정을 추가할 수 있다.

from fastapi import Depends, FastAPI

app = FastAPI()

async def get_db():
    db = SomeDatabase()
    try:
        yield db
    finally:
        db.close()

@app.get("/items/")
async def read_items(db: Database = Depends(get_db, use_cache=True)):
    return {"db_connection": db}

 

9. 클래스 기반 의존성

   - 의존성을 클래스 기반으로 정의하여 사용할 수도 있다. 이 방법은 의존성을 더욱 구조화하고 재사용성을 높일 수 있다.

   - 일반적인 클래스를 의존성으로 주입하는 경우 __call__이나 __init__이 없어도 상관없다.

from fastapi import Depends, FastAPI

app = FastAPI()

class Database:
    def __init__(self):
        self.connection = None

    def connect(self):
        self.connection = "Connected"

    def disconnect(self):
        self.connection = None

    def __call__(self):
        if not self.connection:
            self.connect()
        return self

def get_db():
    db = Database()
    try:
        yield db
    finally:
        db.disconnect()

@app.get("/items/")
async def read_items(db: Database = Depends(get_db)):
    db_instance = db()
    return {"db_connection": db_instance.connection}

 

댓글