Python'da FastAPI ile Bağımlılık Enjeksiyon sorunu
İ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
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 .