这份数据验证方案,可以让你的 FastAPI 崩溃率直降90%

上节说到:没有数据验证的API,就像没有保安的小区,什么"妖魔鬼怪"都能随便进出。

今天,我将通过构建一个"图书管理API"的实战案例,带你掌握用 FastAPI + Pydantic 打造"坚固" 后端服务的核心技巧,让你的接口从此告别脏数据的困扰!

数据验证:为API穿上"防弹衣"

为什么需要自动验证?

在传统开发中,我们需要写大量的if-else来判断数据合法性:

python 复制代码
if not isinstance(id, int):
    return {"error": "ID必须是整数"}
if rating < 1 or rating > 5:
    return {"error": "评分必须在1-5之间"}
# ...更多繁琐的判断

Pydantic 让这一切变得优雅、简单

上一小节中,我们构建了一个 BodyRequest(BaseModel) 对象。使用 Pydantic 给我们做一些自动化的检查。

python 复制代码
class BodyRequest(BaseModel):
    id: int
    title: str
    author: str
    description: str
    rating: int

今天,我们在这此基础上,使用 Pydantic 对每个字段添加自定义的数据验证。

python 复制代码
class BodyRequest(BaseModel):
    id: Optional[int] = Field(description="ID is not needed on create", default=None)
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0, lt=6)

我们回到浏览器的 Swagger UI 页面,刷新页面。我们进入 POST /create_book 接口,在请求体中使用如下内容,点击 "Execute",执行它。

json 复制代码
{
  "id": 0,
  "title": "",
  "author": "string",
  "description": "string",
  "rating": 1
}

**效果立竿见影:**当传入非法数据时,Pydantic 自动返回清晰的错误信息,HTTP状态码422(验证失败):

完整CRUD实战:从创建到删除

1、创建(Create)
python 复制代码
@app.post("/create_book")
async def create_book(book_reqeust: BodyRequest):
    new_book = Book(**book_reqeust.model_dump())
    BOOKS.append(find_book_id(new_book))
    return {"message": "图书创建成功!"}


def find_book_id(book: Book) -> Book:
    if len(BOOKS) > 0:
        book.id = BOOKS[-1].id + 1
    else:
        book.id = 1
    return book
2、查询(Read)
python 复制代码
# 按ID查询单本书
@app.get("/books/{book_id}")
async def read_book(book_id: int):
    for book in BOOKS:
        if book.id == book_id:
            return book
    return None


# 按评分查询书籍列表  
@app.get("/books/")
async def read_books_by_rating(book_rating: int):
    books_to_return = []
    for book in BOOKS:
        if book.rating == book_rating:
            books_to_return.append(book)
    return books_to_return
3、更新(Update)
python 复制代码
@app.put("/books/update_book")
async def update_book(updated_book: BodyRequest):
    for i in range(len(BOOKS)):
        if BOOKS[i].id == updated_book.id:
            BOOKS[i] = updated_book
            break
4、删除(Delete)
python 复制代码
@app.delete("/books/{book_id}")
async def delete_book(book_id: int):
    for i in range(len(BOOKS)):
        if BOOKS[i].id == book_id:
            BOOKS.pop(i)
            break

进阶技巧:巧用API文档

我们在前面已经对 BodyRequest(BaseModel) 的每个字段进行的自定义验证。

切回 Swagger UI 页面,找到 POST /create_book 接口,打开它。找到 "Request body" 下的 "Example Value" 。显然 "Example Value" 下的示例数据还是比较"简陋"的,如果线上使用的话不太合适。

现在,我们在 BodyRequest(BaseModel) 添加 model_config配置:

python 复制代码
class BodyRequest(BaseModel):
    id: Optional[int] = Field(description="ID is not needed on create", default=None)
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0, lt=6)
	# 新加内容
    model_config = {
        "json_schema_extra": {
            "example": {
                "title": "A new book",
                "author": "Mr.Wang",
                "description": "A new description of a book",
                "rating": 5
            }
        }
    }

回到浏览器的 Swagger UI 页面,刷新页面。找到 POST /create_book 接口,打开它。找到 "Request body" 下的 "Example Value" 内容如下:

可以看到 "Example Value" 的内容已经改变了。这回看着就比较专业了。

再回到浏览器的 Swagger UI 页面,找到 POST /create_book 接口,打开它。找到 "Request body" 下的 "Schema",点击它。

在这里,我们可以清晰的看到 "Request body" 中每个参数的验证类型和约束。这样,更方便前端测试。

写在最后

在本小节中,我们使用 Pydantic 完成繁琐的验证工作。

良好的类型提示,自动生成了API文档,彻底告别"代码写完还要写文档"的痛苦。

并且,在数据进入业务逻辑前就进行了验证,避免脏数据污染系统。

下节预告

本节中,我们在 BodyRequest(BaseModel) 中添加了类型验证和自定义验证。

但是,有些 API 接口并不使用 BodyRequest(BaseModel) ,那这些接口,我们应该如何完成我们验证需求呢?

欢迎 "关注",我们在下一小节一起来解锁这个问题。


-------- 写在最后 --------

关注我,每天1分钟,轻松懂 Python

我的同名公众号正在连载《FastAPI 开发实战》、《Python 核心技术》、《职场》。


点赞 :如果觉得有收获,点赞支持一下吧!

分享 :分享给身边同样对Python感兴趣的朋友!

关注我 :不要错过每一篇 Python 实战内容!


#Python #FastAPI #API #Web开发 #程序员 #编程教程 #效率提升 #后端开发 #API设计

相关推荐
woshikejiaih7 小时前
**播客听书与有声书区别解析2026指南,适配不同场景的音频
大数据·人工智能·python·音视频
深蓝海拓7 小时前
PySide6,QCoreApplication::aboutToQuit与QtQore.qAddPostRoutine:退出前后的清理工作
笔记·python·qt·学习·pyqt
Sagittarius_A*7 小时前
特征检测:SIFT 与 SURF(尺度不变 / 加速稳健特征)【计算机视觉】
图像处理·人工智能·python·opencv·计算机视觉·surf·sift
像风一样的男人@8 小时前
python --读取psd文件
开发语言·python·深度学习
薛定谔的猫喵喵8 小时前
天然气压力能利用系统综合性评价平台:基于Python和PyQt5的AHP与模糊综合评价集成应用
开发语言·python·qt
yuluo_YX8 小时前
Reactive 编程 - Java Reactor
java·python·apache
独好紫罗兰8 小时前
对python的再认识-基于数据结构进行-a004-列表-实用事务
开发语言·数据结构·python
ZH15455891318 小时前
Flutter for OpenHarmony Python学习助手实战:模块与包管理的实现
python·学习·flutter
choke2338 小时前
[特殊字符] Python异常处理
开发语言·python
玄同7659 小时前
从 0 到 1:用 Python 开发 MCP 工具,让 AI 智能体拥有 “超能力”
开发语言·人工智能·python·agent·ai编程·mcp·trae