FastAPI 进阶:教你 APIRouter 模块化与 Pydantic 实战
前面的笔记我们快速过了一遍 FastAPI ,这篇开始将开始细分学习常用的两块内容:路由组织 和 请求体。
在实际开发当中,会遇到两个头疼的问题:
-
代码堆积: 所有的 API 都写在 main.py 里,几百行后根本找不到代码。
-
数据混乱: 前端传来的 JSON 格式不对
今天这篇内容,就是为了解决这两个痛点:APIRouter(路由组织) 与 Pydantic(请求体校验)。
文章目录
APIRouter(路由)
一、使用 APIRouter 模块化
当你的项目包含用户、订单、商品等多个模块时,APIRouter 就是你的“收纳盒”。
1、推荐的项目结构
project/
├── main.py # 程序入口,负责挂载路由
├── routers/ # 存放各个模块的逻辑
│ ├── init.py
│ ├── user.py # 用户相关接口
│ └── item.py # 商品相关接口
└── schemas/ # 存放数据模型(Pydantic Models)
2. 编写模块化路由(main.py)
main.py是整个项目的入口文件,所有的请求都会先经过这里,只负责初始化和路由挂载
利用 ** prefix** 和** tags ** 参数,可以极大地减少重复工作:
from fastapi import FastAPI
# 导入路由
from aps.Users import urls
# 1. 初始化路由器
app.include_router(urls.api_router,prefix="/users",tags=["用户管理"])
tags参数的体现如下图箭头所指:
3. 业务分流
在 分流文件当中,不使用 app = FastAPI(),而是使用 api_router = APIRouter()。这样,这一组 API 就可以像插件一样,随时插拔到主程序上。
from fastapi import APIRouter
# 路由干三件事:路由 = “网址 → 函数”的映射表
# 看路径(/users /login)
# 看请求方式(GET / POST)
# 决定调用哪个函数
# 创建路由
api_router = APIRouter()
# 创建功能函数(增删改查)
# 省略了/users 是因为在main函数中,路由已经定义了
@api_router.get('/{id}')
async def get_user(id: int):
return {
'id': id,
'name': '张三'
}
二、Pydantic(请求体校验)
在这里补充一个表格:
| 操作 | 方法 |
|---|---|
| 查找 | GET |
| 新增 | POST |
| 全改 | PUT |
| 局部改 | PATCH |
| 删除 | DELETE |
在处理** POST** 请求时,如果字段太多,用路径参数显然不现实。这时我们需要 Pydantic 模型来定义数据规范。
1、定义数据模型
实战代码实现:
from pydantic import BaseModel
# Pydantic模型:定义数据模型,进行数据验证和序列化
class User(BaseModel):
name: str
age: int
salary: float
telephone: str
@api_router.post('/add')
# 这个异步函数的作用是添加用户,接收一个User对象作为参数,这个User对象会自动进行数据验证,如果数据不符合要求,会返回一个错误信息
async def add_user(user: User):
print(user)
return {
'name': user.name,
'age': user.age,
'salary': user.salary,
'telephone': user.telephone,
'message': '添加成功'
}
2、测试方法(用 Swagger 或 Yaak):
方法:POST
路径:/add
FastAPI 会自动校验:
name、age、salary、telephone必须有
age 必须是整数
假如age传入的参数并非整数,则返回422错误并且打印哪里错了。如下图:
当然,传入的参数有其他错误时,也会报422错误。
3、Union类型
Union类型在Fastapi里边使用时,表示可以接受多种类型的参数
from typing import Union
# 而下面具体的函数里面定义了两个参数,name和age,name是路径参数,age是查询参数
@api_router.get('/search/{name}')
async def add_user(name: str, age:Union[int, None] = None):
print(name, age)
return {
'name': name,
'age': age
}
上述使用到的Union则是表示,age参数的数据类型可以是int,也可以是None,并且默认是None。
而现在多用以下这种表达形式:
@api_router.get('/search/{name}')
async def add_user(name: str,height:float | None = None):
print(name,height)
return {
'name': name,
'height': height
}
4、嵌套模型
假如用户里有地址,只需要多定义一个Address类:
class AddUser(BaseModel):
street: str
floor: int
class User(BaseModel):
name: str
age: int
salary: float
telephone: str
address: AddUser
这篇就先写到这里,内容聚焦在路由组织 + 请求体基础,部分代码是伪代码,运行时还需仔细辨别。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)