Skip to content

30. Dependencies with yield


1. Dependencies with yield

  • FastAPI는 함수의 종료 후 몇 가지 추가 단계를 수행하는 dependencies를 지원한다.
  • 이를 위해서는 return 대신 yield를 사용하고 이후에 추가 단계를 작성한다.


Note

  • yield는 한 번만 사용하는 게 좋다.


2. A database dependency with yield

  • 다음의 예제는 yield를 사용하여 데이터베이스 세션을 만들고, 종료한 후 닫을 수 있는 예제이다.


  • 다음과 같이 작성하면, response를 보내기 전 yield 문까지 실행된다.


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


  • 다음과 같이 yield된 값은 path operations 및 다른 dependencies에 주입되는 값이다.


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


  • yield 문 다음의 코드는 response가 전달된 후 실행된다.


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


3. A dependency with yield and try

  • yield가 있는 dependency에서 try 블록을 사용하는 경우 dependency를 사용할 때 throw된 모든 예외를 수신한다.
  • 예를 들어, 다른 dependency 또는 path operation에 있는 일부 코드가 데이터베이스 트랜잭션 "rollback"을 하거나 다른 에러를 생성하는 경우 dependency에서 예외를 수신한다.
  • 따라서 except SomeException으로 dependency 내부에서 특정 예외를 찾을 수 있다.


  • 또한 다음과 같이 finally 블록을 사용하여 예외가 있는지 여부에 관계없이 닫을 수 있다.


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


4. Sub-dependencies with yield

  • 어떠한 sub-dependencies 내부에서도 yield를 사용할 수 있다.


  • 다음의 예제는 sub-dependencies 내부에서 yield를 사용하는 예제이다.


from fastapi import Depends

async def dependency_a():
    dep_a = generate_dep_a()
    try:
        yield dep_a
    finally:
        dep_a.close()

async def dependency_b(dep_a=Depends(dependency_a)):
    dep_b = generate_dep_b()
    try:
        yield dep_b
    finally:
        dep_b.close(dep_a)

async def dependency_c(dep_b=Depends(dependency_b)):
    dep_c = generate_dep_c()
    try:
        yield dep_c
    finally:
        dep_c.close(dep_b)


  • 위의 예제의 경우, dependency_c는 종료 코드를 실행하려면 dependency_b의 값이 필요하다.
  • 그리고 차례대로, dependency_b는 종료 코드를 실행하려면 dependency_a의 값이 필요하다.


from fastapi import Depends

async def dependency_a():
    dep_a = generate_dep_a()
    try:
        yield dep_a
    finally:
        dep_a.close()

async def dependency_b(dep_a=Depends(dependency_a)):
    dep_b = generate_dep_b()
    try:
        yield dep_b
    finally:
        dep_b.close(dep_a)

async def dependency_c(dep_b=Depends(dependency_b)):
    dep_c = generate_dep_c()
    try:
        yield dep_c
    finally:
        dep_c.close(dep_b)


Note

  • yield뿐만 아니라 return 또한 같이 사용될 수 있다.


5. Context Managers

1) What are "Context Managers"

  • "Context Managers"란, with 문에서 사용할 수 있는 Python 객체이다.


  • 예를 들어, 다음과 같이 파일을 읽는 데 사용하는 것이다.


with open("./somefile.txt") as f:
    contents = f.read()
    print(contents)


  • 위의 예제에서 open("./somefile.txt")는 "Context Manager"라는 객체를 생성한다.
  • with 블록이 종료되면 예외가 있더라도 파일을 닫게 된다.
  • yield를 사용하여 dependency를 생성하면, FastAPI가 내부적으로 이를 context manager로 변환하고 다른 관련 도구와 결합한다.


2) Using context managers in dependencies with yield

  • Python에서는 클래스 내부에 __enter__()__exit__()이라는 두 가지 메서드를 사용하여 context manager를 만들 수 있다.


  • 다음과 같이 dependency 함수 내에서 yield와 함께 with 또는 async with를 사용할 수 있다.


class MySuperContextManager:
    def __init__(self):
        self.db = DBSession()

    def __enter__(self):
        return self.db

    def __exit__(self, exc_type, exc_value, traceback):
        self.db.close()

async def get_db():
    with MySuperContextManager() as db:
        yield db

References