跳到内容

API 兼容策略

API 兼容策略用于保证 Admin、App、PC、开放平台调用方和第三方集成方在版本升级时可预期、可灰度、可回滚。

核心原则

  • 所有 REST API 路由必须带版本号,统一使用 /api/v{major}/{domain}/**,例如 /api/v1/iam/**
  • 后台管理 API 对外统一使用 /api/v1/admin/{domain}/**,例如 /api/v1/admin/iam/users/api/v1/admin/mall/orders
  • 同一个版本内只做兼容扩展,不改变既有字段、语义、权限和错误码含义。
  • 破坏性变更必须进入新版本路径,例如 /api/v2/iam/**
  • HTTP 状态只表达传输层结果;业务成功或失败由 Result.code 表达。
  • Controller 返回 ResponseEntity<?>;普通 JSON 的响应体使用 Result<T>
  • 入参使用 DTO,出参使用 VO,不直接暴露 Entity。

版本放置

框架推荐把 API 主版本固定放在 /api 后面,业务域放在主版本后面:

text
/api/v{major}/{domain}/{resources}

这样可以让所有调用方第一眼看到 API 主版本,同时保持业务域在固定位置,网关、OpenAPI、前端 baseURL 和日志检索都更整洁。后端统一从 ApiRoutes.API_V1 派生域常量,未来调整主前缀时优先改少量公共常量,而不是散改 Controller。

后台管理接口在主版本后追加 admin 访问层:

text
/api/v{major}/admin/{domain}/{resources}

后台管理 API 直接挂载在真实 owning domain 下,例如 IAM 使用 /api/v1/admin/iam/**,Cashier 使用 /api/v1/admin/cashier/**,Open Platform 使用 /api/v1/admin/open-platform/**。开发期不再为旧后台路径保留兼容转发,新增 Controller 必须从公共路由常量派生真实域前缀。

不默认使用 Header 或 query 参数做版本选择,因为路径版本对浏览器调试、Nginx / 网关路由、OpenAPI 展示、日志排查和第三方接入更直观。

API 路径版本只表示接口契约主版本,不等同于项目发布版本。项目可以发布 1.0.3,但接口仍保持 /api/v1/iam/**;只有发生破坏性契约变化时才进入 v2

兼容外部协议的网关接口允许保留协议自身版本。例如 /api/v1/ai/gateway/claude/v1/messages 中,/api/v1 是框架 API 主版本,claude/v1 是 Claude / Anthropic Messages 协议版本,二者职责不同。

兼容变更

以下变更可以保留在当前版本内:

类型示例
新增可选请求字段DTO 增加 remark,未传时保持旧行为
新增响应字段VO 增加 displayName,老客户端可忽略
新增接口增加 /api/v1/iam/users/preferences
新增查询条件列表接口增加可选 keyword
新增枚举值客户端已按未知值兜底展示时可直接增加
新增业务码不改变旧 code 含义,只补充新场景

兼容变更仍需要同步 OpenAPI、正式文档和对应前端调用契约。

破坏性变更

以下变更必须进入新版本路径,或先提供迁移期双写 / 双读方案:

类型示例
删除字段移除 name,只保留 displayName
重命名字段userName 改为 username
改变字段语义status=1 从启用改为待审核
新增必填字段创建接口新增必填 type
改变路由或 HTTP 方法POST /create 改为 PUT /{id}
改变分页语义page 从 1 基改为 0 基
改变鉴权 / scope原公开接口变为强制登录
改变签名规则开放平台 canonical string 规则变化
改变错误码含义40001 从未登录改为参数错误

开发期虽然还未进入正式版兼容期,也应尽量按上述规则设计,避免 V1.0 前形成难清理的隐性债务。

请求与响应

普通 JSON 接口:

java
ResponseEntity<?> detail(@PathVariable Long id)

文件、流式、跳转等非 JSON 响应按场景返回:

java
ResponseEntity<Resource>
ResponseEntity<byte[]>
ResponseEntity<SseEmitter>

前端判断业务结果时只看 Result.code,不要通过 HTTP 4xx / 5xx 推导业务失败。

字段命名

  • Java DTO / VO 使用 camelCase。
  • 数据库列使用 snake_case。
  • API 查询字段优先使用 Java 属性名;需要兼容数据库列名时必须通过后端白名单归一化。
  • 不允许前端任意字段名直接拼 SQL、排序或过滤。
  • 业务展示字段优先返回 displayName / displayTitle / displayDescription,前端不维护后端业务元数据翻译表。

Open Platform

开放平台 API 面向第三方调用方,兼容要求更严格:

  • 版本路径、scope、签名算法、防重放规则必须写入文档。
  • canonical string、Header 名称、时间戳容忍窗口和错误码不能在同版本内改变。
  • 计量、配额、成本快照、账单和余额扣费相关字段必须可审计、可幂等。
  • 新增能力优先新增 scope,不复用语义不清的旧 scope。

Jar API 兼容检查

除 REST API 外,spring-open-starters/** 和对外复用的 spring-open-core/** 也要保持公开 Java API 可升级。发布前优先用发布脚本生成上一版本与当前版本的公共 jar 兼容检查命令:

bash
./scripts/release api-compat --previous-version 0.7.0

脚本只读,不会构建、提交、打 tag、推送或发布;它会根据上一版本 tag 和当前工作区交集生成 spring-open-starters/** / spring-open-core/** 模块列表,并输出隔离 Maven 仓库的安装上一版本与当前 japicmp verify 命令。

底层能力由 api-compat Maven profile 提供,可针对单个模块手工比对上一版本 jar 和当前构建产物:

bash
./mvnw -pl spring-open-starters/spring-open-starter-common -am verify \
  -Papi-compat \
  -DskipTests \
  -Dapi.compat.previousVersion=0.7.0

发布前如果本地仓库里没有上一版本,先用隔离目录构建上一 tag,避免污染当前工作区:

bash
API_COMPAT_ROOT="target/api-compat-$(date +%Y%m%d%H%M%S)"
API_COMPAT_REPO="$(pwd)/$API_COMPAT_ROOT/repository"
mkdir -p "$API_COMPAT_ROOT/v0.7.0"
git archive v0.7.0 | tar -x -C "$API_COMPAT_ROOT/v0.7.0"

(cd "$API_COMPAT_ROOT/v0.7.0" && \
  ./mvnw -pl spring-open-starters/spring-open-starter-common -am install \
    -DskipTests \
    -Dmaven.repo.local="$API_COMPAT_REPO")

./mvnw -pl spring-open-starters/spring-open-starter-common -am verify \
  -Papi-compat \
  -DskipTests \
  -Dapi.compat.previousVersion=0.7.0 \
  -Dmaven.repo.local="$API_COMPAT_REPO"

api-compat 只在显式启用时运行,不影响日常开发构建。默认检查 public API,发现二进制不兼容会失败;源码不兼容先输出报告,由维护者按发布口径判断是否需要进入新版本或补迁移说明。上一版本后新增的模块没有可比对旧 jar,发布说明中应按“新增公共 API”记录,不强行伪造兼容检查。

数据库迁移

  • 兼容迁移优先新增表、新增可空字段、新增索引。
  • 删除字段、改字段类型、改字段语义、数据不可逆迁移属于高风险操作。
  • Liquibase changeSet 尽量使用跨数据库写法;数据库特性必须用 dbms 限定。
  • 业务代码先兼容新旧数据形态,再考虑清理历史字段。

废弃流程

稳定版本后废弃接口按以下流程处理:

  1. 文档和 OpenAPI 标记 deprecated。
  2. 新接口提供等价能力和迁移说明。
  3. 保留至少一个小版本周期。
  4. 删除前在发布说明中明确列出影响范围。

V1.0 前可以更快清理未发布能力,但仍要同步 .ai/todo.md、正式文档和前端调用方。

发布检查

发布前检查:

  • 路由是否带 /api/v{major}/{domain}/**;后台管理入口是否使用 /api/v{major}/admin/{domain}/**
  • 是否有同版本破坏性字段、错误码或权限变更。
  • OpenAPI 是否能描述最新 DTO / VO。
  • 前端 Admin / App / PC 是否已同步接口 contract。
  • 新增配置、迁移、权限码和 i18n key 是否写入对应文档。
  • 破坏性变更是否进入新版本路径或有明确迁移方案。

Released under the Apache License 2.0.