Fastapi: [QUESTION] Depends not works for several layers

Created on 5 Oct 2020  路  5Comments  路  Source: tiangolo/fastapi

Good day! Please tell me how you can solve the following task 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

Run hypercorn: app.main:app --reload
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 level of handlers 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: How do I use Depends in this case and why doesn't it work?

I attach an archive with a test project
test.zip

question

Most helpful comment

@Kludex that's not correct - classes are callable, they return an instance when called.

@dmpyatin here's one way of fixing your issue:

class UserHandler1:
    def __init__(self, repo=Depends(get_repo)):
        self.repo = repo

    def get_all(self):
        return self.repo.get_all()

the reason this is required is because you are calling UserHandler1.get_all() directly, so the repo=Depends(get_repo) is never resolved.

All 5 comments

UserHandler1 is not a callable. You need to implement __call__ there. Depends expects a callable.

@Kludex that's not correct - classes are callable, they return an instance when called.

@dmpyatin here's one way of fixing your issue:

class UserHandler1:
    def __init__(self, repo=Depends(get_repo)):
        self.repo = repo

    def get_all(self):
        return self.repo.get_all()

the reason this is required is because you are calling UserHandler1.get_all() directly, so the repo=Depends(get_repo) is never resolved.

You're right. What I said doesn't make any sense. 馃馃憤

@Mause, Many thanks! Your example helped a lot

Feel free to close the issue if that solves it :)

Was this page helpful?
0 / 5 - 0 ratings