前言
依赖注入(DI)是一种编程技术,用于增强代码的可重用性,并促进类与其依赖项之间的解耦。在FastAPI 的上下文中,依赖注入在优化应用程序的灵活性、可测试性和整体架构方面发挥着关键作用。
在 FastAPI 中实现依赖注入
FastAPI 提供了 Depends
函数来声明依赖项。让我们来看一些常用的用例。
基本依赖注入
一个简单的依赖注入示例是注入一个返回消息的函数
import uvicorn
from fastapi import FastAPI, Depends
from starlette.responses import JSONResponse
app = FastAPI()
def get_message():
return "Hello from Dependency!"
@app.get("/message")
def read_message(message: str = Depends(get_message)):
return JSONResponse({"message": message})
if __name__ == '__main__':
uvicorn.run(app="main:app", port=8000)
在这个例子中:
get_message()
是一个依赖项。Depends(get_message)
:将其返回值注入到read_message
函数中
FastAPI 中的依赖注入方法
- 在 FastAPI 中 使用
Depends
函数 - 在 FastAPI 中处理子依赖项
FastAPI 中 的 Depends 函数
在 FastAPI 中, Depends
函数用于管理依赖注入,作为其他函数的通用参数。这使得 FastAPI 能够有序地处理依赖项,便于在应用程序的不同部分管理和注入所需的组件。
语法:
@app.get("URL")
:指定该函数响应指定 URL 的 HTTP GET 请求的装饰器。def main_function(value: str, list=Depends(dependency_function))
:value
:依赖主函数的字符串参数。list
:依赖于dependency_function
的结果。Depends
函数通常用于处理依赖项并动态获取值。
@app.get("URL")
def main_function(value: str, list=Depends(dependency_function)):
pass
代码定义了一个 FastAPI 应用程序,其中包含一个水果列表(main_fruits_list
)。/fruits/
端点接受一个查询参数(fruit
),并将其添加到主水果列表中,返回一条表示添加成功的消息。水果列表通过依赖项(call_main_fruits
) 进行管理。
import uvicorn
from fastapi import FastAPI, Depends
app = FastAPI()
# 创建水果列表
main_fruits_list = ["Apple"]
# 调用主水果列表
def call_main_fruits():
return main_fruits_list
# 使用 Pydantic 调用主 FastAPI 应用程序
@app.get("/fruits/")
def test_main_fruits(fruit: str, list=Depends(call_main_fruits)):
list.append(fruit)
print(list)
return {"message": f"Added fruit {fruit} in the list"}
if __name__ == '__main__':
uvicorn.run(app="main:app", port=8000)
在 FastAPI 中 处理子依赖项
在 FastAPI 中,管理子依赖项涉及组织和处理应用程序中的附加依赖项。这使得在 FastAPI 中引入和使用二级组件或服务的方式更加有条理,有助于构建模块化且易于维护的代码库。
语法:
dependency_function
是一个异步函数,依赖于 sub_dependency_function
的结果,并接受一个可选的整数参数 value
。
async def dependency_function(value: int = Depends(sub_dependency_function)):
pass
import uvicorn
from fastapi import FastAPI, Depends
app = FastAPI()
# 创建价格的子依赖项
async def sub_dependency_price(price: int):
if price == 0:
return 50
else:
return price
# 创建水果的依赖项
async def dependency_fruits(fruit: str, price: int = Depends(sub_dependency_price)):
return {"Fruit": fruit, "Price": price}
# 使用 Pydantic 调用 FastAPI 应用程序
@app.get("/fruits")
async def fetch_authors(fruits_list: dict = Depends(dependency_fruits)):
return fruits_list
if __name__ == '__main__':
uvicorn.run(app="main:app", port=8000)
依赖注入案例
下面是一个使用依赖注入的实际案例。我们将构建一个 用户管理 API,其中包括:数据库访问
数据库依赖注入
我们将使用 SQLAlchemy
来管理数据库会话,并通过依赖注入来使用它们。
安装所需要的包:
pip install fastapi uvicorn sqlalchemy psycopg2 pydantic bcrypt pyjwt python-multipart
我们将使用 SQLAlchemy
来管理数据库会话,并通过依赖注入来使用它们。
**database.py ** 文件
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base, Session
DATABASE_URL = "mysql+pymysql://root:123456@localhost/fastapi"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True)
hashed_password = Column(String)
get_db()
是一个提供数据库会话的依赖项yield
语句确保会话在使用后被关闭
创建一个 AuthService
类,使用 JWT 处理认证逻辑(可注入依赖项)
auth.py 文件
import jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
SECRET_KEY = "supersecret"
ALGORITHM = "HS256"
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
class AuthService:
@staticmethod
def hash_password(password: str) -> str:
return pwd_context.hash(password)
@staticmethod
def verify_password(password: str, hashed_password: str) -> bool:
return pwd_context.verify(password, hashed_password)
@staticmethod
def create_jwt_token(user_id: int):
expiration = datetime.utcnow() + timedelta(hours=1)
return jwt.encode({"sub": user_id, "exp": expiration}, SECRET_KEY, algorithm=ALGORITHM)
def get_auth_service():
return AuthService()
AuthService
是一个基于 类的依赖项get_auth_service()
是一个可注入的依赖项函数
在 API 路由中注入依赖项
main.py 文件
import uvicorn
from fastapi import FastAPI, Depends, HTTPException, Form
from sqlalchemy.orm import Session
from auth import get_auth_service, AuthService
from database import get_db, User
app = FastAPI()
@app.post("/register")
def register_user(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db),
auth_service: AuthService = Depends(get_auth_service)):
hashed_password = auth_service.hash_password(password)
user = User(username=username, hashed_password=hashed_password)
db.add(user)
db.commit()
db.refresh(user)
return {"message": "User registered successfully"}
@app.post("/login")
def login_user(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db),
auth_service: AuthService = Depends(get_auth_service)):
user = db.query(User).filter(User.username == username).first()
if not user or not auth_service.verify_password(password, user.hashed_password):
raise HTTPException(status_code=400, detail="Invalid credentials")
token = auth_service.create_jwt_token(user.id)
return {"access_token": token, "token_type": "bearer"}
if __name__ == '__main__':
uvicorn.run(app="main:app", port=8000)
总结
FastAPI 中的依赖注入是一种强大的机制,能够增强代码的模块化和可维护性。通过高效地管理和注入依赖项,FastAPI 让开发人员能够创建更加有条理、可扩展且可测试的应用程序。