【Web全栈进阶】FastAPI工程化:APIRouter拆分 + 配置 + 依赖注入
之前的FastAPI还活在单文件里所有路由挤在一个main.py。200行时没问题500行时没人敢动——今天把它升级成“分模块的工程”用早报站的API实战三件套APIRouter拆路由、Settings管配置、Depends依赖注入。本篇产出早报站FastAPI应用骨架——app/分层、两个路由模块、统一会话注入、配置文件外置。含代码约150行。 太长不看版给想快速上手的你项目信息一句话说明本篇目标FastAPI从单文件升级为分模块工程代码行数~150行含注释依赖fastapipydantic-settings新增核心功能APIRouter拆分 Settings配置 Depends依赖注入跑起来的命令uvicorn app.main:app --reload核心知识点分层结构、配置外置、依赖注入做完你能得到一套能维护、可扩展的FastAPI工程骨架⚠️工程声明本篇先把FastAPI的“骨架与结构”立起来响应模型response_model的完整规范留到后面联调篇统一设计——今天解决“结构”明天解决“规范”。一、为什么需要“工程化”单文件的三宗罪单文件API是这个画风# 所有路由、所有逻辑、所有配置挤在一个文件app.get(/todos)...app.post(/todos)...app.put(/todos/{id})...三个问题会随着代码长大依次爆发#问题表现①路由一多文件失控找接口靠CtrlF②配置散落连接串、密钥写在文件各处③重复代码每个接口都写一遍“开会话、关会话”工程化就是把这三件事制度化——这正是早报站从“玩具”走向“产品”必须跨过的一步。二、新结构app/层的标准布局python_daily/ ├── core/ # 数据层第03、04篇已就位 │ ├── db.py # 引擎与会话 │ └── models.py # ORM模型 ├── app/ # API层本篇新建 │ ├── __init__.py │ ├── main.py # 应用入口创建app、挂载路由 │ ├── config.py # Settings配置集中管理 │ ├── deps.py # 共享依赖get_session等 │ └── routers/ # 路由按资源分文件 │ ├── __init__.py │ ├── articles.py │ └── sources.py └── .env # 本地配置进.gitignore分层逻辑一句话core是“数据怎么存”app是“接口怎么暴露”routers是“一个资源一个文件”。三、第1步Settings——配置只写一处app/config.pyapp/config.py —— 全局配置frompydantic_settingsimportBaseSettings,SettingsConfigDictclassSettings(BaseSettings):配置项集中声明环境变量与.env文件自动注入database_url:strpostgresqlpsycopg://postgres:你的密码localhost:5432/dailysecret_key:strdev-onlydebug:boolFalsemodel_configSettingsConfigDict(env_file.env,extraignore)settingsSettings()# 全局唯一实例其他地方import它 三个细节#细节说明①env_file.env自动读项目根的.env文件——.env必须进.gitignore密钥不在代码里、不在仓库里只在环境里②环境变量自动匹配字段database_url自动匹配环境变量DATABASE_URL大小写不敏感.env里写DATABASE_URLxxx即生效③默认值本地开发兜底生产环境用环境变量覆盖代码零改动 以后任何接口要用配置一行from app.config import settings。.env示例记得进.gitignoreDATABASE_URLpostgresqlpsycopg://postgres:你的密码localhost:5432/daily SECRET_KEY你的随机密钥 DEBUGfalse四、第2步共享依赖——session注入每个接口都要数据库会话但“开一个、用、关一个”不该重复写。FastAPI的依赖注入Depends把这件事制度化app/deps.pyapp/deps.py —— 共享依赖fromcore.dbimportSessiondefget_session():每个请求一个独立会话请求结束自动关闭with保证withSession()assession:yieldsessionapp/routers/articles.pyapp/routers/articles.py —— 文章接口fromfastapiimportAPIRouter,Dependsfromsqlalchemyimportselectfromsqlalchemy.ormimportSessionfromapp.depsimportget_sessionfromcore.modelsimportArticle routerAPIRouter(prefix/articles,tags[articles])router.get()deflist_articles(session:SessionDepends(get_session),# 依赖注入FastAPI自动调用get_sessionlimit:int10,):文章列表最新在前stmtselect(Article).order_by(Article.id.desc()).limit(limit)returnsession.scalars(stmt).all() 拆开看发生了什么#关键点说明①Depends(get_session)声明“这个接口需要get_session提供的东西”——FastAPI收到请求时自动调用get_session把yield出的session作为参数传进来请求结束自动执行收尾②好处一接口代码干净函数体里只有业务逻辑没有样板③好处二全局替换将来测试时第26篇把get_session换成“测试库会话”所有接口自动切换一行接口代码不用改依赖注入的第一个字面收益是整洁深层收益是可替换。 再加一个业务型依赖练手——分页参数app/routers/articles.py补充defget_page(page:int1,size:int10):分页依赖page从1开始返回(offset, limit)return(page-1)*size,sizerouter.get(/top)deftop_articles(session:SessionDepends(get_session),page:tuple[int,int]Depends(get_page),# 依赖还能组合依赖):offset,limitpage stmtselect(Article).order_by(Article.id.desc()).offset(offset).limit(limit)returnsession.scalars(stmt).all() 注意page的类型注解是tuple[int, int]和get_page返回值对齐——类型注解要和实际返回一致第七节④会讲这个坑。五、第3步应用入口——把路由挂上去app/main.pyapp/main.py —— FastAPI应用入口fromfastapiimportFastAPIfromapp.routersimportarticles,sources appFastAPI(title早报站 API,version0.2.0)app.include_router(articles.router)app.include_router(sources.router)app/routers/sources.py订阅源接口模式同articlesfromfastapiimportAPIRouter,Dependsfromsqlalchemyimportselectfromsqlalchemy.ormimportSessionfromapp.depsimportget_sessionfromcore.modelsimportSource routerAPIRouter(prefix/sources,tags[sources])router.get()deflist_sources(session:SessionDepends(get_session)):returnsession.scalars(select(Source)).all()✅ 运行在项目根目录执行uvicorn app.main:app--reload打开/docs——见证结构化的第一个红利Swagger里接口按articles / sources分组显示tags自动归类接口多了也不乱。六、验收清单1. uvicorn启动无报错/docs里articles / sources两组接口2. 浏览器访问/articles?limit3→ 返回3条文章JSON3. 访问/articles/top?page2→ 翻页生效offset正确4. 改.env的DATABASE_URL指向不存在的库 → 接口报可读错误 → 改回5.gitstatus确认.env不在仓库里6. 全程无报错后提交Gitgitadd.gitcommit-mFastAPI工程化路由拆分 Settings 依赖注入七、常见报错这6个工程化改造的标配重点①ModuleNotFoundError: No module named pydantic_settings 原因pydantic-settings需要单独安装FastAPI自带pydantic不带settings。✅ 解法pipinstallpydantic-settings pip freezerequirements.txt②ModuleNotFoundError: No module named app 原因启动目录不对——不在项目根目录执行uvicorn。✅ 解法cd python_daily再跑cwd在sys.path里才有app包一季第5篇的老规矩。③/docs里接口地址变成/articles//或访问报307 原因prefix/articles加router.get(/)拼出了双斜杠。✅ 解法带prefix时路由写空串router.get()不带prefix时写/。prefix与路径的拼接规则要记牢。④ 访问接口报missing required argument: session 原因函数签名写了session: Session但忘了 Depends(get_session)——FastAPI把它当成普通必填参数。✅ 解法依赖注入的声明是Depends(...)不是类型注解本身。类型注解只是文档Depends才是接线。⑤ 返回的JSON里datetime报cannot encode datetime 原因直接返回ORM对象时FastAPI默认序列化不了datetime等复杂类型。✅ 解法现在表里全是基础类型所以没炸加了时间列就会遇到——响应模型response_model与序列化规范在后续统一处理。先记住裸ORM对象返回是过渡态。⑥ 改了.env配置程序没反应 原因Settings在import时读一次.env——改完要重启uvicorn--reload会自动重启但改了.env有时不触发。✅ 解法手动重启或确认.env在项目根、名字正确无后缀就叫.env。八、课后练习#练习难度提示1补齐sources接口给订阅源加“按url模糊搜索”⭐⭐Source.url.contains(keyword)2分页依赖升级给get_page加max_size50上限size传1000时自动截断⭐⭐依赖里的防御逻辑一次生效全接口受益3密钥搬家把遗留的明文配置全部迁入Settings .env⭐⭐密钥军规正式落地4选做新旧对照用新结构重写待办API⭐⭐⭐感受“单文件”与“工程”的差距 配套代码完整app/结构已上传Gitpython_daily/【gitee仓库地址】

相关新闻

Spring AI 接入已有 Java 项目的三种架构设计

Spring AI 接入已有 Java 项目的三种架构设计

Spring AI 真正进入现有 Java 系统时,首先需要解决的是 AI 能力应该放在哪个位置。实际设计可以归纳为三种典型方式:直接嵌入现有服务、独立建设 AI Service,以及为旧系统旁路增加 AI 服务。三种方式分别对应不同的业务规模、复用范围和改造成…

2026/10/9 10:19:41 阅读更多 →
C++模板进阶:非类型模板参数、模板特化与分离编译一次搞懂

C++模板进阶:非类型模板参数、模板特化与分离编译一次搞懂

C模板进阶:非类型模板参数、模板特化与分离编译一次搞懂 文章目录C模板进阶:非类型模板参数、模板特化与分离编译一次搞懂一、非类型模板参数1 类型模板参数2 非类型模板参数3 非类型模板参数的特点必须是编译期能够确定的值浮点数、类对象以及字符串不能…

2026/10/9 10:19:41 阅读更多 →
XinText 更新|一套编辑器,Windows/macOS/Linux都可用!

XinText 更新|一套编辑器,Windows/macOS/Linux都可用!

兄弟们,时代变了! 以前大家都说我的编辑器只能 Windows 用,太可惜了! 每次有人问我:“大佬什么时候出 Mac / Linux 版本?” 这次!直接一次性拉满!!🔥 Xin…

2026/10/9 10:19:41 阅读更多 →

最新新闻

基于JWT/JWE的跨系统安全数据透传方案详解

基于JWT/JWE的跨系统安全数据透传方案详解

先说结论:这套“基于JWT/JWE的跨系统安全数据透传方案”,解决的是两个不同域、不同技术栈、甚至不同运维体系的服务之间,如何安全地把一段结构化数据从A端交付到B端——既保证数据在“路上”不被看、不被改,又保证接收方能够验证数…

2026/10/9 10:57:43 阅读更多 →
MySQL慢查询优化实战:索引设计与执行计划调优全攻略

MySQL慢查询优化实战:索引设计与执行计划调优全攻略

接手线上MySQL慢查询优化这类活儿,看着是加几个索引的事,实际上是一整套“读表逻辑”的博弈。索引优化策略不只是“在WHERE条件字段上建索引”这么简单,它背后涉及索引结构、查询执行计划、数据分布、写入成本之间的复杂权衡。这篇就把我在实…

2026/10/9 10:57:43 阅读更多 →
撕开高性能芯片与电竞级体验的包装:实测数据还原真实性能

撕开高性能芯片与电竞级体验的包装:实测数据还原真实性能

上周帮朋友挑新机,宣传页上“高性能芯片”四个字印得比Logo还大,背面还配了一行小字“电竞级稳帧体验”。跑分一拉出来,确实漂亮,安兔兔九十几万,看着就热血。结果朋友拿回家打了两局游戏,第三把还没打完&a…

2026/10/9 10:57:43 阅读更多 →
光伏电站运维模式怎么选?自建、委托、混合与智能运维全解析

光伏电站运维模式怎么选?自建、委托、混合与智能运维全解析

光伏圈里有一句话我特别认同:"电站并网只是起点,运维才是长跑。"做光伏这么多年,见过太多项目,前期的设计、采购、施工都舍得花钱,一到运维环节就开始精打细算,结果呢?组件热斑、逆变…

2026/10/9 10:57:43 阅读更多 →
MySQL提交数归零与123个CVE背后:真相与运维应对

MySQL提交数归零与123个CVE背后:真相与运维应对

最近在数据库圈子里,一个话题被反复讨论,甚至有人说 MySQL 正在“自杀”:代码提交数为 0,123 个 CVE 安全漏洞悬而未决。乍一听确实吓人,但作为常年折腾数据库的人,我第一反应是:得把这些数字拆…

2026/10/9 10:57:43 阅读更多 →
数据产品思维:打破数据所有权困局,让数据真正资产化

数据产品思维:打破数据所有权困局,让数据真正资产化

1. 数据团队和业务团队,为什么总在“谁说了算”上打架先从我最近遇到的一个真实场景说起。某家做零售的公司,数据部门辛苦搭了一套用户画像体系,整合了线上线下十几个系统的会员数据,清洗、打标、建模,前前后后折腾了大…

2026/10/9 10:56:40 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →