深入理解 FastAPI 的路由与视图
FastAPI 是一个现代、高性能的 Python Web 框架,基于 Starlette 和 Pydantic,特别适合构建 RESTful API。它以异步支持、类型提示和自动生成交互式文档(如 Swagger UI)而著称。在 FastAPI 中,路由和视图是构建应用程序的核心部分。
1. 什么是路由和视图?
在 Web 开发中,路由是指将特定的 HTTP 请求(例如 GET、POST 等)映射到对应的处理函数的过程,而视图则是处理这些请求并返回响应的函数或方法。在 FastAPI 中,路由通过装饰器定义,视图则以 Python 函数的形式实现。
FastAPI 的路由设计非常直观,开发者只需使用装饰器(如 @app.get() 或 @app.post())指定路径和 HTTP 方法即可。视图函数可以是同步的,也可以是异步的,具体取决于业务需求。
2. 基本路由与视图
让我们从一个简单的例子开始,展示 FastAPI 如何定义路由和视图。
2.1 示例 1:基本 GET 请求
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}
解释:
- FastAPI() 创建一个应用实例。
- @app.get("/") 是一个装饰器,表示当客户端发送 GET 请求到根路径(/)时,调用 read_root 函数。
- read_root 是视图函数,返回一个 JSON 格式的响应。
运行这段代码后,访问 http://127.0.0.1:8000/,你将看到 {"message": "Hello, FastAPI!"}。
2.2 示例 2:带路径参数的路由
FastAPI 支持动态路径参数,通过在路径中定义变量并在视图函数中接收这些参数。
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
解释:
- {item_id} 是路径参数,FastAPI 会将其提取并传递给视图函数。
- item_id: int 使用类型提示,FastAPI 会自动验证参数类型并在类型不匹配时返回错误。
- 访问 http://127.0.0.1:8000/items/42,返回 {"item_id": 42}。
如果传入非整数(如 http://127.0.0.1:8000/items/abc),FastAPI 会返回 422 状态码和错误信息。
3. 查询参数与视图
除了路径参数,FastAPI 还支持查询参数(Query Parameters),这些参数通常附加在 URL 的 ? 后面。
3.1 示例 3:查询参数
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
解释:
- skip 和 limit 是查询参数,默认值分别为 0 和 10。
- 访问 http://127.0.0.1:8000/items/?skip=5&limit=20,返回 {"skip": 5, "limit": 20}。
- 如果不提供参数,则使用默认值,返回 {"skip": 0, "limit": 10}。
4. POST 请求与请求体
FastAPI 使用 Pydantic 模型来处理复杂的请求体数据,例如 JSON。
4.1 示例 4:POST 请求与 Pydantic 模型
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = None
@app.post("/items/")
def create_item(item: Item):
return {"item_name": item.name, "item_price": item.price, "is_offer": item.is_offer}
解释:
- Item 是一个 Pydantic 模型,定义了请求体的结构。
- @app.post("/items/") 表示处理 POST 请求。
- item: Item 接收 JSON 请求体并自动验证数据。
- 发送 POST 请求到 http://127.0.0.1:8000/items/,请求体为 {"name": "Book", "price": 9.99, "is_offer": true},返回 {"item_name": "Book", "item_price": 9.99, "is_offer": true}。
如果请求体的格式不符合 Item 模型,FastAPI 会返回详细的错误信息。
5. 异步视图
FastAPI 支持异步函数,这对于需要处理 I/O 操作(如数据库查询或外部 API 调用)的场景非常有用。
5.1 示例 5:异步视图
python
from fastapi import FastAPI
import asyncio
app = FastAPI()
@app.get("/async-example/")
async def async_example():
await asyncio.sleep(1) # 模拟异步操作
return {"message": "This is an async response"}
解释:
- 使用 async def 定义异步视图函数。
- await asyncio.sleep(1) 模拟一个耗时操作,例如数据库查询。
- 访问 http://127.0.0.1:8000/async-example/,会在 1 秒后返回响应。
异步视图特别适合高并发场景,能够显著提升性能。
6. 路径操作的更多选项
FastAPI 提供了丰富的路由选项,例如自定义状态码、响应模型和描述信息。
6.1 示例 6:自定义状态码与描述
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
username: str
email: str
@app.post("/users/", status_code=201, summary="Create a new user")
def create_user(user: User):
return {"username": user.username, "email": user.email}
解释:
- status_code=201 指定成功的状态码为 201(Created)。
- summary 提供路由的简短描述,会显示在自动生成的文档中。
- 发送 POST 请求到 http://127.0.0.1:8000/users/,请求体为 {"username": "john", "email": "[email protected]"},返回相应数据。
7. 综合实例:构建一个小型 API
让我们结合以上内容,构建一个简单的物品管理 API。
python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
app = FastAPI()
class Item(BaseModel):
id: int
name: str
price: float
# 模拟数据库
items_db = []
@app.post("/items/", status_code=201)
def create_item(item: Item):
for existing_item in items_db:
if existing_item.id == item.id:
raise HTTPException(status_code=400, detail="Item already exists")
items_db.append(item)
return item
@app.get("/items/", response_model=List[Item])
def list_items():
return items_db
@app.get("/items/{item_id}", response_model=Item)
def get_item(item_id: int):
for item in items_db:
if item.id == item_id:
return item
raise HTTPException(status_code=404, detail="Item not found")
解释:
- 定义了一个 Item 模型和一个模拟数据库 items_db。
- create_item:创建新物品,检查 ID 是否重复。
- list_items:返回所有物品列表,使用 response_model 指定返回类型。
- get_item:根据 ID 获取单个物品,未找到时抛出 404 错误。
运行后,你可以通过以下方式测试:
- POST http://127.0.0.1:8000/items/,请求体 {"id": 1, "name": "Pen", "price": 1.99}。
- GET http://127.0.0.1:8000/items/ 查看所有物品。
- GET http://127.0.0.1:8000/items/1 获取 ID 为 1 的物品。
8. 总结
FastAPI 的路由和视图机制简单而强大,结合类型提示和 Pydantic 模型,可以轻松构建健壮的 API。无论是简单的 GET 请求,还是复杂的异步操作,FastAPI 都能提供灵活的支持。