FastAPI 入门:一位架构师的后端开发实战笔记
开篇 · 为什么我要写这篇文章

我是一名后端架构师,过去几年一直在使用 Python 构建各类中小型服务。最初用的是 Flask,后来也尝试过 Tornado、Django REST Framework,直到去年在一个新项目中第一次引入了 FastAPI。
说实话,第一眼看到 FastAPI 的时候并没有太在意,觉得不过又是一个“轮子”。但随着项目的推进,它带来的生产力提升让我彻底改观。这次我想以一个开发者兼架构师的身份,把我在实际项目中使用 FastAPI 的经验分享出来,希望能帮到那些刚准备入门或还在犹豫要不要尝试 FastAPI 的朋友。
项目背景 · 新产品上线倒计时

去年公司决定启动一个新产品线,目标是为内部系统构建一套统一的数据接口服务,供多个前端应用(Web + App)调用。这个服务要具备高并发支撑能力,同时要求开发效率快、代码结构清晰、后期易于扩展。
当时我们在技术选型上讨论了很久,最后敲定了:
- 后端框架:FastAPI
- 数据库:PostgreSQL
- ORM:SQLAlchemy(配合 asyncpg)
- 身份认证:JWT + OAuth2
- 部署方式:Docker + Gunicorn + Uvicorn Worker
- 日志监控:ELK + Sentry
- 测试框架:pytest
选择 FastAPI 主要有几个原因:
- 支持异步编程模型,这对处理高并发请求非常关键;
- 自带类型提示和 OpenAPI 文档生成,对前后端协作非常友好;
- 社区活跃度高,生态逐渐完善;
- 我们希望用现代的语法风格来构建项目,减少 boilerplate 代码。
初期挑战 · 帧率不稳的开发节奏


虽然 FastAPI 官方文档很全,但真正上手的时候还是遇到了一些坑,特别是在早期架构设计阶段。
问题一:如何组织项目结构?
在初期,我们按照传统的 Flask 风格来组织代码——main.py 里直接写路由,逻辑函数分散在各个模块里。结果没多久就发现:
- 路由混乱,查找接口难;
- 同样功能的视图分散在不同文件里;
- 模块依赖复杂,测试困难;
- 无法很好地支持依赖注入和中间件复用。
解决方法:采用模块化+分层架构
我们参考了 Django 和 NestJS 的结构理念,重新调整了项目结构如下:
app/
├── main.py
├── config/ # 配置文件
├── core/ # 核心逻辑(权限、日志、异常处理)
├── models/ # SQLAlchemy Models
├── schemas/ # Pydantic Schemas
├── services/ # 业务逻辑封装
├── routers/ # 每个模块一个 router 文件
├── repositories/ # 数据操作封装
└── utils/ # 工具类函数
通过这种结构,可以做到:
- 接口职责分明;
- 业务逻辑与数据访问分离;
- 更容易做单元测试;
- 中间件、依赖项便于复用。
问题二:数据库查询性能差,响应慢
我们的 API 会频繁访问 PostgreSQL,某些聚合查询响应时间超过了预期,甚至在压力测试时出现了阻塞现象。
解决方案一:引入异步数据库连接
我们使用 asyncpg 作为 Postgres 的驱动,并将 SQLAlchemy 设置为异步模式(基于 SQLAlchemy 2.0 + async session)。这样就能在 FastAPI 的异步路由中使用 await 查询数据库了:
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
engine = create_async_engine(DATABASE_URL)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_db():
async with async_session() as session:
yield session
在路由中这样调用:
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalars().first()
return user

这一步优化后,平均响应时间降低了 30%以上。
解决方案二:加入缓存机制
对于一些低频更新但高频读取的数据(如配置表、状态字典等),我们引入了 Redis 缓存。使用的是 redis-py 的异步客户端,并结合 FastAPI 的依赖注入:
from fastapi import Depends
from redis import asyncio as aioredis
def get_redis():
return aioredis.from_url("redis://localhost")
在需要缓存的方法中注入 redis 实例即可实现快速读取。
持久化设计 · 真实场景中的数据库考量

FastAPI 并没有自带 ORM,所以我们选择了 SQLAlchemy(异步版)。下面是一些我们在实际使用中的实践经验:
1. 明确 Schema 分层结构
我们通常定义两套 Schema:
- Request Schema(Pydantic Model):用于请求参数校验;
- Response Schema(Pydantic Model):用于控制返回字段;
- Database Model(SQLAlchemy ORM Class):映射到数据库。
例如:
class UserCreate(BaseModel):
name: str
email: EmailStr
class UserOut(BaseModel):
id: int
name: str
email: EmailStr
created_at: datetime
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
created_at = Column(DateTime)
这样做有几个好处:
- 隔离了数据库模型和 API 模型,解耦更彻底;
- 提升可维护性(改数据库字段不影响外部 API);
- 更方便进行数据脱敏、权限控制等操作。
2. 复杂查询尽量交给数据库处理
有些同事习惯在 Python 层做一些 join 或 aggregate 操作,但这样很容易引起性能问题。我们在 Review Code 时强调:
“能写成 SQL 的,不要在 Python 里 filter。”
我们鼓励团队优先编写高效 SQL,并利用 SQLAlchemy 的表达式构造查询。比如一个复杂的多表查询:
query = select(Order).join(Order.user).where(User.status == 'active')
这种方式不仅性能好,还更容易被数据库优化器识别。
安全性与接口设计 · 保护你的每一寸边界
FastAPI 在安全方面的设计非常出色,提供了很多开箱即用的支持。我们主要做了以下几件事:
1. 强制输入校验
借助 Pydantic,我们在所有入口都加上了类型和格式检查:
class CreateUserRequest(BaseModel):
name: str
email: EmailStr
age: Optional[int] = Field(None, ge=0, le=150)
FastAPI 会自动进行校验并返回错误码,极大地提升了安全性。
2. 权限控制体系
我们采用了 JWT Token + OAuth2 的方案:
- 用户登录后获取 Token;
- 每个接口根据角色判断是否有权限;
- Token 使用加密签名防止篡改。
这部分我们用了 python-jose 库来做 JWT 加解密,结合 FastAPI 的依赖注入机制实现:
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id: int = payload.get("sub")
if user_id is None:
raise credentials_exception
token_data = TokenData(user_id=user_id)
except PyJWTError:
raise credentials_exception
user = get_user_by_id(db, user_id=token_data.user_id)
if user is None:
raise credentials_exception
return user
再在接口中这样使用:
@app.get("/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
上线后的表现与运维经验
我们这套服务最终部署在 AWS ECS 上,使用 Docker + Gunicorn + Uvicorn Worker 组合,共启用了 4 个 worker 进程(每个 worker 使用异步事件循环)。
性能表现
在压测过程中,单节点(t3.medium)QPS 可达 3k~4k,TP99 控制在 200ms 以内。对比之前使用 Flask 的项目(同样部署配置下),性能提升了约 2.8 倍。
日常运维
我们使用了以下几个关键工具来保障稳定性:
- Sentry:捕获未处理异常,追踪堆栈;
- Prometheus + Grafana:监控 QPS、延迟、错误率等指标;
- ELK Stack:统一日志管理;
- Fluent Bit:收集容器日志转发至 Kafka;
- 定期 DBVacuum:避免 Postgres 表膨胀。
特别要注意的一点是:FastAPI 默认的 debug 模式要关闭生产环境,否则容易暴露敏感信息。
另外,在部署时如果发现接口响应变慢,可以先排查是否因为同步 IO 阻塞了 event loop,特别是使用第三方库时要注意是否支持 async。
总结 · FastAPI 究竟适合什么项目?
FastAPI 是一种“现代化”的 Web 框架,它的设计理念非常贴近现代软件工程的最佳实践:
- 类型安全;
- 异步编程;
- 快速原型;
- 易于维护;
- 自动生成 OpenAPI 文档;
- 社区活跃,生态丰富。
如果你的项目满足以下条件之一,FastAPI 都值得尝试:
- 需要高性能异步处理(高并发场景);
- 团队注重类型安全(Type Hints 成员较多);
- 希望建立良好的 API 文档规范;
- 不想重复造轮子(自动生成接口文档、验证逻辑);
- 想提升后端开发效率。
当然,也不是说 FastAPI 就完美无缺。对于超大规模系统来说,Python + FastAPI 可能还不够硬核;但对于中小型系统、创业团队、微服务场景,它确实是一个非常好的选择。
给新手的一些建议
作为一个从其他框架转过来的老兵,我想给刚开始学 FastAPI 的朋友几点建议:
- 别一开始就追求速度:先把结构理清楚,后面写起来才顺;
- 认真对待类型注解:这是 FastAPI 的灵魂所在;
- 多用依赖注入:这是 FastAPI 最强大的设计之一;
- 重视测试:尤其是异步函数测试,一定要熟练掌握 pytest-asyncio;
- 合理设计数据库模型:避免反范式设计导致后期难以维护;
- 善用官方文档:虽然英文为主,但结构清晰、示例丰富;
- 参与社区学习交流:FastAPI 的中文资料还不算特别多,多看看 GitHub Issues、StackOverflow 上的真实案例很有帮助。
最后一句
FastAPI 真的让我在项目中感受到了“开发幸福感”,那种接口定义完就能跑通、文档自动生成、逻辑清晰可维护的感觉,是你亲手试过之后才会理解的。
如果你正准备开始一个后端项目,或者想换换口味体验一下新东西,不妨试试 FastAPI。它不会让你失望。
祝大家 coding 快乐! 🚀

评论 0