Python에서 FastAPI의 종속성 주입 문제

Oct 05 2020

좋은 날! Python + FastAPI에서 다음 문제를 어떻게 해결할 수 있는지 알려주세요.

테스트 프로젝트가 있습니다.

app / main.py - main file
app / routes / users.py -set of api methods
app / repos / factory.py - repository factory
app / repos / user_repository.py - repositories
app / handlers / factory.py - handler factory
app / handlers / users.py - handlers
app / domain / user.py - data class

주 및 경로 구조는 예제와 동일합니다. https://fastapi.tiangolo.com/tutorial/bigger-applications/

에서 경로 / users.py 파일 :

from fastapi import APIRouter, Depends
from ..handlers import factory

router = APIRouter()

@router.get("/users/", tags=["users"])
def read_users(handler=Depends(factory.get_handler)):
    return handler.get_all()

에서 핸들러 / factory.py :

from fastapi import Depends
from .users import UserHandler1

def get_handler(handler=Depends(UserHandler1)):
    return handler

에서 핸들러 / users.py :

from fastapi import Depends
from ..repos import factory

class UserHandler1:
    def __init__(self):
        pass

    def get_all(self, repo=Depends(factory.get_repo)):
        return repo.get_all()

repos / factory.py :

from fastapi import Depends
from ..repos.user_repository import UserRepository

def get_repo(repo=Depends(UserRepository)):
    return repo

repos / user_repository.py :

from ..domain.user import User

class UserRepository:
    def __init__(self):
        pass

    def get_all(self):
        return [User(1, 'A'), User(2, 'B'), User(3, 'C')]

domain / user.py :

class User:
    id: int
    name: str

    def __init__(self, id, name):
        self.id = id
        self.name = name

그런 다음 하이퍼 콘 서버를 실행합니다. app.main:app --reloadapi 메서드 호출 시도 : http://127.0.0.1:8000/users/그리고 AttributeError 오류가 발생합니다.'Depends' object has no attribute 'get_all'

핸들러 레이어를 제거하고 이렇게하면 모든 것이 작동합니다.

route / users.py :

from fastapi import APIRouter, Depends
from ..repos import factory

router = APIRouter()

@router.get("/users/", tags=["users"])
def read_users(repo=Depends(factory.get_repo)):
    return repo.get_all()
It also works if you completely remove all Depends and create
UserRepository and UserHandler1 directly in factories.

질문 1 : 이 경우 "Depends"를 어떻게 사용하고 왜 작동하지 않습니까?

일반적으로 공장은이 문제에 대한 좋은 해결책으로 보이지 않습니다. 다중 상속을 사용하는 DI 구현의 예를 보았지만 저에게는 팩토리 방법과 동일합니다. 또한 Pinject 라이브러리를 사용하려고 시도했지만 그래프의 초기 구성이 필요하며 API 핸들러에서 액세스하려면 어딘가에 저장해야합니다.

질문 2 (더 중요) : 이 경우 종속성 주입을 어떻게 적용 할 수 있습니까?

답변

1 lsabi Oct 05 2020 at 12:37

주석에서 언급했듯이 종속성은 호출 가능한 모든 것이 될 수 있으므로 클래스도 될 수 있습니다. 후자의 경우 유일한주의 사항은 클래스가 초기화 만된다는 것입니다 (즉, init (..) 함수 만 호출 됨).

따라서 클래스를 종속성으로 사용하려면 https://fastapi.tiangolo.com/tutorial/dependencies/classes-as-dependencies/#shortcutinit 내에서 대상 함수를 호출 하고 값을 클래스의 속성으로 설정 하기 만하면 됩니다.

from ..domain.user import User

class UserRepository:
    def __init__(self):
        self.get_all()

    def get_all(self):
        self.users = [User(1, 'A'), User(2, 'B'), User(3, 'C')]


from fastapi import Depends
from ..repos.user_repository import UserRepository

def get_repo(repo=Depends(UserRepository)):
    print(repo.users) # This will print the list of users
    return repo

질문 2

NB

이것은 모델링 질문입니다. 여기서 나는 내 관점 에서 내가 적합하다고 생각하는 것을 제안한다 . 반드시 최선의 방법이거나 가장 간단한 방법 일 필요는 없습니다.

두 번째 질문에 대한 대답은 이러한 복잡한 종속성에 대한 조언이 아닙니다. 종속성이 라우터 수준에있는 경우 매개 변수를 사용하고 depends=[...]종속성 클래스 / 기능 목록을 제공 하여 라우터에 간단히 추가 할 수 있습니다 .

또는 팩토리에서했던 것처럼 모든 종속성을 엔드 포인트의 함수 매개 변수로 선언 할 수 있습니다. 이 방법은 많은 양의 코드를 복사하여 붙여 넣을 수 있으므로 위의 방법을 권장합니다.

데이터 매개 변수를 처리해야하는 경우 요청에 추가하고 엔드 포인트 내에서 액세스합니다. 최소한의 예제는 FastAPI API 키에서 사용자 ID 가져 오기를 참조하십시오 .