FastAPI 是一个现代、高性能的 Python Web 框架,广泛用于构建 API。它以其异步支持、自动生成交互式文档以及类型检查等特性受到开发者的喜爱。FastAPI 的强大功能离不开其两大核心组件:Starlette 和 Pydantic。本文将详细介绍这两大组件的作用、特性,并通过实例展示它们在 FastAPI 中的应用。
一、Starlette:FastAPI 的异步基石
1.1 什么是 Starlette?
Starlette 是一个轻量级的 ASGI(Asynchronous Server Gateway Interface)框架,专为构建异步 Web 应用设计。它是 FastAPI 的底层框架,提供了路由、请求处理、中间件、WebSocket 支持等核心功能。Starlette 的设计目标是简单、高效,同时保持足够的灵活性,适用于各种 Web 开发场景。
1.2 Starlette 的核心特性
- • 异步支持:基于 Python 的 asyncio,支持异步 I/O 操作,适合高并发场景。
- • 路由系统:提供直观的路径操作装饰器,用于定义 API 端点。
- • 请求与响应处理:内置对 HTTP 请求和响应的支持,支持 JSON、表单数据等格式。
- • 中间件:允许开发者在请求处理前后添加自定义逻辑。
- • WebSocket 支持:支持实时双向通信,适用于聊天应用等场景。
1.3 Starlette 在 FastAPI 中的作用
FastAPI 直接继承了 Starlette 的所有功能,例如路由、请求处理和中间件。FastAPI 的 @app.get()、@app.post() 等装饰器实际上是对 Starlette 路由系统的封装。换句话说,FastAPI 在 Starlette 的基础上增加了类型检查、自动文档生成等高级特性。
1.4 Starlette 示例
以下是一个简单的 Starlette 示例,展示如何定义路由和处理请求:
python
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
async def homepage(request):
return JSONResponse({"message": "欢迎使用 Starlette!"})
async def user(request):
user_id = request.path_params["user_id"]
return JSONResponse({"user_id": user_id})
app = Starlette(debug=True, routes=[
Route("/", homepage),
Route("/user/{user_id:int}", user),
])
# 运行方式:使用 uvicorn 启动
# uvicorn script_name:app --reload
在这个例子中:
- • 定义了两个路由:/ 返回欢迎信息,/user/{user_id:int} 返回动态的用户 ID。
- • 使用 JSONResponse 返回 JSON 格式的响应。
- • 通过 request.path_params 获取路径参数。
运行后,访问 http://127.0.0.1:8000/ 会返回 {"message": "欢迎使用 Starlette!"},访问 http://127.0.0.1:8000/user/123 会返回 {"user_id": 123}。
二、Pydantic:数据验证与序列化的利器
2.1 什么是 Pydantic?
Pydantic 是一个基于 Python 类型注解的数据验证和序列化库。它利用 Python 的类型提示(type hints)来定义数据模型,并提供强大的数据验证功能。Pydantic 在 FastAPI 中用于定义请求和响应的数据结构,确保数据的正确性。
2.2 Pydantic 的核心特性
- • 类型验证:自动检查数据是否符合定义的类型(如 int、str 等)。
- • 数据解析:将输入数据(如 JSON)转换为 Python 对象。
- • 默认值与可选字段:支持为字段设置默认值或标记为可选。
- • 嵌套模型:支持复杂的数据结构,例如嵌套对象和列表。
- • 错误提示:当数据不合法时,提供详细的错误信息。
2.3 Pydantic 在 FastAPI 中的作用
在 FastAPI 中,Pydantic 被用来定义 API 的请求体(request body)、查询参数(query parameters)和响应模型(response model)。FastAPI 会根据 Pydantic 模型自动验证输入数据,并在 Swagger UI 中生成交互式文档。
2.4 Pydantic 示例
以下是一个简单的 Pydantic 示例,展示如何定义数据模型并验证数据:
python
from pydantic import BaseModel, validator
from typing import Optional
class User(BaseModel):
name: str
age: int
email: Optional[str] = None
@validator("age")
def age_must_be_positive(cls, v):
if v < 0:
raise ValueError("年龄必须大于等于 0")
return v
# 测试数据验证
try:
user = User(name="Alice", age=25, email="[email protected]")
print(user.dict()) # 输出: {'name': 'Alice', 'age': 25, 'email': '[email protected]'}
invalid_user = User(name="Bob", age=-5) # 抛出异常
except ValueError as e:
print(e) # 输出: 1 validation error for User\nage\n 年龄必须大于等于 0
在这个例子中:
- • 定义了一个 User 模型,包含 name(必填)、age(必填)和 email(可选)字段。
- • 使用 @validator 添加了自定义验证逻辑,确保 age 不为负数。
- • user.dict() 将模型转换为字典,方便序列化。
2.5 Pydantic 的类型自动转换机制
Pydantic 不仅验证数据类型,还能在合理范围内自动将输入数据转换为目标类型。这种类型强制转换(type coercion)机制极大地提高了开发效率,尤其是在处理来自客户端的非严格类型数据时。
2.5.1 类型转换的规则
- • 字符串到数值:如果字段类型定义为 int 或 float,Pydantic 会尝试将字符串转换为对应的数值类型。
- • 布尔值转换:字符串 "true"、"false"、"1"、"0" 等会被转换为 bool 类型。
- • 嵌套对象:如果字段是另一个 Pydantic 模型,输入的字典数据会被递归解析。
- • 严格模式:可以通过 strict=True 关闭类型转换,要求输入数据严格匹配定义类型。
2.5.2 类型转换示例
以下是一个展示 Pydantic 类型转换的示例:
python
from pydantic import BaseModel
class Product(BaseModel):
id: int
price: float
is_available: bool
# 测试类型转换
data = {
"id": "123", # 字符串转换为 int
"price": "19.99", # 字符串转换为 float
"is_available": "1" # 字符串转换为 bool
}
product = Product(**data)
print(product.dict()) # 输出: {'id': 123, 'price': 19.99, 'is_available': True}
# 错误示例
try:
invalid_data = {"id": "abc", "price": "xyz", "is_available": "yes"}
Product(**invalid_data) # 抛出异常
except ValueError as e:
print(e) # 输出: 多个验证错误,提示无法转换 "abc" 到 int,"xyz" 到 float 等
在这个例子中:
- • id 从字符串 "123" 转换为整数 123。
- • price 从字符串 "19.99" 转换为浮点数 19.99。
- • is_available 从字符串 "1" 转换为布尔值 True。
- • 如果输入数据无法转换(例如 "abc" 到 int),Pydantic 会抛出详细的验证错误。
2.5.3 在 FastAPI 中的应用
类型转换机制在 FastAPI 中尤为重要,因为客户端发送的 JSON 数据通常是字符串格式。Pydantic 确保这些数据在进入业务逻辑之前被正确转换为目标类型,避免手动转换的繁琐工作。
三、FastAPI 中 Starlette 和 Pydantic 的结合
FastAPI 将 Starlette 的异步能力和 Pydantic 的数据验证完美结合,提供了简洁而强大的开发体验。以下是一个完整的 FastAPI 示例,展示两者的协同工作,并融入类型转换机制:
python
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
# 定义 Pydantic 模型
class Item(BaseModel):
name: str
price: float
stock: int
description: Optional[str] = None
# 创建 FastAPI 应用(基于 Starlette)
app = FastAPI()
# 定义路由
@app.get("/")
async def read_root():
return {"message": "欢迎使用 FastAPI!"}
@app.post("/items/")
async def create_item(item: Item):
return {"item": item.dict(), "status": "创建成功"}
# 运行方式:uvicorn script_name:app --reload
3.1 运行与测试
-
- 启动服务后,访问 http://127.0.0.1:8000/,返回 {"message": "欢迎使用 FastAPI!"}。
-
- 使用 POST 请求发送数据到 http://127.0.0.1:8000/items/,例如:
perl
{
"name": "苹果",
"price": "1.99", // 字符串将被转换为 float
"stock": "10", // 字符串将被转换为 int
"description": "新鲜水果"
}
返回
json
{
"item": {"name": "苹果", "price": 1.99, "stock": 10, "description": "新鲜水果"},
"status": "创建成功"
}
-
- 如果数据格式错误(例如 "price": "abc"),FastAPI 会返回详细的错误信息。
3.2 分析
- • Starlette 的作用:@app.get 和 @app.post 是 Starlette 路由系统的封装,异步函数支持高并发处理。
- • Pydantic 的作用:Item 模型定义了请求体的结构,自动将字符串 "1.99" 和 "10" 转换为 float 和 int,并验证数据合法性。
四、总结
Starlette 和 Pydantic 是 FastAPI 的两大支柱:
- • Starlette 提供了异步 Web 框架的基础设施,负责路由、请求处理和响应。
- • Pydantic 提供了数据验证、序列化和类型自动转换的能力,确保 API 的输入输出符合预期,同时减少开发者的手动转换工作。
通过两者的结合,FastAPI 实现了高性能、类型安全和开发者友好的特性。Pydantic 的类型自动转换机制尤其在处理非严格类型输入时表现出色,进一步提升了开发效率。
五、联系方式
- • 知识星球:创新技术阁
- • 公众号:ScienceStudio
- • Github: github.com/KandyYe
- • 知乎:www.zhihu.com/people/Scie...