FastAPI 完整实践:有上限的 SQLite 费用账本 · 读者执行步骤与预期至参考答案
前置:契约、依赖生命周期。完整工程位于 examples/python/p2-fastapi。示例未执行、测试未执行、依赖未安装;本页只提供完整源码、预期规格和静态检查范围。没有启动ASGI服务、访问API或调用TestClient,也没有把设计OpenAPI冒充运行结果。
读者执行步骤与预期
FastAPI示例应该如何自行验证?先在独立venv安装固定依赖,运行unittest,再启动回环地址服务;本次未执行这些命令。README给出PowerShell和Bash的解释器路径,测试使用临时数据库,不依赖工作目录中的已有账本。
从空数据库提交 {"reference":"lunch_001","category":"food","cents":1250} 预期201,JSON包含正整数id及三个原输入字段。用该id读取预期200同一对象,列表预期含该对象。相同reference再次提交预期409和 {"detail":"duplicate_reference"},随后列表仍一条。删除预期204且字节body为空,再读取预期404和 {"detail":"not_found"}。不要把id必为1写成永久协议,AUTOINCREMENT可能因历史删除留空洞。
负例预期:cents为0、100000001、"1250"、true、12.5,reference含空格,category为unknown,或额外提交id,均422固定 {"detail":"invalid_request"} 且不插入行。填满100条后第101条预期409 ledger_full;删除一条后可再新增。另一连接持有BEGIN IMMEDIATE时新增预期503 storage_busy;释放锁后重试可成功。所有这些是测试规格,尚无运行通过记录。
并发规格与静态证据
FastAPI怎样检验重复请求的并发边界?测试规格让两个独立客户端并行提交同一reference,预期恰好一个201,另一个允许409或503,最终只有一条记录。客户端lifespan先串行进入,避免建表竞争掩盖请求写入竞争;没有断言固定线程顺序或吞吐量。
BEGIN IMMEDIATE把容量查询与INSERT串成写事务;同一请求不并发使用自己的连接。多进程也必须遵守同一数据库事务规则,不能靠Python进程内锁当跨进程保证。不能因为SQLite每次只允许一个写者就推导所有请求必然成功:等待超过timeout会失败,磁盘、权限和损坏还可能产生其他服务器错误。
静态验证只解析Python AST、TOML、JSON、Markdown锚点、同源include以及VitePress→Vue模板;没有导入FastAPI、执行app.openapi、跑TestClient或真正写入SQLite。AST只能发现语法结构问题,不能验证注解解析、路由注册、Pydantic实际转换、依赖释放或锁竞争。当前测试方法覆盖创建/读取/删除/持久化、输入拒绝、冲突回滚、容量释放、忙锁恢复和并发唯一性,但都仍是待执行规格。
练习
- 增加 GET /summary 返回分组整数分总额,先写schema和空账本规格,再决定事务快照范围。
- 把容量检查移到BEGIN前,写出两个请求都看到99条的交错时序。
- 对重复reference但不同金额,当前协议如何回答?若要幂等重放,需要保存并比较哪些内容?
- 新增备注字段时,列出实现、契约、数据库迁移和测试规格的修改点。
参考答案
summary应保持整数分输出;一次SELECT GROUP BY可取得该语句一致的读取结果,多条读取则需定义一致快照。检查放事务外时两个请求都通过容量判断,串行INSERT仍可累计到101;写者串行不等于检查已被纳入事务。当前不同payload相同reference仍409;幂等重放需要明确请求摘要、结果保存、冲突状态及保留期限,不能直接改成返回旧行。备注要同时改模型、输入输出schema、表结构迁移与长度/Unicode/未知字段负例;CREATE TABLE IF NOT EXISTS不会迁移旧表。
继续阅读
- 知识专题
- 排错
- 排错