依赖与配置管理
依赖与配置管理 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
这一课解决服务长大后的两个黏腻问题:每个接口都自己开数据库连接、配置散落在代码各处。目标是学会用 Depends 注入依赖、用 Settings 收拢配置,并让「缺一项可选能力」不再炸掉整个服务。
问题场景
P08 的 NOTES 还是内存列表,P11 会换成 SQLite。最直接的写法是每个路由函数第一行 sqlite3.connect(...)——十个接口十份连接代码,测试时想换成内存库要改十个函数。前端 React 里你用 Context 解决「组件树到处传依赖」,FastAPI 的答案是 Depends。
核心解释
依赖注入的本质:函数声明「我需要什么」,框架负责「造出来递给你」。
import os
import sqlite3
from functools import lru_cache
from fastapi import Depends, FastAPI
app = FastAPI()
def get_db():
conn = sqlite3.connect(os.environ.get("DB_PATH", "reactlab.db"))
try:
yield conn
finally:
conn.close() # yield 后的代码在请求结束时执行
@lru_cache
def get_settings() -> dict:
return {
"db_path": os.environ.get("DB_PATH", "reactlab.db"),
"ai_key": os.environ.get("AI_API_KEY", ""), # 可选能力
}
@app.get("/notes")
def list_notes(conn: sqlite3.Connection = Depends(get_db)):
rows = conn.execute("SELECT id, title FROM note").fetchall()
return {"total": len(rows), "items": [dict(zip(("id", "title"), r)) for r in rows]}
四条设计纪律:
- 依赖可以被替换。测试时用
app.dependency_overrides[get_db] = lambda: memory_conn,整个应用的数据库换成内存库,路由代码零改动。这是注入比「函数里直接 connect」值钱的地方。 - 配置集中 + 环境变量注入。
get_settings用lru_cache保证全进程只读一次;数据库路径、密钥这类随部署变化的东西全部走环境变量,代码里只留默认值。本站的做法一致:AI 密钥只存在于服务端.env.local。 - 区分启动必需与可选能力。数据库路径缺失应该启动时明确报错;AI 密钥缺失不该阻止启动——对应本站
/api/ai/status:没配 AI 时服务照常跑,只是 AI 功能返回not_configured。启动崩溃是给「必需项」的待遇。 - 不要在模块导入时连接服务。
import时连数据库,测试导入模块就连上真库,P03 讲的「导入无副作用」在服务端的翻版。所有连接都发生在请求期(Depends)或显式启动事件里。
示例拆解
验证「注入可替换」这个核心收益:
# test_note.py(先感受,P17 系统讲)
from fastapi.testclient import TestClient
import sqlite3
from main import app, get_db
app.dependency_overrides[get_db] = lambda: iter([sqlite3.connect(":memory:")]) # 示意
client = TestClient(app)
# 请求 /notes 时拿到的不再是文件库,而是注入的内存库
预期效果:同一个路由函数,生产用文件库、测试用内存库,切换只发生在 override 一处。对照 P17 的临时数据库测试和 P19 的契约测试,这条链路贯穿整个 track 的工程化路线。
动手任务
- 把 P08 的笔记接口改造成
Depends(get_db)从 SQLite 读,删除内存列表。 - 新增
GET /ai/status:读 settings 里的ai_key,为空返回{"configured": false, "category": "not_configured"},非空返回{"configured": true}——注意服务本体不因缺 key 崩溃。 - 把 DB 路径挪进
get_settings,用环境变量DB_PATH=test.db启动一次,确认新库文件被创建。
常见错误
- 模块顶层 connect:导入即连接,测试和生产互相污染;连接一律走依赖或启动事件。
- 每个接口读一遍 os.environ:配置散落,改名要全局搜;收进 Settings 对象。
- 依赖里忘了 close:yield 依赖的
finally是释放资源的唯一保险,漏写连接数只涨不降。 - 可选能力设成硬依赖:没配 AI 密钥连笔记接口都起不来;必需项启动校验,可选项运行时降级。
检查与复盘
自查清单:
- 路由函数里找不到 connect/environ 的直接调用
- 能演示用 dependency_overrides 换掉一个依赖
- 拔掉可选配置(AI key)服务照常启动,必需配置缺失则明确报错
参考资料
- FastAPI 官方教程:Dependencies —— Depends 与 yield 依赖
- FastAPI 进阶:Settings and Environment Variables —— 配置对象与环境变量
读完这一课了?
标记完成后,工作台会安排接下来的学习。