Python에서 FastAPI의 종속성 주입 문제
좋은 날! 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 (더 중요) : 이 경우 종속성 주입을 어떻게 적용 할 수 있습니까?
답변
주석에서 언급했듯이 종속성은 호출 가능한 모든 것이 될 수 있으므로 클래스도 될 수 있습니다. 후자의 경우 유일한주의 사항은 클래스가 초기화 만된다는 것입니다 (즉, 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 가져 오기를 참조하십시오 .