先记住这个答案
在 schema 字段上添加 @deprecated(reason: "..."),字段仍保留但内省标记废弃,客户端可获警告。废弃并非删除,直到确认无流量再移除,避免破坏现有查询。
- 用 @deprecated 标记而非立即删除字段
- 客户端通过内省或提示感知废弃
- 移除前需确认无客户端使用该字段
废弃标记与无版本演进的运作机制
GraphQL schema 中的字段通过 @deprecated(reason: "使用 nickname 替代") 指令标记废弃。在 SDL 中,该字段仍存在于类型上,服务端执行器照常处理请求。内省查询时,客户端可获得 deprecationReason 信息,但普通查询不会因此报错。这是非破坏性变更,旧查询继续有效。
无版本演进的核心是每个字段有生命周期:稳定期、废弃期、移除期。废弃期让客户端有时间迁移。服务端一般不主动删除字段,除非通过访问日志或持久化查询分析确认无查询引用。持久化查询(如将查询哈希存储)和访问日志可帮助统计字段使用频率,从而决定是否可安全移除。
用户资料 API 中用户名字段的迁移
假设 User 类型有 name 字段,现需拆为 firstName 和 lastName。增加新字段后,将 name 标为 @deprecated(reason: "使用 firstName 和 lastName")。现有移动客户端仍请求 name,服务端保留映射逻辑,返回拼接值。新客户端改用新字段,内省列表不再显示 name 为推荐字段。
三个月后通过访问日志统计到 name 的查询量降为零,此时从 schema 移除 name。若仍有零星请求,则继续保留。关键是决策基于流量数据,而非时间猜测。没有访问日志的小团队可延长废弃期,或通过客户端版本强制升级。
此策略不适用于的情况与代价
若字段是必填非空(如 String!),废弃但保留没问题。但若移除,某些查询会因字段缺失而校验失败。因此废弃时应同时提供替代字段,否则客户端无法安全迁移,且需预先避免让新客户端依赖废弃字段,不然会陷入无限保留。
另一种失效是客户端缓存了 schema 的内省结果,长期不更新,可能不知道字段已废弃,继续使用。此时只能硬性切断或使用别名兼容。移除字段本身是破坏性变更,应与所有已知客户端确认,不能仅凭内省标记自动处理。
容易答错的地方
- 把废弃当立即删除
- 有团队认为加了 @deprecated 就可在下个版本删掉,实际上删除会让现存客户端立刻失败。废弃是一个带明确理由的过渡状态,非删除许可。
- 忽略 reason 的内容
- 只写 @deprecated 而不给 reason,开发者不知替代方案。规范中 reason 参数可选,但建议提供明确指引。内省场景下缺少指引会延长迁移时间。
面试官还会怎么问?
如果客户端不更新,废弃字段能一直保留吗?
可以,但维护成本随字段数量上升。GraphQL 不强制删除,保留它们不影响新字段。长期不迁移者可考虑通过权限或请求头限制旧访问方式。
@deprecated 能用于接口或输入类型吗?
规范支持标记字段和枚举值,不直接标记类型。若要标记整个接口,只能在其所有字段上重复添加指令,或通过注释说明。
是否可在运行时根据客户端版本动态隐藏废弃字段?
不可靠,GraphQL 请求本身不含客户端版本信息。应使用 schema 版本控制或向所有客户端返回 field 存在,由客户端决定。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。