FastAPI实战:待办事项API的增删改查全流程实现
FastAPI作为新一代Python Web框架,以其高性能、自动生成文档和类型提示支持等特性,成为构建现代Web API的首选工具。本文将通过一个完整的待办事项管理项目,深入探讨如何利用FastAPI快速实现路由的增删改查(CRUD)功能,覆盖从项目初始化到API测试的全流程。
一、项目初始化与环境配置
1.1 创建项目结构
使用pip install fastapi uvicorn安装核心依赖后,建议采用如下项目结构:
todo_api/├── main.py # 主入口├── models.py # 数据模型├── schemas.py # 请求/响应模型├── crud.py # 数据操作层└── requirements.txt # 依赖清单
这种分层设计遵循MVC模式,使代码更易于维护和扩展。
1.2 基础应用配置
在main.py中初始化FastAPI应用:
from fastapi import FastAPIfrom fastapi.middleware.cors import CORSMiddlewareapp = FastAPI(title="待办事项API", version="1.0.0")# 跨域配置(开发环境必备)app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_methods=["*"],allow_headers=["*"],)
二、数据模型设计
2.1 数据库模型(models.py)
使用Pydantic进行数据验证,结合SQLAlchemy(可选)进行持久化:
from pydantic import BaseModel, Fieldfrom typing import Optionalfrom datetime import datetimeclass TodoItem(BaseModel):id: Optional[int] = Field(default=None, description="自动生成ID")title: str = Field(..., min_length=3, max_length=50)description: Optional[str] = Field(default="", max_length=200)completed: bool = Falsecreated_at: Optional[datetime] = Field(default_factory=datetime.now)updated_at: Optional[datetime] = Field(default_factory=datetime.now)class Config:orm_mode = True # 支持SQLAlchemy模型转换
2.2 请求/响应模型(schemas.py)
分离创建和更新模型,提高接口灵活性:
from pydantic import BaseModelclass TodoCreate(BaseModel):title: strdescription: str = ""class TodoUpdate(BaseModel):title: Optional[str] = Nonedescription: Optional[str] = Nonecompleted: Optional[bool] = None
三、CRUD路由实现
3.1 内存存储实现(开发阶段)
使用Python字典模拟数据库:
from typing import Dict, Optionalfrom fastapi import HTTPExceptionfrom models import TodoItemdb: Dict[int, TodoItem] = {}current_id = 1def create_todo(item: TodoItem) -> TodoItem:global current_iditem.id = current_iddb[current_id] = itemcurrent_id += 1return itemdef get_todo(id: int) -> Optional[TodoItem]:return db.get(id)def update_todo(id: int, updates: TodoUpdate) -> Optional[TodoItem]:if id not in db:raise HTTPException(status_code=404, detail="Item not found")existing = db[id]update_data = updates.dict(exclude_unset=True)updated_item = existing.copy(update=update_data)db[id] = updated_itemreturn updated_itemdef delete_todo(id: int) -> bool:if id in db:del db[id]return Truereturn False
3.2 路由定义(main.py扩展)
from fastapi import APIRouter, Path, HTTPExceptionfrom schemas import TodoCreate, TodoUpdatefrom models import TodoItemfrom crud import create_todo, get_todo, update_todo, delete_todorouter = APIRouter(prefix="/todos", tags=["todos"])@router.post("/", response_model=TodoItem)def create_todo_item(item: TodoCreate):"""创建新的待办事项"""# 实际项目需在此转换模型todo_item = TodoItem(title=item.title, description=item.description)return create_todo(todo_item)@router.get("/{id}", response_model=TodoItem)def read_todo_item(id: int = Path(..., ge=1)):"""获取单个待办事项"""todo = get_todo(id)if not todo:raise HTTPException(status_code=404, detail="Item not found")return todo@router.put("/{id}", response_model=TodoItem)def update_todo_item(id: int, updates: TodoUpdate):"""更新待办事项"""return update_todo(id, updates)@router.delete("/{id}")def delete_todo_item(id: int):"""删除待办事项"""if not delete_todo(id):raise HTTPException(status_code=404, detail="Item not found")return {"message": "Item deleted successfully"}app.include_router(router)
四、高级功能实现
4.1 分页与过滤
from fastapi import Queryfrom typing import List@router.get("/", response_model=List[TodoItem])def read_todos(skip: int = Query(0, ge=0),limit: int = Query(10, le=100),completed: Optional[bool] = None):"""分页获取待办事项列表,支持完成状态过滤"""items = list(db.values())if completed is not None:items = [item for item in items if item.completed == completed]return items[skip : skip + limit]
4.2 依赖注入与认证
from fastapi import Depends, HTTPExceptionfrom fastapi.security import APIKeyHeaderAPI_KEY = "secret-key"api_key_header = APIKeyHeader(name="X-API-Key")def get_api_key(api_key: str = Depends(api_key_header)):if api_key != API_KEY:raise HTTPException(status_code=403, detail="Invalid API Key")return api_key@router.get("/secure/", response_model=List[TodoItem])def read_secure_todos(api_key: str = Depends(get_api_key)):"""需要API密钥的受保护端点"""return list(db.values())
五、测试与文档
5.1 自动生成API文档
FastAPI自动生成Swagger UI和ReDoc文档:
- 访问
/docs查看交互式Swagger界面 - 访问
/redoc查看标准化文档
5.2 单元测试示例
from fastapi.testclient import TestClientfrom main import appclient = TestClient(app)def test_create_todo():response = client.post("/todos/",json={"title": "Test Item", "description": "Test Description"})assert response.status_code == 200assert "id" in response.json()def test_read_todo():# 先创建测试项create_resp = client.post("/todos/",json={"title": "Read Test", "description": "Test Read"})todo_id = create_resp.json()["id"]# 读取测试response = client.get(f"/todos/{todo_id}")assert response.status_code == 200assert response.json()["title"] == "Read Test"
六、生产环境部署建议
- 持久化存储:替换内存存储为SQLite/PostgreSQL
- 异步支持:使用
databases库实现异步CRUD - 性能优化:
- 启用Uvicorn的
--workers参数 - 配置适当的超时设置
- 启用Uvicorn的
- 监控:集成Prometheus和Grafana
- 日志:使用结构化日志(如
loguru)
七、常见问题解决方案
7.1 跨域问题
确保正确配置CORS中间件,生产环境应限制具体域名:
app.add_middleware(CORSMiddleware,allow_origins=["https://yourdomain.com"],allow_methods=["GET", "POST", "PUT", "DELETE"],allow_headers=["*"],)
7.2 数据验证错误处理
FastAPI自动返回422错误,可通过异常处理器自定义:
from fastapi import Requestfrom fastapi.responses import JSONResponsefrom fastapi.exceptions import RequestValidationError@app.exception_handler(RequestValidationError)async def validation_exception_handler(request: Request, exc: RequestValidationError):return JSONResponse(status_code=422,content={"detail": exc.errors(), "body": exc.body},)
八、扩展建议
- 添加用户系统:集成OAuth2或JWT认证
- 附件支持:实现文件上传功能
- 定时任务:使用Celery处理逾期提醒
- WebSocket:实现实时状态更新
- GraphQL:通过Strawberry添加GraphQL支持
通过本文的完整实现,开发者可以快速掌握FastAPI的核心功能,构建出符合生产标准的Web API。实际项目中,建议结合具体需求进行模块化扩展,并始终遵循RESTful设计原则。FastAPI的自动文档和类型系统将显著提升开发效率和代码质量,是构建现代微服务的理想选择。