# RESTful API设计与FastAPI实战
原理说明:
典型示例:
关键代码 (FastAPI路由设计):
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
username: str
email: str
class UserUpdate(BaseModel):
email: str | None = None
# 模拟数据库
fake_db = {}
counter = 1
@app.get("/users", status_code=status.HTTP_200_OK)
async def get_users():
return list(fake_db.values())
@app.post("/users", status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate):
global counter
user_id = counter
fake_db[user_id] = {"id": user_id, **user.model_dump()}
counter += 1
return fake_db[user_id]
@app.patch("/users/{user_id}", status_code=status.HTTP_200_OK)
async def update_user(user_id: int, user: UserUpdate):
if user_id not in fake_db:
raise HTTPException(status_code=404, detail="User not found")
existing = fake_db[user_id]
update_data = user.model_dump(exclude_unset=True)
existing.update(update_data)
return existing
2. FastAPI依赖注入 (Dependency Injection)
依赖注入是FastAPI最强大的特性之一,它允许你将重复的逻辑(如数据库会话、认证校验、分页参数)抽象为可复用的函数或类,从而避免代码重复,提升可测试性。
原理说明:
- 定义一个函数(或类)作为依赖项,其参数声明方式与路径操作函数相同。
- 在路径操作函数中使用 `Depends()` 声明依赖项。
- FastAPI会在调用路径操作函数前自动解析并执行依赖项,并将返回值注入到函数参数中。
典型示例:提取公共的分页参数。
关键代码:
from fastapi import FastAPI, Depends, Query
app = FastAPI()
# 定义依赖项,返回分页参数
async def pagination_params(
page: int = Query(1, ge=1, description="页码"),
page_size: int = Query(10, ge=1, le=100, description="每页条数")
):
return {"page": page, "page_size": page_size}
@app.get("/items")
async def get_items(pagination: dict = Depends(pagination_params)):
# 模拟数据
items = [{"id": i, "name": f"Item {i}"} for i in range(1, 101)]
start = (pagination["page"] - 1) * pagination["page_size"]
end = start + pagination["page_size"]
return {
"page": pagination["page"],
"page_size": pagination["page_size"],
"total": len(items),
"items": items[start:end]
}
3. 认证与授权 (JWT)
API安全是重中之重。JWT(JSON Web Token)是目前最流行的无状态认证方案。FastAPI通过依赖注入可以优雅地实现Token校验与权限控制。
原理说明:
- **认证**:用户登录后,服务端验证凭据,签发一个包含用户身份信息的JWT Token。
- **授权**:客户端在请求头中携带 `Authorization: Bearer <token>`,服务端解码并验证Token,从中提取用户角色等信息,判断是否有权访问资源。
- **依赖注入**:将Token的解析与校验逻辑封装成一个依赖项,供需要认证的路由使用。
典型示例:实现用户登录与受保护的路由。
关键代码 (需要安装 python-jose[cryptography] 和 passlib[bcrypt]):
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import JWTError, jwt
from datetime import datetime, timedelta
app = FastAPI()
security = HTTPBearer()
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# 模拟用户数据
fake_users_db = {
"alice": {"username": "alice", "password": "secret123", "role": "user"},
"admin": {"username": "admin", "password": "admin123", "role": "admin"}
}
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
# 认证依赖项
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise HTTPException(status_code=401, detail="Invalid token")
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
user = fake_users_db.get(username)
if user is None:
raise HTTPException(status_code=401, detail="User not found")
return user
@app.post("/login")
async def login(username: str, password: str):
user = fake_users_db.get(username)
if not user or user["password"] != password:
raise HTTPException(status_code=400, detail="Incorrect username or password")
access_token = create_access_token(data={"sub": user["username"], "role": user["role"]})
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
4. 自动API文档
FastAPI基于OpenAPI规范,可以自动生成交互式API文档,无需手动编写。这极大地提升了前后端联调与API测试的效率。
原理说明:
- FastAPI在启动时,会根据所有路由定义、请求/响应模型自动生成一个符合OpenAPI 3.0规范的JSON文档。
- 框架内置了两个文档界面:Swagger UI (`/docs`) 和 ReDoc (`/redoc`),开发者可直接在浏览器中查看、测试API。
关键代码 (无需额外配置,启动后访问 /docs 即可):
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="My API", version="1.0.0", description="这是一个示例API")
class Item(BaseModel):
name: str
price: float
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
return item
二、实操步骤
目标:搭建一个支持用户注册、登录、文章CRUD的RESTful API服务。
步骤1:项目初始化与环境配置
mkdir fastapi_blog && cd fastapi_blog
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install fastapi uvicorn python-jose[cryptography] passlib[bcrypt] pydantic
步骤2:创建项目结构
.
├── main.py # 应用入口
├── models.py # Pydantic模型
├── dependencies.py # 依赖项(认证、分页)
└── routers/
├── users.py # 用户路由
└── posts.py # 文章路由
步骤3:实现用户认证逻辑
在 dependencies.py 中实现 get_current_user 依赖(参考上文代码)。在 routers/users.py 中实现注册(POST /register)和登录(POST /login)接口。
步骤4:实现文章CRUD
在 routers/posts.py 中实现文章资源API。注意:创建文章需要认证(依赖 get_current_user),更新和删除只能由文章作者操作。
步骤5:在main.py中组装应用
from fastapi import FastAPI
from routers import users, posts
app = FastAPI(title="Blog API", docs_url="/docs")
app.include_router(users.router, prefix="/users", tags=["Users"])
app.include_router(posts.router, prefix="/posts", tags=["Posts"])
步骤6:启动并测试
uvicorn main:app --reload
打开浏览器访问 http://127.0.0.1:8000/docs,使用Swagger UI测试所有接口。
三、常见问题与故障排查
1. 问题:Depends() 依赖项中的参数未正确解析
原因:依赖项函数参数类型或默认值声明有误,导致FastAPI无法正确从请求中提取参数。
解决:检查依赖项函数是否使用了 Query、Path、Body 等参数校验工具,并确保参数名与预期一致。
2. 问题:JWT Token验证失败,返回401
原因:密钥不一致、Token过期、Token格式错误(缺少"Bearer "前缀)。
解决:确认服务端 SECRET_KEY 与签发时一致;检查Token是否过期;确保请求头格式为 Authorization: Bearer <token>。
3. 问题:Pydantic模型校验失败,返回422 Unprocessable Entity
原因:请求体JSON字段类型或格式不符合模型定义(如字符串传了数字)。
解决:仔细阅读错误信息,定位具体字段;检查前端发送的数据类型是否正确。
4. 问题:pip install 时 python-jose 或 passlib 报错
原因:Python环境缺少编译依赖或版本冲突。
解决:确保已安装最新的 pip (pip install --upgrade pip);尝试使用 pip install python-jose[cryptography] (注意方括号)。
5. 问题:自动文档 /docs 页面加载不出来或显示空白
原因:Swagger UI资源加载失败(网络问题)或FastAPI版本过低。
解决:检查网络连接;升级FastAPI到最新版 (pip install --upgrade fastapi)。
四、总结与扩展学习
核心要点:
- RESTful设计应遵循资源模型、HTTP动词与状态码的语义规范。
- FastAPI的依赖注入系统是构建可复用、可测试代码的关键,尤其适用于认证、分页等横切关注点。
- JWT是实现无状态认证的成熟方案,结合FastAPI的依赖注入可优雅地实现权限控制。
- FastAPI的自动文档功能是开发效率的倍增器,应善加利用。
扩展学习方向:
- **数据库集成**:学习使用SQLAlchemy或Tortoise-ORM与FastAPI集成,替代内存数据库。
- **高级认证**:探索OAuth2协议(如GitHub、Google登录)在FastAPI中的实现。
- **异步与性能**:深入学习FastAPI的异步特性,结合异步数据库驱动(如asyncpg)提升并发能力。
- **测试**:学习使用 `pytest` 和 `httpx` 编写FastAPI的单元测试与集成测试。
- **部署**:研究使用Docker容器化FastAPI应用,并配合Nginx反向代理与Gunicorn/Uvicorn进行生产部署。