Python'da FastAPI ile Bağımlılık Enjeksiyon sorunu

Oct 05 2020

İyi günler! Lütfen aşağıdaki sorunu Python + FastAPI'de nasıl çözebileceğinizi söyleyin.

Bir test projesi var:

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

Ana ve güzergah yapısı örnekteki ile aynıdır https://fastapi.tiangolo.com/tutorial/bigger-applications/

In yolları / users.py dosyası :

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 işleyicileri / factory.py :

from fastapi import Depends
from .users import UserHandler1

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

In işleyicileri / 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

Sonra hiperkorn sunucusunu çalıştırıyorum: app.main:app --reloadapi yöntemini çağırmayı deneyin: http://127.0.0.1:8000/users/Ve AttributeError hatasını al:'Depends' object has no attribute 'get_all'

İşleyiciler katmanını kaldırırsanız ve bunu yaparsanız, her şey çalışacaktır.

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.

Soru 1: Bu durumda "Bağımlı" yı nasıl kullanırım ve neden çalışmaz?

Genel olarak fabrika bu soruna iyi bir çözüm gibi görünmüyor. Çoklu miras kullanan bir DI uygulaması örneği gördüm, ancak bana gelince bu fabrika yöntemiyle aynı. Pinject kitaplığını da kullanmayı denedim, ancak api işleyicilerinde ona erişmek için bir yere kaydedilmesi gereken bir grafiğin ilk yapımını gerektiriyor.

Soru 2 (daha önemli): Bu durumda Bağımlılık Enjeksiyonu nasıl uygulanabilir?

Yanıtlar

1 lsabi Oct 05 2020 at 12:37

Yorumlarda belirtildiği gibi, bağımlılık çağrılabilir herhangi bir şey ve dolayısıyla bir sınıf da olabilir. İkinci durumda tek uyarı, sınıfın yalnızca başlatılacağıdır (yani, yalnızca init (..) işlevi çağrılacaktır).

Yani, örnekte olduğu gibi bağımlılık olarak bir sınıfa sahip olmak için https://fastapi.tiangolo.com/tutorial/dependencies/classes-as-dependencies/#shortcutinit içindeki hedef işlevleri çağırmanız ve değerleri sınıfın öznitelikleri olarak ayarlamanız yeterlidir .

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

SORU 2

NB

Bu bir modelleme sorusudur. Burada, benim bakış açıma göre uygun olduğuna inandığım şeyi öneriyorum . En iyi veya en basit yaklaşım olmak zorunda değildir.

İkinci sorunuza cevap verirken, bu tür karmaşık bağımlılıklar için tavsiyede bulunmam. Bağımlılıklar yönlendirici düzeyinde ise, parametreyi kullanarak depends=[...]ve bağımlılık sınıflarının / işlevlerinin bir listesini sağlayarak onları basitçe yönlendiriciye ekleyebilirsiniz .

Alternatif olarak, tüm bağımlılıkları fabrikada yaptığınız gibi uç noktanın fonksiyon parametreleri olarak tanımlayabilirsiniz. Bu yöntem, büyük kod parçalarının kopyalanıp yapıştırılmasına yol açabilir, bu nedenle yukarıdaki yaklaşımı tavsiye ederim.

Veri parametrelerini işlemeniz gerekiyorsa, bunları isteğe eklersiniz ve bunlara uç noktadan erişirsiniz. Minimal bir örnek için FastAPI'nin API anahtarından kullanıcı kimliği alma bölümüne bakın .