FastAPI项目结构与异步架构设计
FastAPI是Python生态中性能最优秀的Web框架之一,基于Starlette异步引擎和Pydantic数据校验,原生支持async/await。与Flask的同步模型不同,FastAPI从底层就是异步架构,I/O密集型场景(数据库查询、HTTP调用、文件读写)用async def可获得数倍吞吐量提升。项目结构推荐按功能模块分层:
project/
├── app/
│ ├── main.py # FastAPI实例与中间件注册
│ ├── core/
│ │ ├── config.py # Settings配置
│ │ ├── security.py # JWT/密码哈希
│ │ └── deps.py # 公共依赖注入
│ ├── api/
│ │ ├── v1/
│ │ │ ├── router.py # 路由汇总
│ │ │ ├── users.py # 用户接口
│ │ │ └── articles.py # 文章接口
│ ├── models/ # SQLAlchemy模型
│ ├── schemas/ # Pydantic Schema
│ ├── services/ # 业务逻辑层
│ └── crud/ # 数据访问层
├── alembic/ # 数据库迁移
├── tests/
└── pyproject.toml
Pydantic V2数据校验与Schema设计
Pydantic V2用Rust重写校验核心,性能比V1提升5-50倍。Schema设计遵循”请求/响应分离”原则,避免一个Schema承担多种职责:
from pydantic import BaseModel, Field, ConfigDict
from datetime import datetime
from enum import Enum
class ArticleStatus(str, Enum):
draft = "draft"
published = "published"
archived = "archived"
# 请求Schema:严格校验输入
class ArticleCreate(BaseModel):
model_config = ConfigDict(strict=True)
title: str = Field(min_length=1, max_length=200, description="文章标题")
content: str = Field(min_length=10, description="正文内容")
category_id: int = Field(gt=0, description="分类ID")
tags: list[str] = Field(default_factory=list, max_length=5)
status: ArticleStatus = ArticleStatus.draft
# 更新Schema:所有字段可选
class ArticleUpdate(BaseModel):
title: str | None = Field(default=None, min_length=1, max_length=200)
content: str | None = Field(default=None, min_length=10)
status: ArticleStatus | None = None
# 响应Schema:包含服务端生成的字段
class ArticleResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
title: str
content: str
status: ArticleStatus
author_id: int
created_at: datetime
updated_at: datetime | None = None
from_attributes=True让Pydantic直接从SQLAlchemy ORM对象提取字段值,无需手动转换。strict=True禁止自动类型转换(如字符串”123″不会自动转为int 123),防止模糊输入通过校验。
依赖注入系统设计与复用模式
FastAPI的依赖注入(Dependency Injection)是代码复用的核心机制。依赖可以是函数、类、或生成器,通过Depends()声明。依赖支持嵌套——一个依赖可以依赖另一个依赖,形成依赖链:
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
# 数据库会话依赖(生成器模式,确保连接释放)
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with async_session_factory() as session:
yield session
# 当前用户依赖(依赖数据库会话)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
) -> User:
payload = decode_jwt(token)
user = await db.get(User, payload["user_id"])
if not user or not user.is_active:
raise HTTPException(status_code=401, detail="Invalid credentials")
return user
# 管理员权限依赖(依赖当前用户)
async def get_current_admin(
user: User = Depends(get_current_user)
) -> User:
if user.role != "admin":
raise HTTPException(status_code=403, detail="Admin required")
return user
# 接口中使用
@router.put("/articles/{article_id}")
async def update_article(
article_id: int,
data: ArticleUpdate,
user: User = Depends(get_current_admin),
db: AsyncSession = Depends(get_db)
):
# user已确保是管理员
article = await crud.article.get(db, article_id)
...
依赖链:get_db -> get_current_user -> get_current_admin。每层添加自己的校验逻辑,接口函数只关注业务逻辑。依赖缓存:同一请求中多次Depends(get_db)只执行一次,返回同一个session对象,这是FastAPI默认行为。
中间件开发与请求生命周期钩子
中间件处理请求前后的通用逻辑:认证、日志、限流、CORS。FastAPI中间件基于Starlette中间件协议:
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import time
class ProcessTimeMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start = time.perf_counter()
response = await call_next(request)
elapsed = time.perf_counter() - start
response.headers["X-Process-Time"] = f"{elapsed:.3f}s"
return response
app = FastAPI()
app.add_middleware(ProcessTimeMiddleware)
# 异步中间件(更灵活,推荐)
@app.middleware("http")
async def log_requests(request: Request, call_next):
start = time.perf_counter()
response = await call_next(request)
elapsed_ms = (time.perf_counter() - start) * 1000
if elapsed_ms > 1000: # 慢请求告警
logger.warning(f"Slow request: {request.method} {request.url.path} took {elapsed_ms:.0f}ms")
return response
中间件执行顺序:最后添加的最先执行(洋葱模型)。CORS中间件通常最先添加(最外层),认证中间件后添加(更内层)。异常处理中间件应在最内层捕获业务异常返回结构化错误响应。
后台任务与异步操作优化
接口中存在耗时操作(发送邮件、生成报表、调用第三方API)时,用BackgroundTasks将耗时操作推迟到响应返回后执行,避免阻塞请求:
from fastapi import BackgroundTasks
async def send_welcome_email(user_email: str, username: str):
# 模拟耗时邮件发送
await email_service.send(to=user_email, template="welcome", data={"name": username})
@router.post("/users", status_code=201, response_model=UserResponse)
async def create_user(
data: UserCreate,
background_tasks: BackgroundTasks,
db: AsyncSession = Depends(get_db)
):
user = await crud.user.create(db, data)
background_tasks.add_task(send_welcome_email, user.email, user.username)
return user # 立即返回,邮件在后台发送
BackgroundTasks适合轻量异步任务。重量级任务(长耗时、需重试、需持久化)应使用Celery或ARQ等任务队列。FastAPI应用启动/关闭时的初始化和清理通过lifespan上下文管理器处理:
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
# 启动时:初始化数据库连接池、Redis连接
await init_db()
app.state.redis = await aioredis.create_redis_pool("redis://localhost")
yield
# 关闭时:释放资源
await app.state.redis.close()
await close_db()
app = FastAPI(lifespan=lifespan)
接口文档自动生成与版本管理
FastAPI自动生成OpenAPI 3.0文档,Swagger UI和ReDoc开箱即用。生产环境自定义文档信息:
app = FastAPI(
title="My API",
version="1.0.0",
description="业务系统REST API文档",
docs_url="/docs",
redoc_url="/redoc"
)
# API版本管理
from fastapi import APIRouter
api_v1 = APIRouter(prefix="/api/v1")
api_v2 = APIRouter(prefix="/api/v2")
# v1版本接口
@api_v1.get("/users/{user_id}")
async def get_user_v1(user_id: int):
...
# v2版本接口(响应结构变更)
@api_v2.get("/users/{user_id}")
async def get_user_v2(user_id: int):
...
app.include_router(api_v1)
app.include_router(api_v2)
版本管理策略:URL路径版本化(/api/v1、/api/v2)最直观,客户端改造成本低。Header版本化适合不想暴露版本号的场景。数据库Schema变更用Alembic管理迁移脚本,每个版本对应一个迁移文件,支持回滚。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/pythonfastapi-yi-bu-jie-kou-kai-fa-yu-yi-lai-zhu-ru-xi-tong/