ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

码道:用 FastAPI 十分钟写一个学生管理接口项目:内存列表存储 + Swagger 文档一把梭

码道:用 FastAPI 十分钟写一个学生管理接口项目:内存列表存储 + Swagger 文档一把梭 一、前言为什么要有这个项目最近在复习后端接口开发总想找一个麻雀虽小、五脏俱全的练手项目。传统的学生管理系统教程大多绑定 MySQL、JDBC、配置文件、ORM 一堆东西对一个只想快速理解接口是怎么一个流程的学习者来说学习曲线太陡了。于是我想能不能做一个零数据库依赖、纯内存、自带可视化接口文档的学生信息管理接口把注意力集中在最核心的 RESTful 设计上带着这个想法我用 Python 的 FastAPI 框架完成了这个小项目。它没有什么宏大目标就是一个标准的学生表增删改查CRUD接口数据保存在内存列表里。但麻雀虽小它把接口开发的完整链路都覆盖了一遍数据模型设计、参数校验、路由组织、错误处理、自动文档、自动化测试。跑通它之后你对一个后端接口是怎么被写出来并如何被调用这件事会有很直观的体感。二、技术选型为什么是 FastAPIPython 生态里的 Web 框架不少Flask、Django、FastAPI 是三个主流选择。我最终选了 FastAPI主要看重三点第一自带 OpenAPI 规范。FastAPI 基于 Python 类型注解自动生成接口文档启动服务后访问/docs就能看到 Swagger UI每一个接口的参数、返回值、示例全部可视化。相比之下Flask 要自己接 flasgger 或者手写文档Django REST framework 也能生成文档但配置成本更高。对需要给出 Swagger API 说明这类需求FastAPI 几乎是开箱即答。第二性能出众。FastAPI 基于 Starlette 和 Pydantic异步支持良好在接口性能评测里长期排在第一梯队。虽然本项目只做内存操作性能区别不明显但选型时考虑未来扩展是合理的。第三类型安全和自动校验。用 Pydantic 定义数据模型后请求体会被自动校验字段缺失、类型错误、取值越界会直接返回 422 错误省去了大量手写 if-else 的防御性代码也让接口契约变得非常清晰。服务器端选用 Uvicorn它是目前 FastAPI 官方推荐的 ASGI 服务器轻量、稳定、支持热重载开发体验很好。三、项目结构与架构设计你可能会觉得写 CRUD 还要分层有点小题大做但我在项目里确实做了一套简单的分层因为我知道学习接口开发的人最缺的往往不是怎么写通而是怎么组织得更像正式项目。项目结构如下bigData_demo_1001/ ├── app/ │ ├── __init__.py │ ├── main.py # 应用入口创建 FastAPI 实例 │ ├── models.py # Pydantic 数据模型 │ ├── database.py # 内存存储层 │ └── routers/ │ └── students.py # 学生接口路由 ├── tests/ │ └── test_students.py # 自动化测试 ├── requirements.txt ├── README.md └── BLOG.md三层职责划分很清楚模型层models.py用 Pydantic 定义StudentCreate、StudentUpdate、Student三个模型分别对应创建请求体、更新请求体、完整学生数据结构存储层database.py封装一个InMemoryStudentStore类内部用一个列表保存学生外加一把threading.Lock保证并发下 ID 自增不冲突路由层routers/students.py只负责接收 HTTP 请求、调用存储层、拼装响应不碰业务细节。这样拆分的最大好处是以后想换真实数据库只需要重写database.py路由和模型完全不用动。这种存储和接口解耦的思维是正式后端项目里的通用做法。四、核心实现数据模型与存储层先看数据模型。学生表里有id、name、age、gender、email、major、created_at这几个字段。其中id和created_at是系统自动生成的name、age、gender、email、major是调用方传入的。Pydantic 让字段约束变得非常优雅。比如年龄字段我要求取值在 0 到 150 之间性别只能是男 / 女 / 其他邮箱必须是合法格式姓名和专业不能为空。这些约束写进模型里之后FastAPI 在请求进来时就会自动完成校验非法数据直接被挡在业务逻辑之外classStudentCreate(BaseModel):name:strField(...,min_length1,max_length50,description学生姓名)age:intField(...,ge0,le150,description学生年龄0~150)gender:strField(...,pattern^(男|女|其他)$,description性别)email:EmailStrField(...,description学生邮箱)major:strField(...,min_length1,max_length100,description专业)再看存储层。虽然只是内存列表我还是把它写成了一个独立的类并考虑了线程安全。核心是一个自增 ID 生成器defcreate(self,payload:StudentCreate)-Student:studentStudent(idself._assign_id(),created_atdatetime.now(),**payload.model_dump(),)self._students.append(student)returnstudent_assign_id内部用with self._lock保护 ID 的分配过程避免多线程并发请求时出现重复 ID。同时我也写了get_by_id、update、delete等方法配套路由使用。五、路由层五个接口覆盖全 CRUD路由层我设计成 RESTful 风格前缀统一为/api/students方法路径作用POST/api/students新增学生GET/api/students查询列表GET/api/students/{id}查询单个学生PUT/api/students/{id}全量更新学生DELETE/api/students/{id}删除学生有几个设计细节值得一提。关于更新动词的选择。我采用了 PUT 做全量更新即调用方必须提交所有必填字段这是对更新最简单直观的理解。真实项目里也有 PATCH 做局部更新的用法本项目中为了保持接口简洁只保留了 PUT。查询接口支持筛选和分页。GET /api/students支持三个查询参数name按姓名模糊匹配、limit每页条数默认 50最大 200、offset跳过条数。分页参数同样通过 FastAPI 的Query做了边界校验比如limit传负数会被直接拒绝。错误处理遵循 HTTP 语义。查询或更新一个不存在的学生会返回 404 和明确的中文错误信息请求体校验失败则返回 422。这些都不需要手写 try-catch框架的自动校验和HTTPException已经足够。六、Swagger 文档接口说明的自动化用户要求给出 Swagger 的 API 说明这在 FastAPI 里几乎是零成本。启动服务后访问http://127.0.0.1:8000/docs你就能看到一份完整、可交互的接口文档每个接口的请求参数、请求体 JSON 结构、响应状态码、示例值全部自动生成还能直接在页面上点Try it out发请求测试。这背后的机制是 FastAPI 自动维护的 OpenAPI原 Swagger规范托管在/openapi.json。如果在路由函数的 Docstring 里写清楚「summary」和「description」这些内容也会呈现到文档里。对接口使用者来说文档即接口契约完全不需要额外维护一份独立的接口说明文档。除了交互式的/docs项目还自带了 ReDoc 风格文档/redoc适合把接口规范给非技术同学阅读。七、测试验证11 个用例守护接口行为代码写完了、能跑了但我不放心于是基于 FastAPI 官方推荐的TestClient写了自动化测试。测试文件覆盖了健康检查接口返回 200新增学生成功返回 201且 ID 自增、含有创建时间新增非法数据年龄为负数返回 422列表查询、按姓名模糊筛选按 ID 查单个学生、查询不存在返回 404更新学生后字段变化且 ID 和创建时间保持不变删除成功后再次查询返回 404。每个测试用例之间通过一个autouse的 fixture 清空内存存储保证用例互相独立。最终 11 个用例全部通过这让我对接口行为有了信心也为后续重构提供了安全网。八、实测走一遍curl 完整调用演示写代码和测试是一回事亲自把服务跑起来、用真实的 HTTP 请求打一遍又是另一回事。为了让验证更踏实我启动服务后直接用 curl 串了一遍完整的增删改查流程。先用 POST 新增一位叫王小明的学生服务端返回 201并且我们能看到系统自动分配了 ID 为 1还带了一个 ISO8601 格式的创建时间{name:王小明,age:21,gender:男,email:wangxmexample.com,major:软件工程,id:1,created_at:2026-10-01T14:48:08.367345}紧接着查询列表能拿到这位学生然后我用 PUT 把他的年龄从 21 改成 22邮箱也换了一个返回结果里可以看到年龄字段已经更新但 ID 和创建时间保持不变这说明更新只改业务字段、不碰主键信息最后执行 DELETE返回 204 无内容再查这个 ID 就返回 404 了——一个完整的数据生命周期就这么走完了。这个实际调用过程给了我两点启发一是接口的响应语义201、204、404、422要符合直觉使用者一看状态码就知道发生了什么二是字段的可变与不可变要分清楚像 ID、创建时间这种系统字段就绝不允许调用方篡改这与权限、安全也直接相关。九、踩坑记录开发过程中遇到两件值得记录的事。第一个坑是EmailStr需要额外的email-validator依赖。Pydantic 的EmailStr类型只是一个注解真正的邮箱格式校验是同名的独立库完成的。如果没装启动时不会报错但一调用就会抛ImportError。解决方法是pip install pydantic[email]并把版本固定进requirements.txt。第二个坑是字段约束写得太严格导致误伤。最初我把性别约束为^(男|女)$后来意识到现实场景中存在保密等其他选项于是放宽为^(男|女|其他)$。这个小改动说明数据模型约束不是越严越好要与业务场景匹配兼顾合理性与兼容性。十、关于内存列表存储的再思考既然题目明确要求用内存列表完成数据存储那我们就认真聊聊这种方案的得与失。先说为什么它可以成立。内存列表本质上是一个以 Pythonlist为载体的简单数据结构增删改查都是 O(n) 级别的线性操作配合字典索引还能降到 O(1)。对于单机、低并发、测试演示类的场景它的读写速度反而比需要网络往返的数据库更快也没有环境依赖跑起来零成本。这也是很多联调环境、单元测试里常用 mock 数据或者内存存储的原因。再说它的边界在哪里。最直接的限制是不持久化服务重启数据清空。其次是不可扩展内存有限数据量上来之后必然扛不住进程之间也无法共享这份数据。最后是并发安全虽然我加了threading.Lock但它只在单进程多线程内有意义一旦真正做成多实例部署锁就形同虚设了。所以我对内存存储的定位是教学演示与快速原型的好工具但绝不是生产环境的终点。这也是我在设计时把存储层单独抽出来的原因——将来把database.py换成 SQLAlchemy 的实现接口层一行都不用改。这种接口与实现解耦带来的替换成本最小化正是分层设计价值的最佳注脚。十一、总结与扩展思路这个项目用大约两百行代码完成了学生信息管理接口的闭环RESTful 路由设计、Pydantic 数据校验、内存存储、Swagger 自动文档、pytest 自动化测试。它最适合两类人一是想快速理解后端接口开发流程的初学者二是需要一个能跑的最小示例来演示 RESTful 风格教学的场景。当然它也有明显局限内存存储重启即丢失、没有身份认证、没有 CORS 配置、单进程下线程锁意义有限。正因为留有这些开放口它才更适合作为持续演进的项目。如果继续做下去我会按这样的优先级迭代把内存存储替换为 SQLite 或 MySQL引入 SQLAlchemy 做持久化增加 JWT 鉴权让接口有用户体系完善分页返回结构加上总条数、总页数等元信息用 Docker 打包支持一键部署。如果你也对这种小而完整的接口项目感兴趣欢迎克隆仓库 clone 下来跑一跑或者干脆把它 fork 走加上你自己的改进——无论是接上真实数据库还是补充更多字段和接口都会是一个不错的练习。最后想说的是写接口这件事最难的不是把接口写出来而是把写接口的流程和思维方式沉淀下来。这个项目就是一个可复用的最小范式希望对你有帮助。TOC欢迎使用Markdown编辑器你好 这是你第一次使用Markdown编辑器所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持除了标准的Markdown编辑器功能我们增加了如下几点新功能帮助你用它写博客全新的界面设计将会带来全新的写作体验在创作中心设置你喜爱的代码高亮样式Markdown将代码片显示选择的高亮样式进行展示增加了图片拖拽功能你可以将本地的图片直接拖拽到编辑区域直接展示全新的KaTeX数学公式语法增加了支持甘特图的mermaid语法1功能增加了多屏幕编辑Markdown文章功能增加了焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置等功能功能按钮位于编辑区域与预览区域中间增加了检查列表功能。功能快捷键撤销Ctrl/CommandZ重做Ctrl/CommandY加粗Ctrl/CommandB斜体Ctrl/CommandI标题Ctrl/CommandShiftH无序列表Ctrl/CommandShiftU有序列表Ctrl/CommandShiftO检查列表Ctrl/CommandShiftC插入代码Ctrl/CommandShiftK插入链接Ctrl/CommandShiftL插入图片Ctrl/CommandShiftG查找Ctrl/CommandF替换Ctrl/CommandG合理的创建标题有助于目录的生成直接输入1次#并按下space后将生成1级标题。输入2次#并按下space后将生成2级标题。以此类推我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。如何改变文本的样式强调文本强调文本加粗文本加粗文本标记文本删除文本引用文本H2O is是液体。210运算结果是 1024.插入链接与图片链接: link.图片:带尺寸的图片:居中的图片:居中并且带尺寸的图片:当然我们为了让用户更加便捷我们增加了图片拖拽功能。如何插入一段漂亮的代码片去博客设置页面选择一款你喜欢的代码片高亮样式下面展示同样高亮的代码片.// An highlighted blockvarfoobar;生成一个适合你的列表项目项目项目项目1项目2项目3计划任务完成任务创建一个表格一个简单的表格是这么创建的项目Value电脑$1600手机$12导管$1设定内容居中、居左、居右使用:---------:居中使用:----------居左使用----------:居右第一列第二列第三列第一列文本居中第二列文本居右第三列文本居左SmartyPantsSmartyPants 是一个文本转换工具主要功能是将普通的 ASCII 标点符号自动转换为更美观的印刷体标点符号。例如原始符号转换后说明引号“引号”直引号变弯引号单引号‘单引号’直单引号变弯单引号--–两个连字符变短破折号---—三个连字符变长破折号...…三个点变省略号创建一个自定义列表MarkdownText-to-HTMLconversion toolAuthorsJohnLuke如何创建一个注脚一个具有注脚的文本。2注释也是必不可少的Markdown将文本转换为HTML。KaTeX数学公式您可以使用渲染LaTeX数学表达式 KaTeX:Gamma公式展示Γ ( n ) ( n − 1 ) ! ∀ n ∈ N \Gamma(n) (n-1)!\quad\forall n\in\mathbb NΓ(n)(n−1)!∀n∈N是通过欧拉积分Γ ( z ) ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) \int_0^\infty t^{z-1}e^{-t}dt\,.Γ(z)∫0∞​tz−1e−tdt.你可以找到更多关于的信息LaTeX数学表达式here.新的甘特图功能丰富你的文章2014-01-072014-01-092014-01-112014-01-132014-01-152014-01-172014-01-192014-01-21已完成进行中计划一计划二现有任务Adding GANTT diagram functionality to mermaid关于甘特图语法参考 这儿,UML图表可以使用UML图表进行渲染例如下面产生的一个序列图王五李四张三王五李四张三李四想了很长时间, 文字太长了不适合放在一行.你好李四, 最近怎么样?你最近怎么样王五我很好谢谢!我很好谢谢!打量着王五...很好... 王五, 你怎么样?关于UML图表语法参考 这儿,流程图链接长方形圆圆角长方形菱形关于Mermaid语法参考 这儿,FLowchart流程图我们依旧会支持flowchart.js的流程图语法Created with Raphaël 2.3.0开始我的操作确认结束yesno关于Flowchart流程图语法参考 这儿.导出与导入导出如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到文章导出生成一个.md文件或者.html文件进行本地保存。导入如果你想加载一篇你写过的.md文件在上方工具栏可以选择导入功能进行对应扩展名的文件导入继续你的创作。mermaid语法说明 ↩︎注脚的解释 ↩︎
返回列表