API合同兼容性
為什麼需要合同兼容性
合同兼容性是API在不破壞現有集成的情況下發展的能力。在不斷發展的系統中,API更頻繁地更改客戶端代碼。相容性允許叠代生產菲奇,而無需安排「大移動」。
關鍵思想:合同-初級,更改遵循兼容性規則並自動驗證。
基本概念
合同-正式界面規格:資源/方法/事件,數據電路,錯誤代碼,限制,SLA,安全要求。
提供程序(provider)-API的所有者。消費者(消費者)-客戶端/集成。
- Backward:新供應商與老消費者合作。
- 前進:老供應商與新消費者合作(通常通過「寬容的讀者」來實現)。
- 滿:後衛和前鋒(最強選項)都遵循。
- 可加性-添加可選元素而不切斷現有元素。
考試政策
語義版本(建議):- MAJOR是斷開的更改(僅在發布新的API行時:'/v2',「服務」。v2`).
- MINOR-加法更改(新的可選字段/方法)。
- PATCH-不更改合同的修復程序。
- Deprecation Policy:聲明遺留項目,支持窗口(日落),標題/元數據中的警告,刪除計劃。
安全vs危險變化
安全(通常是反向兼容)
在JSON/Protobuf/Avro中添加可選字段。
添加新的端點/方法/事件。
如果消費者容忍未知值,則以新值擴展enum。
提高限制(例如「maxItems」)而無需收緊最小值。
添加帶有正確默認值的nullable。
更改描述/示例文本。
危險(中斷互操作性)
重命名/刪除字段,更改字段的類型或約束。
狀態代碼/錯誤語義的變化(例如「200」變為「204」或「404」)。
更改標識符格式(UUID → int)。
收緊驗證(嚴格為最小值/模式)而無需版本。
gRPC流/事件中的順序和結構變化。
將Protobuf中的標記編號重新用於新字段。
互操作性樣式
REST/HTTP + JSON Schema
可加性:將新字段標記為「optional」/「nullable」。
客戶端的Tolerant Reader:忽略未知字段;不要依靠秩序。
轉化: 專業-在路上('/v2')或介質('application/vnd。example.v2+json`).
ETag/If-Match:用於安全升級而無需比賽。
錯誤:單一格式(「type」,「code」,「title」,「detail」,「trace_id」),不要在沒有專業的情況下更改「code」的含義。
分離:遊標優於offset;添加「next_cursor」字段,不要改變現有字段的含義。
gRPC / Protobuf
標簽編號不變。已刪除的標簽不會重新使用。
新字段是「optional」/「repeated」,服務器上有合理的默認值。
不要在streaming-RPC中更改消息的順序和約束。
錯誤狀態是穩定的(「INVALID_ARGUMENT」,「FAILED_PRECONDITION」等);新語義→方法/服務的新版本。
Event-driven (Kafka/NATS/Pulsar) + Avro/JSON Schema
事件命名: "域。action.v{major}`.
新字段-可選;釋放內核和富集(「.enriched」)。
電路寄存器:主題/事件的兼容性規則(BACKWARD/FORWARD/FULL)。
當消費者側的tolerant reader時,enum擴展是允許的。
更改聚合的部分/順序鍵=斷開更改。
GraphQL
添加字段/類型-安全;刪除/重命名-僅通過@deprecated和遷移窗口。
不要在沒有專業的情況下改變類型/不可阻擋。
控制complexity/depth-限制是合同的一部分。
可持續進化的模式
Additive-first:在不中斷的情況下進行擴展。
功能性negotation:客戶端報告他們支持(標題/選項/安排),服務器進行調整。
合同邊界:固定MGC(最低保修合同)和分離擴展(反金字塔模型)。
默認收費:客戶忽略多余,並正確處理未知的enum值(fallback)。
Dual-write/Dual-emit:在主要更改中,並行發布「v1」和「v2」一段時間。
Sunset headers/Events:提前通知您已刪除版本。
政府和自動化
API linters:- OpenAPI/Spectral:命名、分頁、錯誤代碼、字段格式。
- Buf/Protobuf:禁止使用標簽和數據包符號。
- AsyncAPI/Schema Registry:CI級別的電路兼容性。
- 合同目錄(SSOT):具有誹謗歷史的集中電路/版本註冊表。
- API Guild:接受規則,模板和更改評論的行會/委員會。
- 更改管理:RFC/ADR,發布註釋,遷移粘合劑。
兼容性測試
CI中的Schema-diff:阻止斷裂的孢子變化(OpenAPI-diff,Buf breaking,SR compatibility)。
Consumer-Driven Contracts (CDC): Pact/相似-驗證供應商與特定消費者的合同。
Golden Samples:參考查詢/響應和倒退事件。
E2E金絲雀:分成流量份額/單獨的控制組。
Chaos/Latency: Taymout/Retraes檢查-Latency-SLO更改被視為合同更改。
遷移和刪除
1.聲明刪除:標記項目,指定日落期限和替代方案。
2.支持互操作性時期:雙write/dual-emit、網橋、適配器。
3.收集遙測:還有誰在使用舊的?
4.通訊:郵件、發行說明、測試臺。
5.卸載:窗口到期後,使用固定版本卸載。
更改示例
REST
有:json
{ "id":"p1", "status":"authorized" }
已成為(加法,安全):
json
{ "id":"p1", "status":"authorized", "risk_score": 0. 12 }
忽略未知字段的客戶不會崩潰。
Protobuf
proto message Payment {
string id = 1;
string status = 2; // don't change tag numbers optional double risk_score = 3; // additive
}
Event
`payment.authorized.v1'(內核)+'payment。enriched.v1'(富集)。關鍵路徑的消費者讀取核心,不依賴濃縮。
反模式
Swagger-wash:規範正式存在,但服務行為與它不一致。
破折號:在沒有新版本和遷移窗口的情況下更改類型/狀態/格式。
原始CDC事件作為公共合同:DB方案泄漏,無法進化。
硬客戶端:在未知字段/值下下降;沒有tolerant閱讀器。
重新使用protobuf標簽:無聲的數據腐敗。
潛伏為「非合同」:p95出乎意料地延長了-消費者打破了時間。
兼容性檢查表(在默奇之前)
- 更改是可加的(或已準備好主要版本)。
- Linters/diff支票已通過,兼容性規則為綠色。
- 錯誤/代碼/狀態沒有改變語義。
- Enum在不禁止舊值的情況下進行了擴展;客戶是tolerant。
- MGC邊界不變。
- 更新示例/文檔/SDK。
- 對於專業-雙寫/雙表情計劃,日落日期,comm計劃。
- 測試CDC/Golden/E2E通過。
FAQ
背面與前面的兼容性有何不同?
Backward-新服務器不會打破舊客戶端。Forward-新客戶端不會在較舊的服務器上破裂(通過tolerant reader和整潔的默認)。
什麼時候做「/v2」?
當不變式/語義發生變化時,刪除字段/方法,需要新的安全模型-運行新線更簡單,更誠實。
沒有Schema Registry/Linters可以生活嗎?
從理論上講-是的,實際上-這些是頻繁的倒退和「隱藏」的斷裂。自動化正在得到回報。
Enum可以擴展嗎?
是的,如果客戶正確處理未知值(fallback/ignore)。否則-大調。
底線
合同兼容性是規則+紀律+自動化。加性設計,折斷性變化,應用托勒南特讀取器,自動檢查誹謗和CDC,計劃丟棄。因此,API將能夠快速發展,集成將保持穩定。