老舊的API,你應(yīng)該如何處理?
點擊“開發(fā)者技術(shù)前線”,選擇“星標??”
讓一部分開發(fā)者看到未來
萬物都會有終結(jié),HTTP API 也不例外。不論你的 API 今天看上去多么偉大,遲早有一天你會想發(fā)布一個全新的版本,新版本能更好地解決相同問題,在各方面可能都會有所改善,但是它因為有了新參數(shù),與舊版本也無法兼容,或者你只是想徹底關(guān)閉舊的 API??偠灾?,你現(xiàn)在的 API 不會永遠存在。
但是,這并非輕而易舉就能完成的,因為你的 API 有客戶端。如果你關(guān)閉端點、參數(shù)或整個 API 而沒有做出恰當?shù)木娴脑?,那他們肯定會非常不爽?/p>
那么,該怎樣安全地關(guān)閉 API,讓你的用戶盡可能地感到輕松愉快呢?
在這方面,我們有正確的做事方式,包括兩個新的頭信息草案,它們正在被新的 IETF “Building Blocks for HTTP APIs”工作組進行標準化,旨在形成一個精確的過程。我們了解一下。
初始第一步:檢查相關(guān)的 API 是否真的有客戶端。
希望你能有某些 API 的度量指標,至少在某些地方存有日志。如果沒有的話,那把它們添加上,如果你有這些東西的話,并且你能確定沒有人再使用這個 API 了,那么恭喜你,你贏了?,F(xiàn)在,你就可以把它關(guān)掉,刪掉代碼,不要再管這篇文章了,好好睡一覺。
下一個問題,如果比較遺憾,你無法去睡覺的話,那就要問問自己,除了關(guān)閉這個 API,還有沒有其他方案。你關(guān)閉的所有東西都有可能破壞別人的代碼,并且會消耗他們的時間來修復(fù)這些問題。如果 API 能繼續(xù)運行的話,對客戶端的生態(tài)系統(tǒng)和整個 web 的健康都是有好處的。
在很多場景下,舊的 API 可以在內(nèi)部進行轉(zhuǎn)換,透明地轉(zhuǎn)化成對新 API 的調(diào)用,這樣可以避免維護兩個完全獨立的版本。這是 Stripe 的 API 版本管理方式的一個基本組成部分,他們在所有發(fā)生變化的 API 中都包含了轉(zhuǎn)換,以確保對不兼容的舊版本 API 的請求能繼續(xù)像以前那樣運行,根據(jù)需要自動轉(zhuǎn)換請求和響應(yīng)從而可以使用較新的代碼。
https://stripe.com/blog/api-versioning#versioning-under-the-hood
這樣的轉(zhuǎn)換并不總是可行的,而且如果永遠這樣做的話會帶來明顯的額外復(fù)雜性,但是如果你可以做到這一點的話,就能為用戶提供非常有價值的穩(wěn)定性,并且可以節(jié)省大量廢棄舊版本或維護舊版本相關(guān)的工作。
但是,如果這個服務(wù) / 端點 / 參數(shù)已經(jīng)用到了生產(chǎn)環(huán)境,而且繼續(xù)支持它是不現(xiàn)實的做法,那么它必須要被淘汰。
要實現(xiàn)這一點,我們就要有一個計劃。我們首先要問自己三個關(guān)鍵的問題:
你希望用戶該怎么做?常見的答案包括:升級到相關(guān)功能的一個更新的、依然能得到支持的版本;使用一些可替代的端點 / 參數(shù) / 服務(wù);使用不同的服務(wù),它們與你無關(guān),不需要你關(guān)心。
用戶應(yīng)該何時遷離這個 API?你所提出的替代方案現(xiàn)在就可以用了嗎?
截止時間是什么時候?也就是,這個 API 何時會完全停止使用?(如果不能完全確定的話,你可以稍微延遲回答這個問題)。
計劃準備就緒之后,我們就該把它告訴人們了。
首先,要把這一決定告訴人們。
發(fā)郵件到郵件列表,在 Twitter 或微博上發(fā)帖,如果有 API 規(guī)范的話,對其進行更新(比如,OpenAPI 在 operations 和 parameters 上有一個deprecated字段),并在相關(guān)的在線文檔上大聲強調(diào)這一點。
你應(yīng)該包含上文提到的所有信息:他們應(yīng)該做些什么作為替代方案,你建議他們什么時候開始遷移以及他們必須要進行遷移的最后期限(如果已經(jīng)確定期限的話)。
在將這些信息告訴給人們后,接下來就該告訴計算機,而這就是新的 IETF 頭信息可以發(fā)揮作用的地方。
Deprecation 頭信息能告訴客戶端請求的資源現(xiàn)在依然像以前那樣運行,但是這種方式已經(jīng)不再推薦使用了。
https://datatracker.ietf.org/doc/draft-ietf-httpapi-deprecation-header/?include_text=1
Deprecation: trueDeprecation: Thu, 21 Jan 2021 23:59:59 GMT如果你要廢棄整個端點或服務(wù),那么你可以在每個響應(yīng)中都帶上這樣的頭信息。如果你想要廢棄的是一個具體的特性,可能是一個參數(shù)、請求方法或者請求體中的某個特定字段的話,那么你應(yīng)該在該特性被使用的時候才在響應(yīng)中包含這個頭信息。
為了給客戶端更多的信息,我們還可以使用Link HTTP 響應(yīng)頭信息鏈接至端點或人類易讀的文檔。在同一個Link頭信息中,我們可以包含多個這樣的鏈接,只需要使用逗號進行分割即可(后面我們會看到一個完整的例子)。該規(guī)范定義了四個與 API 廢棄相關(guān)的鏈接:
Link: <https://developer.example.com/deprecation>; rel="deprecation"; type="text/html"這是告訴用戶發(fā)生了什么以及他們該怎么辦的主要方式。你應(yīng)該始終使用它。如果還沒有完整的詳情和最終的關(guān)閉日期,那么即使只是一個占位符,這也是很有幫助的。在這種情況下,不要忘記讓用戶訂閱更新,這可以采用郵件列表、RSS 或其他類似的方式來實現(xiàn)。
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 何時完全關(guān)閉的話,那么就應(yīng)該添加一個 Sunset 頭信息。
https://datatracker.ietf.org/doc/rfc8594/?include_text=1
Sunset 頭信息告訴客戶端 API 何時會停止運行。這是一個強制的截止時間:API 客戶端必須要在這個日期前進行遷移,我們承諾在這個時間前不會破壞任何事情。
Sunset: Tue, 20 Jul 2021 23:59:59 GMT這非常簡單,它不僅可以用到 API 關(guān)閉的場景中:我們能用它來標記將來 URL 遷移的 HTTP 重定向,或者表明特定 URL 有限的生命周期(適用于臨時性的內(nèi)容,或者適用于具有監(jiān)管要求的特定資源,比如數(shù)據(jù)保留策略)。它所說明的就是“這個端點可能在該日期后不會再按照你的預(yù)期運行,請做好準備”。
Link: <http://developer.example.com/our-sunset-policy>;rel="sunset";type="text/html"在這里我們也要指出,通用的 Sunset 策略是非常有用的!Sunset 策略會告訴客戶端,當我們關(guān)閉端點的時候(比如,一年后替代方案上線),用戶該如何確保他們能得知這一情況(郵件列表、狀態(tài)頁面、HTTP 頭信息等)以及他們通常應(yīng)該做些什么(更新、檢查文檔、遵從Link頭信息)。
如果馬上就要廢棄某個 API 的話,添加這樣的鏈接作用其實不大,但是如果你能在一年前就將其發(fā)布出去的話,你的客戶端可能已經(jīng)為此做好了準備。
除此之外,發(fā)布 Sunset/Deprecation 策略的最好時間就是現(xiàn)在。如果你恰好正以某種方式編寫 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"如果所有這些都已經(jīng)準備到位,并且 sunset 截止時間已過,那么我們就可以將 API 關(guān)閉了。
但是,這并不意味著你需要立即且徹底消滅該 API。漸進式關(guān)閉能有助于確保任何使用該 API 的所有客戶端都有最后的機會在它徹底消失前得到最后一次警告。GitHub 在 2018 年移除一些加密支持的時候曾經(jīng)這樣做:首先禁用一個小時,然后啟用它,最后在兩周后徹底禁用了它。
https://github.blog/2018-02-01-crypto-removal-notice/
這里還有另外一個技巧:安卓在 2015 年為已廢棄的原生 API 增加了越來越多的延遲,在徹底關(guān)閉 API 前,最終達到了 16 秒的等待。
https://twitter.com/jbaruch/status/930476565065953280
這些漸進式的關(guān)閉為那些錯過截止日期的客戶端提供了一些靈活性,并且能幫助那些沒有注意到廢棄時間點的客戶端,從而能在 API 徹底關(guān)閉之前處理一些問題。
不管采用哪種方式,只要你盡了最大的努力去溝通關(guān)于 API 關(guān)閉的事情,那么現(xiàn)在就可以關(guān)閉端點 / 特性 / 整個服務(wù),刪除代碼,然后睡個好覺。
像這樣小心謹慎地進行廢棄和關(guān)閉,可以讓你的客戶端盡可能清楚地知道他們該如何依賴你的 API,何時需要采取行動,以及他們需要做什么。這種變更可能是一件大事兒,這些信息是很重要的。
這些新的草案頭信息讓我們不僅可以與人類溝通,還能將這些信息暴露給自動化系統(tǒng)。隨著這些頭信息的普及,我很高興地開始看到有更多的工具建立在它們之上。通用的 HTTP 客戶端可以根據(jù)這些數(shù)據(jù)自動記錄有用的警告日志,API 生成器本身也能根據(jù) API 規(guī)范處理越來越多的問題,而 HTTP 調(diào)試器(如 HTTP Toolkit)可以在截獲的實時流量中為你突出顯示廢棄端點的使用。這是一個令人激動的時刻,我們可以開始安全地關(guān)閉 API 了!
https://httptoolkit.tech/
需要注意的是,這些頭信息是 HTTP 規(guī)范的草案。在最終確定前,它們有可能會發(fā)生變化。也就是說,它們經(jīng)歷了幾輪修改,從現(xiàn)在開始,它們不太可能發(fā)生巨大的變化,現(xiàn)在能廣泛測試它們了。
不過這也意味著還有時間進行反饋! 如果你對它們的工作方式和如何更好地運行有想法的話,請與“Building Blocks for HTTP APIs”工作組聯(lián)系。你可以給郵件列表發(fā)郵件:[email protected]。
https://httptoolkit.tech/blog/how-to-turn-off-your-old-apis/

