Good day! Please tell me how you can solve the following problem in Python + FastAPI.
There is a test project:
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
The main and routes structure is the same as in the example https://fastapi.tiangolo.com/tutorial/bigger-applications/
In the routes/users.py file:
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()
In the handlers/factory.py:
from fastapi import Depends
from .users import UserHandler1
def get_handler(handler=Depends(UserHandler1)):
return handler
In the handlers/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
Then I run hypercorn server: app.main:app --reload
Try call api method: http://127.0.0.1:8000/users/
And get the error AttributeError: 'Depends' object has no attribute 'get_all'
If you remove the handlers layer and do this, then everything will work.
routes/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.
Question 1: How do I use "Depends" in this case and why doesn't it work?
In general, the factory does not look like a good solution to this problem. I saw an example of DI implementation using multiple inheritance but as for me it is the same as factory method. I also tried to use the Pinject library, but it requires the initial construction of a graph, which needs to be saved somewhere in order to access it in api handlers.
Question 2 (more important): How DI can be applied in this case ?
Your error is you need to apply dependendency injection in callable object's constructor. So the correct UserHandler1 should be this:
RépondreSupprimerclass UserHandler1:
def __init__(self, name= '', repo=Depends(get_repo)):
self.name = name
self.repo = repo
def get_all(self, ):
return self.repo.get_all()
and it is working