没确认的接口契约,前端别先固化
结论先行: 接口字段、状态值、返回结构和业务语义,属于契约,不是细节。契约的合法来源只有三个:已确认的接口文档、源码、用户确认。前端为联调进度按猜测写死的逻辑,债务不会在联调结束时自动消失——它会长期留在代码里,持续收租。
定义:什么是契约
契约是前后端之间关于数据的一切约定:字段名叫什么、类型是什么、状态枚举有哪些值、返回结构怎么嵌套、每个值代表什么业务语义。它不是"后端的事",前端代码里的每一行映射、每一个状态判断,都是在对契约投票。
确认的来源只有三个,按优先级排:已确认的接口文档;文档缺失或存疑时,看源码或运行实证;涉及业务口径的,由用户确认。除此之外的来源——口头约定、截图里抄来的、别的项目里见过的——都算未确认契约。
之所以要纪律,是因为前端往往是最早把契约"落地"成代码的人。联调时接口还不定,进度又催,前端先按猜测写死是常态。但猜测的代码和确认的代码长得一模一样,后人看不出区别,于是临时方案变成正式逻辑,没人再回头确认。
规则一:字段映射默认以已确认接口文档为准
映射逻辑的第一依据是接口文档,不是返回示例。返回示例可能是手工编的,可能只覆盖了 happy path。一个请求里"有哪些字段"看文档,"某次返回长什么样"看抓包,两件事不要混用。
文档缺失或明显过时,也不要顺手用"惯例"代替。"我们以前项目都这么叫"不是确认,三个合法来源里没这一条。过时的文档要么推动更新,要么降级成观察记录,明确标记它不算数。
规则二:不主动保留多套字段名兜底
这是最容易踩的坑。字段名不确定时,顺手写 res.data.name || res.data.title || res.data.label,觉得"兼容一下也无妨"。但这行代码一旦合并,就再也删不掉了:没人知道生产环境里到底哪一个字段在生效,删除任一套都可能是线上事故。契约不确定性的成本,被从"确认一次"推向了"维护永远"。
兜底只保留给"已确认需要兼容旧版本"的明确场景,并且要有删除时间或版本号。没有确认依据的多套映射,写的时候省三分钟,维护时每年都在交税。
规则三:定义缺失时先确认,再实现正式逻辑
没有定义就问:问接口方要口径,看源码找真相,请用户确认业务语义。确认了再写正式逻辑。
如果进度实在等不及,允许写临时逻辑,但必须显式标注为临时:TODO、注释、待办事项三件套一件不能少。临时逻辑最危险的形态不是"写得烂",而是"写得和正式逻辑一模一样",让人分不清。标注是给未来自己的留白,也是给同事的提醒:这块逻辑的契约还没确认,改后端定义时要先回头看。
确认也要找对人。字段语义问接口方,业务口径问需求方,不要把"能跑通"当成"已确认"。联调跑通只证明这条路径上数据是对的,不证明状态值全集、异常分支和边界语义都对——这些正是文档和用户确认才覆盖得了的东西。
规则四:文档和实际返回不一致时,记下三样东西
文档怎么定义、实际返回是什么、当前代码如何处理——不一致出现时,把这三样写在同一个地方。
这件事之所以是纪律,是因为面对不一致,人的本能是选一个顺手的:"反正真实返回长这样,就按返回写吧"。但真实返回可能只是某个版本的偶然行为,按它固化等于把偶然变成了约定。把三样东西并列记下,风险就看得见:后续是推接口方改返回、改文档,还是改前端处理,每个决定都有依据。看不见冲突的团队,冲突不会消失,只会延迟到线上爆发。
收束
这四条规则的来源是多个前端项目交接时沉淀的共性经验:管理后台、H5 端、业务后台,项目不同,踩的坑是同一个——契约没确认就固化,固化之后就忘。记住一句话:先确认再固化,否则前端写的不是业务逻辑,是在替接口的可变性买单。