接口字段契约检查 (ym-api-contract-diff)
把前后端接口约定一次性比对清楚:缺字段、多字段、类型不一致、必填与空值口径不同,并单独标出 Long 精度、日期格式这类一上线就埋雷的高风险项。核心价值是「不靠人肉一行行对字段」,也不给出「两边都差不多」的含糊结论。
何时使用
- 用户说「接口字段对不上」「前端说字段没有」「联调报错」「对比一下接口定义」「字段不一致」「api contract」时
- 用户贴出前端请求/响应 JSON 样例、后端 DTO/实体定义、或 OpenAPI/Swagger 片段,问「两边是不是一致」时
- 联调阶段前后端互相甩锅「是你没传 / 是你字段名错了」时
运行前提
- 脚本
scripts/diff_fields.py仅依赖 Python 标准库json,无需安装任何第三方包 - 适合直接喂 JSON 样例的两两比对;后端 Java DTO 文本、OpenAPI YAML 这类非 JSON 文本,由本技能在对话中按规则解析,不强制走脚本
- 不读取本地文件,除非用户明确给出路径;不联网、不通电请求真实接口
输入契约
| 项 | 必需 | 说明 |
|---|---|---|
| 接口描述(两侧) | 至少 1 份 | 前端 JSON 样例 / 后端 DTO 定义 / OpenAPI 片段,可组合提供 |
| 字段名映射规则 | 可选 | 如驼峰 ↔ 下划线;不提供则自动归一化 |
| 忽略字段列表 | 可选 | 明确不比对的字段(如分页包装 pageNo、traceId) |
缺失处理:
- 只有 1 份 → 只做「单份规范检查」(命名一致性、类型标注、必填说明),并在开头明确声明「仅 1 份,未做差异比对」
- 字段名风格不同(一侧驼峰、一侧下划线)→ 先做归一化,在报告里列出「归一化对照表」,不隐式改写原字段名
- 输入是图片/截图 → 说明暂不支持,请用户粘贴文本或复制字段清单
- 用户给的是 DTO 代码而非 JSON → 在对话里按
类型 字段名提取字段清单,再比对,不强行跑脚本
执行步骤
-
归拢两侧字段清单 — 每侧产出:字段路径、类型、是否必填、是否可为空、示例值。JSON 可直接用
scripts/diff_fields.py自动扁平化;DTO/OpenAPI 由本技能人工解析后填进字段表。 -
归一化 — 字段名按驼峰↔下划线归一到统一形式;类型按「类型族」归一(int/Integer/number → 数值族,String/string → 字符串族,详见
references/type-family-rules.md)。这一步必须先做,否则同名不同写法会被误判为两个字段。 -
差异分类 — 输出四类差异:
- 仅一侧有(漏字段 / 废弃字段)
- 两侧都有但类型族不一致(尤其 Long 精度、日期格式、枚举取值)
- 必填口径不一致(一侧必填、一侧可选)
- 空值口径不一致(一侧返回null、一侧直接不返回该字段) -
逐条给影响与建议 — 每条差异必须写:字段名 / 两侧取值 / 影响(会不会报错、会不会静默丢数据)/ 建议谁改(前端 or 后端)。不许只列差异不给结论。
-
单独标注高风险项 — Long 超出 JS 安全整数(2^53)、日期格式不明确、枚举值未对齐、金额用浮点,这些列进独立章节并标红,判定细则见
references/type-family-rules.md。 -
硬性约束 — 不修改任何源文件;不通电请求真实接口;不生成「两边都对」的含糊结论;差异条数必须与字段条数对账,不能漏比。
输出格式
Markdown,套用 templates/diff-report-template.md:
## 字段清单(归一化后)
| 字段(归一名) | 前端类型 | 后端类型 | 前端必填 | 后端必填 |
## 归一化对照表
| 原字段名(前端) | 原字段名(后端) | 归一名 |
## 差异表
| 字段 | 差异类型 | 两侧取值 | 影响 | 建议修改方 |
## 高风险项
| 字段 | 风险 | 影响 | 建议 |
## 建议修改方与改法
- 后端:...
- 前端:...
能力边界
- 不发起真实 HTTP 请求,不连数据库
- 不自动改代码或改接口定义文件
- 不声称覆盖所有语言的类型系统;首版限定 JSON / OpenAPI / 常见 Java DTO 写法
- 类型族归一只是「便于比对」的宽松归类,不能替代精确类型定义;精确类型(如
decimal(10,2))以高风险项形式单列
常见坑
-
驼峰下划线当成不同字段 — 现象:报告里
userId和user_id都被列为「仅一侧有」。原因:没做字段名归一化。规避:先跑第 2 步归一化并在对照表展示,确认是同一个字段再比对。 -
Long 当 number 放过 — 现象:类型为
Long的 ID 字段被判为「一致」,上线后前端拿到精度丢失的大整数。原因:只比类型族,没看具体类型。规避:凡出现long/Long/bigint一律进高风险项,提醒 JS 安全整数上限 2^53。 -
空值与缺失字段混为一谈 — 现象:后端返回
null前端按「字段不存在」处理,被漏判。原因:把「值为 null」和「字段不出现」当成一回事。规避:在字段清单里分别记录「可空」与「是否可能出现缺失」,第 3 步空值口径单独成类。 -
枚举只比对类型 — 现象:
status两侧都标 String 被判一致,实际前端枚举是0/1/2后端是ENABLED/DISABLED。原因:类型族归一掩盖了取值不一致。规避:枚举字段强制看取值集合,列入「枚举未对齐」高风险项。 -
日期格式不明 — 现象:
createTime前端期望yyyy-MM-dd HH:mm:ss,后端返回时间戳或 RFC3339,解析失败被漏判。原因:日期在类型族里常归为字符串被放过。规避:所有疑似日期字段进高风险项,要求明确格式与时区。 -
金额用浮点 — 现象:
amount标double/float被判一致,做加减后出现精度误差。原因:数值族归一把 double 和 decimal 都归为数值。规避:凡金额/价格字段出现浮点类型,进高风险项要求改用整数分或 decimal。
验收用例
- 正常:前端 JSON 样例 + 后端 DTO → 差异表齐全,含类型与必填差异,高风险项非空
- 边界 1:字段名一侧驼峰一侧下划线 → 归一化后比对,并列出对照表
- 边界 2:只有 OpenAPI 一份 → 只做规范检查,开头声明未做差异比对
- 失败:输入是截图 → 说明不支持,请用户提供文本
目录说明
scripts/diff_fields.py— 纯标准库脚本,输入两份 JSON(文件或内联)做字段名归一化与差异比对,输出 Markdown;scripts/setup.py当前无第三方依赖references/— 类型族归一化对照表与高风险项判定细则templates/— 差异报告输出模板