老旧的API,你应该如何处理?
点击“开发者技术前线”,选择“星标🔝”
让一部分开发者看到未来
万物都会有终结,HTTP API 也不例外。不论你的 API 今天看上去多么伟大,迟早有一天你会想发布一个全新的版本,新版本能更好地解决相同问题,在各方面可能都会有所改善,但是它因为有了新参数,与旧版本也无法兼容,或者你只是想彻底关闭旧的 API。总而言之,你现在的 API 不会永远存在。
但是,这并非轻而易举就能完成的,因为你的 API 有客户端。如果你关闭端点、参数或整个 API 而没有做出恰当的警告的话,那他们肯定会非常不爽。
那么,该怎样安全地关闭 API,让你的用户尽可能地感到轻松愉快呢?
在这方面,我们有正确的做事方式,包括两个新的头信息草案,它们正在被新的 IETF “Building Blocks for HTTP APIs”工作组进行标准化,旨在形成一个精确的过程。我们了解一下。
初始第一步:检查相关的 API 是否真的有客户端。
希望你能有某些 API 的度量指标,至少在某些地方存有日志。如果没有的话,那把它们添加上,如果你有这些东西的话,并且你能确定没有人再使用这个 API 了,那么恭喜你,你赢了。现在,你就可以把它关掉,删掉代码,不要再管这篇文章了,好好睡一觉。
下一个问题,如果比较遗憾,你无法去睡觉的话,那就要问问自己,除了关闭这个 API,还有没有其他方案。你关闭的所有东西都有可能破坏别人的代码,并且会消耗他们的时间来修复这些问题。如果 API 能继续运行的话,对客户端的生态系统和整个 web 的健康都是有好处的。
在很多场景下,旧的 API 可以在内部进行转换,透明地转化成对新 API 的调用,这样可以避免维护两个完全独立的版本。这是 Stripe 的 API 版本管理方式的一个基本组成部分,他们在所有发生变化的 API 中都包含了转换,以确保对不兼容的旧版本 API 的请求能继续像以前那样运行,根据需要自动转换请求和响应从而可以使用较新的代码。
https://stripe.com/blog/api-versioning#versioning-under-the-hood
这样的转换并不总是可行的,而且如果永远这样做的话会带来明显的额外复杂性,但是如果你可以做到这一点的话,就能为用户提供非常有价值的稳定性,并且可以节省大量废弃旧版本或维护旧版本相关的工作。
但是,如果这个服务 / 端点 / 参数已经用到了生产环境,而且继续支持它是不现实的做法,那么它必须要被淘汰。
要实现这一点,我们就要有一个计划。我们首先要问自己三个关键的问题:
你希望用户该怎么做?常见的答案包括:升级到相关功能的一个更新的、依然能得到支持的版本;使用一些可替代的端点 / 参数 / 服务;使用不同的服务,它们与你无关,不需要你关心。
用户应该何时迁离这个 API?你所提出的替代方案现在就可以用了吗?
截止时间是什么时候?也就是,这个 API 何时会完全停止使用?(如果不能完全确定的话,你可以稍微延迟回答这个问题)。
计划准备就绪之后,我们就该把它告诉人们了。
首先,要把这一决定告诉人们。
发邮件到邮件列表,在 Twitter 或微博上发帖,如果有 API 规范的话,对其进行更新(比如,OpenAPI 在 operations 和 parameters 上有一个deprecated
字段),并在相关的在线文档上大声强调这一点。
你应该包含上文提到的所有信息:他们应该做些什么作为替代方案,你建议他们什么时候开始迁移以及他们必须要进行迁移的最后期限(如果已经确定期限的话)。
在将这些信息告诉给人们后,接下来就该告诉计算机,而这就是新的 IETF 头信息可以发挥作用的地方。
Deprecation 头信息能告诉客户端请求的资源现在依然像以前那样运行,但是这种方式已经不再推荐使用了。
https://datatracker.ietf.org/doc/draft-ietf-httpapi-deprecation-header/?include_text=1
Deprecation: true
Deprecation: Thu, 21 Jan 2021 23:59:59 GMT
如果你要废弃整个端点或服务,那么你可以在每个响应中都带上这样的头信息。如果你想要废弃的是一个具体的特性,可能是一个参数、请求方法或者请求体中的某个特定字段的话,那么你应该在该特性被使用的时候才在响应中包含这个头信息。
为了给客户端更多的信息,我们还可以使用Link
HTTP 响应头信息链接至端点或人类易读的文档。在同一个Link
头信息中,我们可以包含多个这样的链接,只需要使用逗号进行分割即可(后面我们会看到一个完整的例子)。该规范定义了四个与 API 废弃相关的链接:
Link: <https://developer.example.com/deprecation>; rel="deprecation"; type="text/html"
这是告诉用户发生了什么以及他们该怎么办的主要方式。你应该始终使用它。如果还没有完整的详情和最终的关闭日期,那么即使只是一个占位符,这也是很有帮助的。在这种情况下,不要忘记让用户订阅更新,这可以采用邮件列表、RSS 或其他类似的方式来实现。
Link: <https://api.example.com/v10/customers>; rel="latest-version"
Link: <https://api.example.com/v2/customers>; rel="successor-version"
Link: <https://api.example.com/v2/users/123/clients>; rel="alternate"
如果你知道了 API 何时完全关闭的话,那么就应该添加一个 Sunset 头信息。
https://datatracker.ietf.org/doc/rfc8594/?include_text=1
Sunset 头信息告诉客户端 API 何时会停止运行。这是一个强制的截止时间:API 客户端必须要在这个日期前进行迁移,我们承诺在这个时间前不会破坏任何事情。
Sunset: Tue, 20 Jul 2021 23:59:59 GMT
这非常简单,它不仅可以用到 API 关闭的场景中:我们能用它来标记将来 URL 迁移的 HTTP 重定向,或者表明特定 URL 有限的生命周期(适用于临时性的内容,或者适用于具有监管要求的特定资源,比如数据保留策略)。它所说明的就是“这个端点可能在该日期后不会再按照你的预期运行,请做好准备”。
Link: <http://developer.example.com/our-sunset-policy>;rel="sunset";type="text/html"
在这里我们也要指出,通用的 Sunset 策略是非常有用的!Sunset 策略会告诉客户端,当我们关闭端点的时候(比如,一年后替代方案上线),用户该如何确保他们能得知这一情况(邮件列表、状态页面、HTTP 头信息等)以及他们通常应该做些什么(更新、检查文档、遵从Link
头信息)。
如果马上就要废弃某个 API 的话,添加这样的链接作用其实不大,但是如果你能在一年前就将其发布出去的话,你的客户端可能已经为此做好了准备。
除此之外,发布 Sunset/Deprecation 策略的最好时间就是现在。如果你恰好正以某种方式编写 Deprecation 文档的话,这么做是值得考虑的。
Deprecation: Thu, 21 Jan 2021 23:59:59 GMT
Sunset: Tue, 20 Jul 2021 23:59:59 GMT
Link: <https://api.example.com/v2/customers>; rel="successor-version",
<https://developer.example.com/shutting-down-customers-v1>; rel="deprecation"
如果所有这些都已经准备到位,并且 sunset 截止时间已过,那么我们就可以将 API 关闭了。
但是,这并不意味着你需要立即且彻底消灭该 API。渐进式关闭能有助于确保任何使用该 API 的所有客户端都有最后的机会在它彻底消失前得到最后一次警告。GitHub 在 2018 年移除一些加密支持的时候曾经这样做:首先禁用一个小时,然后启用它,最后在两周后彻底禁用了它。
https://github.blog/2018-02-01-crypto-removal-notice/
这里还有另外一个技巧:安卓在 2015 年为已废弃的原生 API 增加了越来越多的延迟,在彻底关闭 API 前,最终达到了 16 秒的等待。
https://twitter.com/jbaruch/status/930476565065953280
这些渐进式的关闭为那些错过截止日期的客户端提供了一些灵活性,并且能帮助那些没有注意到废弃时间点的客户端,从而能在 API 彻底关闭之前处理一些问题。
不管采用哪种方式,只要你尽了最大的努力去沟通关于 API 关闭的事情,那么现在就可以关闭端点 / 特性 / 整个服务,删除代码,然后睡个好觉。
像这样小心谨慎地进行废弃和关闭,可以让你的客户端尽可能清楚地知道他们该如何依赖你的 API,何时需要采取行动,以及他们需要做什么。这种变更可能是一件大事儿,这些信息是很重要的。
这些新的草案头信息让我们不仅可以与人类沟通,还能将这些信息暴露给自动化系统。随着这些头信息的普及,我很高兴地开始看到有更多的工具建立在它们之上。通用的 HTTP 客户端可以根据这些数据自动记录有用的警告日志,API 生成器本身也能根据 API 规范处理越来越多的问题,而 HTTP 调试器(如 HTTP Toolkit)可以在截获的实时流量中为你突出显示废弃端点的使用。这是一个令人激动的时刻,我们可以开始安全地关闭 API 了!
https://httptoolkit.tech/
需要注意的是,这些头信息是 HTTP 规范的草案。在最终确定前,它们有可能会发生变化。也就是说,它们经历了几轮修改,从现在开始,它们不太可能发生巨大的变化,现在能广泛测试它们了。
不过这也意味着还有时间进行反馈! 如果你对它们的工作方式和如何更好地运行有想法的话,请与“Building Blocks for HTTP APIs”工作组联系。你可以给邮件列表发邮件:httpapi@ietf.org。
https://httptoolkit.tech/blog/how-to-turn-off-your-old-apis/