1. 为什么选择FastAPI构建RESTful服务
第一次接触FastAPI是在三年前的一个紧急项目里,当时需要在一周内交付一个高性能的API网关。当我发现只用30行代码就实现了Flask需要100行才能完成的功能时,这个框架就彻底改变了我的技术选型习惯。
FastAPI最让我惊艳的是它的开发效率。还记得第一次看到自动生成的交互式文档时,团队前端工程师直接跳过接口对接会议,对着文档就开始调接口了。这背后是它对OpenAPI标准的完美支持,每个路由、参数和返回值都会实时反映在文档中。
性能方面,官方基准测试显示其请求处理速度与Go和Node.js持平。我做过一个实测:在2核4G的云服务器上,单个FastAPI实例能轻松支撑每秒3500+的并发请求。这得益于Starlette提供的异步支持和Pydantic的高效数据验证。
2. 五分钟搭建你的第一个API服务
让我们从最基础的"Hello World"开始。先确保你的Python版本≥3.7,然后执行:
pip install fastapi uvicorn[standard]
新建main.py文件,输入以下代码:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
启动服务只需要一行命令:
uvicorn main:app --reload
这里有几个关键点需要注意:
--reload参数启用热重载,适合开发环境main:app表示从main.py导入app实例- 默认监听8000端口,可通过
--port修改
访问http://127.0.0.1:8000/items/42?q=test,你会立即看到JSON格式的响应。这种即时反馈正是快速开发的关键。
3. 自动化文档的魔法
启动服务后,FastAPI已经自动生成了两套文档系统:
- Swagger UI:
http://127.0.0.1:8000/docs - ReDoc:
http://127.0.0.1:8000/redoc
在最近的一个电商项目中,我们利用这个特性省去了80%的接口文档编写工作。Swagger UI最实用的功能是直接测试接口,你可以:
- 点击"Try it out"按钮
- 修改参数值
- 查看实时响应
背后的技术栈值得了解:
- OpenAPI规范定义API结构
- JSON Schema描述数据格式
- Starlette处理HTTP请求
- Pydantic负责数据校验
试着在代码中添加类型提示,比如将item_id标注为int,你会发现文档会自动更新参数类型,并在传入错误类型时返回清晰的验证错误。
4. 进阶路由与请求处理
实际项目中的路由往往更复杂。下面是一个商品管理API的典型结构:
from fastapi import Path, Query
from typing import Optional
@app.get("/products/{category}")
async def get_products(
category: str = Path(..., min_length=3),
page: int = Query(1, gt=0),
size: int = Query(10, le=100)
):
return {"category": category, "pagination": {"page": page, "size": size}}
@app.post("/products/")
async def create_product(item: dict):
# 实际项目这里应该用Pydantic模型
return {"status": "created", "item": item}
几个实用技巧:
- 使用
Path和Query添加额外验证规则 - 路径参数放在URL中(
/products/{category}) - 查询参数通过
?page=1&size=10形式传递 - POST请求自动解析请求体为Python字典
遇到过的一个坑:当URL参数包含特殊字符时,一定要用urllib.parse.quote处理,否则可能引发路由匹配失败。
5. 数据验证与Pydantic模型
真实项目中最容易出问题的就是数据校验。FastAPI通过Pydantic让这件事变得简单:
from pydantic import BaseModel, Field
from datetime import datetime
class Product(BaseModel):
name: str = Field(..., min_length=2, max_length=100)
price: float = Field(gt=0)
tags: list[str] = []
created_at: datetime = Field(default_factory=datetime.now)
@app.post("/products/")
async def create_product(product: Product):
return product
这个模型会:
- 确保name是2-100个字符的字符串
- 验证price必须大于0
- 自动转换请求体JSON为Product实例
- 为created_at设置默认值
在金融项目中,我们甚至用Pydantic实现了复杂的业务规则校验,比如:
class Transaction(BaseModel):
amount: float
currency: str
@validator('currency')
def check_currency(cls, v):
if v not in ['USD', 'EUR', 'CNY']:
raise ValueError('Unsupported currency')
return v.upper()
6. 错误处理与中间件
规范的错误处理能让API更健壮。FastAPI提供了多种错误处理方式:
from fastapi import HTTPException, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={"detail": exc.errors(), "message": "Validation failed"},
)
@app.get("/secret")
async def read_secret(token: str = Header(...)):
if token != "mysecrettoken":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid authentication token",
)
return {"message": "Secret data"}
中间件则适合处理跨切面关注点:
from fastapi import Request
import time
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
在日志系统中,我们组合使用中间件和依赖项,实现了完整的请求链路追踪。
7. 依赖注入系统
这是FastAPI最强大的特性之一。假设多个路由都需要数据库连接:
from fastapi import Depends
async def get_db():
db = DatabaseSession()
try:
yield db
finally:
db.close()
@app.get("/users/")
async def read_users(db: Database = Depends(get_db)):
return db.query(User).all()
更复杂的依赖关系也能优雅处理:
def query_params(
q: Optional[str] = None,
skip: int = 0,
limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(params: dict = Depends(query_params)):
return params
在微服务架构中,我们常用依赖项来处理:
- 数据库会话管理
- 权限验证
- 请求限流
- 缓存处理
8. 安全与认证
API安全不容忽视。FastAPI内置了多种安全方案:
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/protected/")
async def protected_route(token: str = Depends(oauth2_scheme)):
return {"token": token}
实现JWT认证的完整示例:
from jose import JWTError, jwt
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
实际部署时还要注意:
- 使用HTTPS加密传输
- 设置合理的token过期时间
- 实现refresh token机制
- 记录安全日志
9. 测试与部署
完善的测试是质量的保证。FastAPI的测试客户端让测试变得简单:
from fastapi.testclient import TestClient
client = TestClient(app)
def test_read_item():
response = client.get("/items/42?q=test")
assert response.status_code == 200
assert response.json() == {"item_id": 42, "q": "test"}
对于部署,我推荐两种方案:
- 容器化部署(Docker + Uvicorn)
FROM python:3.9
RUN pip install fastapi uvicorn
COPY ./app /app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
- 云原生部署(Kubernetes)
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi-app
spec:
replicas: 3
template:
spec:
containers:
- name: app
image: your-registry/fastapi-app
ports:
- containerPort: 80
性能调优建议:
- 使用Gunicorn管理Uvicorn worker
- 启用HTTP/2支持
- 配置合适的超时时间
- 启用压缩中间件
10. 真实项目经验分享
在最近的一个物联网平台项目中,我们遇到高并发下的性能瓶颈。通过以下优化将QPS从500提升到3500+:
- 使用异步数据库驱动(asyncpg替代psycopg2)
- 将频繁访问的数据加入Redis缓存
- 用
@lru_cache装饰器缓存配置数据 - 启用响应压缩
另一个电商项目的教训:Pydantic模型在嵌套结构较深时,验证可能成为性能瓶颈。解决方案是:
- 简化数据结构
- 对已知安全的数据关闭详细验证
- 使用自定义验证器替代自动验证
调试技巧:当遇到奇怪的行为时,检查app.openapi_schema的内容,这能帮你理解FastAPI内部如何解析你的路由。
416



被折叠的 条评论
为什么被折叠?



