Kompatybilność kontraktu API
Dlaczego kompatybilność kontraktu
Kompatybilność umowy to zdolność API do ewolucji bez łamania istniejących integracji. W rosnących systemach interfejsy API zmieniają się częściej niż kod klienta; kompatybilność pozwala na iteratywne uwalnianie funkcji, bez aranżowania „dużych ruchów”.
Kluczowy pomysł: umowa jest podstawowa, zmiany są przeprowadzane zgodnie z zasadami zgodności i są sprawdzane automatycznie.
Podstawowe koncepcje
Umowa - formalna specyfikacja interfejsu: zasoby/metody/zdarzenia, schematy danych, kody błędów, limity, SLA, wymagania bezpieczeństwa.
Dostawca - właściciel API. Konsument - klient/integracja.
- Wstecz: Nowy dostawca współpracuje ze starymi konsumentami.
- Naprzód: Stary dostawca współpracuje z nowymi konsumentami (zwykle osiągane przez „tolerancyjnych czytelników”).
- Pełne: obserwuje się zarówno do tyłu, jak i do przodu (najsilniejsza opcja).
- Dodatek - dodaj opcjonalne elementy bez łamania istniejących.
Polityka weryfikacyjna
Wersioning semantyczny (zalecany):- MAJOR - łamanie zmian (tylko wtedy, gdy zostanie wydana nowa linia API: '/v2 ',' service. v2 ").
- MINOR - zmiany addytywne (nowe pola/metody opcjonalne).
- PATCH - poprawki bez zmiany umowy.
- Polityka odrzucenia: deklaracja przestarzałych elementów, okno wsparcia (zachód słońca), ostrzeżenia w nagłówkach/metadanych, plan wycofania.
Bezpieczne vs niebezpieczne zmiany
Bezpieczne (zwykle kompatybilne wstecz)
Dodaj opcjonalne pole do JSON/Protobuf/Avro.
Dodaj nowy punkt końcowy/metodę/zdarzenie.
Rozszerzenie enum o nowe wartości, jeśli konsumenci są tolerancyjni dla nieznanych wartości.
Podnoszenie limitów (na przykład 'maxItems') bez dokręcania minimum.
Dodanie nullable z poprawnymi domyślnymi.
Edytuj opis/przykład tekstu.
Niebezpieczne (kompatybilność przerw)
Zmień nazwę/usuń pola, zmień ich typ lub obowiązkowe.
Zmiana kodu stanu/semantyki błędu (na przykład '200', stała się '204' lub '404').
Zmiana formatu identyfikatorów (UUID → int).
Zaostrzenie walidacji (bardziej rygorystyczne minima/wzory) bez wersji.
Zmiana kolejności i struktury w strumieniach/zdarzeniach gRPC.
Ponownie użyj numerów znaczników w Protobuf dla nowych pól.
Interoperacyjność przez styl interakcji
REST/HTTP + Schemat JSON
Dodatkowość: oznaczamy nowe pola jako „opcjonalne ”/„ nieważne”.
Tolerant Reader w kliencie: ignoruj nieznane pola; Nie polegając na zamówieniu.
Wersioning: major - w drodze ('/v2 ') lub w typie nośnika (' application/vnd. przykład. v2 + json ').
ETag/If-Match: dla bezpiecznych aktualizacji bez wyścigów.
Błędy: pojedynczy format ("typ", "kod", "tytuł", "detal", "trace _ id'), nie zmieniają wartości kodu bez dużego.
Paginacja: kursory są preferowane do offsetu; dodać pola 'next _ cursor', nie zmieniać znaczenia istniejących.
gRPC/Protobuf
Numer znacznika jest niezmieniony. Usunięte znaczniki nie mogą być ponownie użyte.
Nowe pola są 'opcjonalne '/' powtarzane' z rozsądnymi domyślami na serwerze.
Nie zmieniaj kolejności i obowiązkowych wiadomości w strumieniowo-RPC.
Statusy błędów są stabilne („INVALID _ ARGUMENT”, „FAILED _ PRECONDITION” itp.); nowa semantyka → nowa wersja metody/usługi.
Napędzane zdarzeniami (Kafka/NATS/Pulsar) + Avro/JSON Schema
Nazywanie zdarzeń: 'domena. działania. v {major} '.
Nowe pola są opcjonalne; rdzeń izolatu i wzbogacenie („wzbogacone”).
Rejestry schematów: zasady zgodności (BACKWARD/FORWARD/FULL) dotyczące tematu/wydarzenia.
Rozszerzenie enum jest ważne dla czytnika tolerancyjnego po stronie konsumenta.
Zmiana klucza partycji/zamówienia dla kruszywa = zmiany przełamujące.
GraphQL
Dodawanie pól/typów jest bezpieczne; usuń/zmień nazwę - tylko przez @ zdeprecated i okno migracji.
Nie zmieniać typów/nieważne bez większych.
Złożoność/głębokość sterowania - limity są częścią umowy.
Zrównoważone modele ewolucji
Dodatek-pierwszy: Rozwinąć bez łamania.
Negocjacja zdolności: klienci zgłaszają, że obsługują (nagłówki/parametry/umowy), serwer się dostosowuje.
Granice kontraktu: Fix MGC (minimalny kontrakt gwarancyjny) i oddzielne rozszerzenia (model odwrotnej piramidy).
Domyślna tolerancja: klienci ignorują zbędne i prawidłowo obsługują nieznane wartości enum (fallback).
Dual-write/Dual-emmit: dla dużych zmian, zwolnić 'v1' i 'v2' równolegle przez jakiś czas.
Nagłówki/Wydarzenia Zachód słońca: Powiadom z wyprzedzeniem, kiedy wersje zostaną usunięte.
Zarządzanie i automatyzacja
Linters API:- OpenAPI/Spectral: nazewnictwo, paginacja, kody błędów, formaty pola.
- Buf/Protobuf: wyłączenie ponownego użycia znaczników, notacja pakietów.
- Rejestr AsyncAPI/Schema: kompatybilność schematu poziomu CI.
- Katalog umów (SSOT): Scentralizowany schemat/rejestr wersji z rozproszoną historią.
- Gildia API: gildia/komisja, która przyjmuje zasady, szablony i zmiany przeglądowe.
- Zarządzanie zmianą: RFC/ADR, notatki do wydania, przewodniki migracji.
Testowanie zgodności
Schemat-diff w CI: ciastka przełamujące blok (OpenAPI-diff, łamanie Buf, kompatybilność SR).
Umowy konsumenckie (CDC): Pakt/Podobne - Dostawca vs. Umowy specyficzne dla konsumentów.
Złote próbki: zapytania referencyjne/odpowiedzi i zdarzenia dla regresji.
E2E Canary: przejście do części ruchu/poszczególnych grup konsumenckich.
Chaos/latency: Timeout/Retray check - Zmiana latency-SLO jest uważana za zmianę umowy.
Migracja i deprecacja
1. Ogłaszaj przestarzałość: Zaznacz przedmiot, określ termin zachodu słońca i alternatywę.
2. Utrzymać okres kompatybilności: podwójne pisanie/podwójne emisje, mosty, adaptery.
3. Zbierz telemetrię: kto jeszcze używa starego?
4. Komunikacja: mailingi, notatki, stojaki testowe.
5. Usunięcie: po wygaśnięciu okna - usunięcie przy stałym zwolnieniu.
Przykłady zmian
ODPOCZYNEK
To było:json
{ "id":"p1", "status":"authorized" }
Stał się (dodatek, bezpieczny):
json
{ "id":"p1", "status":"authorized", "risk_score": 0. 12 }
Klienci, którzy ignorują nieznane pola nie łamią.
Protobuf
proto message Payment {
string id = 1;
string status = 2; // don't change tag numbers optional double risk_score = 3; // additive
}
Zdarzenie
"płatność. autoryzowany. v1 '(rdzeń) +' płatność. wzbogacony. v1 "(wzbogacenie). Konsumenci ścieżki krytycznej czytają rdzeń i nie są uzależnieni od wzbogacenia.
Antypattery
Swagger-wash: formalnie istnieje specyfikacja, ale zachowanie usługi jest sprzeczne z nią.
Breaking by stealth: zmieniony typ/status/format bez nowej wersji i okna migracji.
Surowe wydarzenia CDC jako zamówienie publiczne: wyciek systemów DB, niemożność ewolucji.
Klient twardy: krople w nieznanych polach/wartościach; brak tolerancyjnego czytnika.
Ponowne użycie znaczników protobufu: cicha korupcja danych.
Opóźnienie jako „non-contract”: p95 został nieoczekiwanie wydłużony - konsumenci rozkładają się w czasie.
Lista kontrolna zgodności (przed połączeniem)
- Zmiany są dodatkiem (lub główna wersja przygotowana).
- Przeszedł kontrolę linterów/diff, zasady zgodności są zielone.
- Błędy/kody/statusy nie zmieniły semantyki.
- Enum rozszerzone bez zakazu starych wartości; klienci - tolerancyjni.
- Granice MGC nie ulegają zmianie.
- Uaktualnione próbki/dokumentacja/SDK.
- W przypadku planu dużego - dual-write/dual-emit, sunset-date, comm-plan.
- Badania CDC/Golden/E2E przeszedł.
NAJCZĘŚCIEJ ZADAWANE PYTANIA
Czym się do tyłu różni od kompatybilności do przodu?
Wstecz - nowe serwery nie łamią starych klientów. Do przodu - nowi klienci nie pękają na starych serwerach (poprzez tolerancyjny czytnik i schludne domyślne).
Kiedy robisz '/v2 '?
Kiedy niezmienne/semantyczne zmiany, pola/metody są usuwane, wymagany jest nowy model bezpieczeństwa - łatwiej i uczciwie jest uruchomić nową linię.
Czy możesz żyć bez systemu Schema Registry/linters?
Teoretycznie - tak, praktycznie - są to częste regresje i „ukryte” załamania. Automatyzacja się opłaca.
Enum można wydłużyć?
Tak, jeśli klienci prawidłowo obsługują nieznane wartości (fallback/ignoruj). W przeciwnym razie - major.
Razem
Zgodność kontraktu to zasady + dyscyplina + automatyzacja. Projektowanie dodatkowo, zmiany łamania wersji, zastosowanie tolerancyjnego czytnika, automatyczne sprawdzanie różnic i CDC, plan deprecate. W ten sposób API mogą szybko ewoluować, a integracje mogą pozostać stabilne.