运动健康计步器手机版
30.07MB · 2025-09-22
在快速迭代的业务中,直接修改现有API接口会导致向后不兼容——老版本客户端(如APP、前端页面)因为依赖旧接口的响应格式或逻辑,会出现崩溃、数据错误等问题。多版本API的本质是在不破坏既有服务的前提下,为新需求提供独立的功能入口,典型场景包括:
FastAPI的路由隔离机制是多版本API的核心支撑:通过APIRouter
将不同版本的接口逻辑封装为独立模块,再通过prefix
(路由前缀)区分版本。例如:
/v1/
路径下;/v2/
路径下。当请求到达时,FastAPI会根据URL前缀自动路由到对应版本的APIRouter
,确保不同版本的接口逻辑完全隔离,不会互相干扰。
我们通过两个独立的APIRouter
分别定义v1和v2版本的接口,再将它们注册到主应用中。以下是完整代码:
需安装的第三方库:
pip install fastapi==0.112.1 pydantic==2.8.2 uvicorn==0.30.5
# main.py
from fastapi import FastAPI, APIRouter
from pydantic import BaseModel, Field
from typing import Optional
# --------------------------
# 1. 定义版本化数据模型(Pydantic)
# --------------------------
# v1版本:基础用户模型(仅包含核心字段)
class UserV1(BaseModel):
id: int = Field(..., description="用户唯一ID")
name: str = Field(..., max_length=50, description="用户姓名")
# v2版本:扩展用户模型(继承v1并添加新字段)
class UserV2(UserV1): # 继承v1模型,保持向后兼容
email: str = Field(..., regex=r"^[w.-]+@[w.-]+.w+$", description="用户邮箱")
phone: Optional[str] = Field(None, max_length=11, description="手机号(可选)")
# --------------------------
# 2. 定义版本化路由(APIRouter)
# --------------------------
# v1版本路由:处理基础用户逻辑
router_v1 = APIRouter(prefix="/v1", tags=["v1版本接口"]) # tags用于Swagger文档分类
@router_v1.get("/users/{user_id}", response_model=UserV1)
def get_user_v1(user_id: int):
"""v1版本:获取用户信息(仅返回id和姓名)"""
# 模拟数据库查询(实际应替换为DB操作)
return {"id": user_id, "name": f"用户_{user_id}"}
# v2版本路由:处理扩展用户逻辑
router_v2 = APIRouter(prefix="/v2", tags=["v2版本接口"])
@router_v2.get("/users/{user_id}", response_model=UserV2)
def get_user_v2(user_id: int):
"""v2版本:获取用户信息(返回id、姓名、邮箱、手机号)"""
# 模拟数据库查询(包含新字段)
return {
"id": user_id,
"name": f"用户_{user_id}",
"email": f"user_{user_id}@example.com",
"phone": f"1380013800{user_id % 10}" # 模拟手机号
}
# --------------------------
# 3. 注册路由到主应用
# --------------------------
app = FastAPI(title="多版本API示例", version="2.0")
# 注册v1和v2路由(通过prefix区分版本)
app.include_router(router_v1)
app.include_router(router_v2)
# 启动命令:uvicorn main:app --reload
上述代码中,UserV2
继承自UserV1
,这种设计的优势是:
id
、name
)无需重复定义;如果需要移除v1的字段(极端场景),则不建议使用继承,应重新定义独立模型——但这种情况会破坏向后兼容性,需谨慎操作。
多版本API的测试核心是确保各版本接口独立工作,且跨版本交互不会出错,具体分为两步:
使用pytest
和fastapi.testclient
编写单元测试,验证每个版本的接口是否符合预期:
# test_api.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_v1_get_user():
"""测试v1版本接口:返回正确的基础字段"""
response = client.get("/v1/users/1")
assert response.status_code == 200
assert response.json() == {"id": 1, "name": "用户_1"} # 仅包含v1字段
def test_v2_get_user():
"""测试v2版本接口:返回扩展字段"""
response = client.get("/v2/users/1")
assert response.status_code == 200
assert "email" in response.json() # 包含v2新增字段
assert "phone" in response.json()
兼容性测试需覆盖**“老客户端调用新接口”和“新客户端调用老接口”**两种场景:
email
和phone
);email
字段”的情况(如设置默认值或提示用户补充信息)。如果需要在不修改老接口的前提下为用户信息接口添加“邮箱”字段,FastAPI中最推荐的多版本实现方式是什么?为什么?
最推荐的方式:路由前缀+APIRouter
+Pydantic模型继承。
原因:
prefix="/v2"
将新接口与老接口完全分开,避免逻辑冲突;UserV2
继承UserV1
,减少重复代码且保持向后兼容;APIRouter
即可。v2版本的模型定义了必填字段(如email
),但请求未传递该字段;或字段格式错误(如email
不符合正则表达式)。
Field
定义:email
是否标记为...
(必填);email
需包含@
);email
改为可选字段(Optional[str] = None
)。两个版本的接口路径完全相同(如/users/{user_id}
),但未通过prefix
区分,导致FastAPI无法识别正确的路由。
APIRouter
在注册时添加了唯一的prefix
(如/v1
、/v2
);/users/{user_id}
,但prefix
不同则不会冲突)。tags
或description
在Swagger文档(/docs
)中明确展示各版本的区别;APIRouter
(如v1),减少代码冗余。梅赛德斯 - 迈巴赫 GLS 改款车型谍照曝光:格栅设计微调
日本 NTT Docomo 旗下 d 支付、Merpay 与微信支付互通,中国游客可直接扫码付款