Vertragliche API-Kompatibilität
Warum vertragliche Kompatibilität erforderlich ist
Vertragliche Kompatibilität ist die Fähigkeit von APIs, sich zu entwickeln, ohne bestehende Integrationen zu brechen. In wachsenden Systemen ändern sich APIs häufiger als Kundencode; Kompatibilität ermöglicht es Ihnen, Fichi iterativ freizugeben, ohne „große Umzüge“ zu arrangieren.
Die Grundidee: Der Vertrag ist primär, die Änderungen erfolgen nach Kompatibilitätsregeln und werden automatisch geprüft.
Grundlegende Konzepte
Vertrag - formale Schnittstellenspezifikation: Ressourcen/Methoden/Ereignisse, Datenschemata, Fehlercodes, Limits, SLAs, Sicherheitsanforderungen.
Anbieter - Der Eigentümer der API. Der Verbraucher (Consumer) ist der Kunde/die Integration.
- Backward: Der neue Anbieter arbeitet mit alten Verbrauchern zusammen.
- Vorwärts: Der alte Anbieter arbeitet mit neuen Verbrauchern (in der Regel von „toleranten Lesern“ erreicht).
- Voll: Sowohl Backward als auch Forward (stärkste Variante) werden eingehalten.
- Additivität - Fügen Sie optionale Elemente hinzu, ohne vorhandene zu brechen.
Versionsrichtlinie
Semantic Versioning (empfohlen):- MAJOR - brechende Änderungen (nur bei Freigabe einer neuen API-Zeile: '/v2', 'service. v2`).
- MINOR - additive Änderungen (neue optionale Felder/Methoden).
- PATCH - Korrekturen ohne Vertragsänderung.
- Deprecation Policy: Deklaration veralteter Elemente, Supportfenster (Sunset), Warnungen in Kopfzeilen/Metadaten, Abhebungsplan.
Sichere vs gefährliche Änderungen
Sicher (normalerweise backward-kompatibel)
Fügt ein optionales Feld zu JSON/Protobuf/Avro hinzu.
Hinzufügen eines neuen Endpoints/einer neuen Methode/eines neuen Ereignisses.
Erweitern Sie enum mit neuen Werten, wenn Verbraucher gegenüber unbekannten Werten tolerant sind.
Anhebung der Limits (z.B. 'maxItems') ohne Verschärfung des Minimums.
Nullable mit korrekten Standardwerten hinzufügen.
Text der Beschreibungen/Beispiele ändern.
Gefährlich (bricht Kompatibilität)
Felder umbenennen/löschen, ihren Typ oder ihre Verbindlichkeit ändern.
Änderung der Semantik von Status Codes/Fehlern (z.B. war '200', wurde' 204 'oder' 404').
Änderung des ID-Formats (UUID → int).
Verschärfung der Validierung (strengere Minima/Muster) ohne Version.
Änderung der Reihenfolge und Struktur in gRPC-Streams/Events.
Neuverwendung von Tag-Nummern in Protobuf für neue Felder.
Kompatibilität durch Interaktionsstile
REST/HTTP + JSON Schema
Additivität: Neue Felder werden als' optional '/' nullbar 'markiert.
Tolerant Reader beim Kunden: unbekannte Felder ignorieren; Verlassen Sie sich nicht auf Ordnung.
Versionierung: Major - unterwegs ('/v2') oder im Mediatip ('application/vnd. example. v2+json`).
ETag/If-Match: für sichere Upgrades ohne Rennen.
Fehler: Einheitliches Format ('type', 'code', 'title', 'detail', 'trace _ id'), Werte' code' ohne Dur nicht ändern.
Pagination: Cursor sind Offset vorzuziehen; fügen Sie die Felder 'next _ cursor' hinzu, ändern Sie nicht die Bedeutung der vorhandenen.
gRPC / Protobuf
Die Tag-Nummerierung ist unverändert. Gelöschte Tags können nicht erneut verwendet werden.
Die neuen Felder sind 'optional '/' wiederholt' mit angemessenen Standardwerten auf dem Server.
Ändern Sie nicht die Reihenfolge und Verbindlichkeit der Nachrichten im Streaming-RPC.
Fehlerstatus - stabil („INVALID _ ARGUMENT“, „FAILED _ PRECONDITION“ usw.); Neue Semantik → neue Version der Methode/des Dienstes.
Event-driven (Kafka/NATS/Pulsar) + Avro/JSON Schema
Benennung der Ereignisse: 'Domäne. action. v{major}`.
Neue Felder - optional; Kernel und Anreicherung („.enriched“).
Schemaregister: Kompatibilitätsregeln (BACKWARD/FORWARD/FULL) pro Thema/Ereignis.
Die Erweiterung enum ist bei einem toleranten Leser auf Verbraucherseite zulässig.
Änderung des Partitionierungs-/Ordnungsschlüssels für das Aggregat = brechende Änderungen.
GraphQL
Hinzufügen von Feldern/Typen - sicher; Löschen/Umbenennen - nur über @ deprecated und das Migrationsfenster.
Ändern Sie nicht die Typen/nicht nullbar ohne Dur.
Kontrolle der Komplexität/Tiefe - Limits sind Teil des Vertrags.
Muster nachhaltiger Evolution
Additive-first: erweitern, ohne zu brechen.
Capability negotiation: Clients melden, was sie unterstützen (Header/Parameter/Arrangements), der Server passt sich an.
Vertragsgrenzen: MGC (Minimum Guarantee Contract) erfassen und Erweiterungen trennen (Reverse Pyramid Model).
Toleranz nach Standard: Kunden ignorieren Überflüssiges und behandeln unbekannte Enum-Werte (Fallback) korrekt.
Dual-write/Dual-emit: Bei großen Änderungen einige Zeit 'v1' und 'v2' parallel freigeben.
Sunset headers/Events: Benachrichtigen Sie im Voraus, wenn Versionen entfernt werden.
Governance und Automatisierung
API-Linter:- OpenAPI/Spectral: Benennung, Paginierung, Fehlercodes, Feldformate.
- Buf/Protobuf: Verbot der Wiederverwendung von Tags, Paketnotation.
- AsyncAPI/Schema Registry: Schema-Kompatibilität auf CI-Ebene.
- Contract Directory (SSOT): Zentralisiertes Schema/Versionsregister mit Diffusgeschichte.
- Guild API: Gilde/Komitee, das Regeln, Vorlagen und Revisionsänderungen akzeptiert.
- Change Management: RFC/ADR, Release Notes, Migrationshinweise.
Kompatibilitätstests
Schema-diff in CI: Blocking Breaking Specs (OpenAPI-diff, Buf breaking, SR-Kompatibilität).
Consumer-Driven Contracts (CDC): Pakt/ähnlich - Lieferantenvalidierung gegen Verträge bestimmter Verbraucher.
Goldene Beispiele: Referenzanfragen/-antworten und -ereignisse für die Regression.
E2E Canary: Rollout auf den Anteil des Verkehrs/einzelne consumer-Gruppen.
Chaos/Latency: Überprüfung von Timeouts/Retrays - eine Änderung des Latency-SLO gilt als Vertragsänderung.
Migrationen und Deprecate
1. Deklarieren Sie das Deprecate: Markieren Sie das Element, geben Sie das Sunset-Datum und die Alternative an.
2. Pflegen Sie den Kompatibilitätszeitraum: Dual-Write/Dual-Emit, Brücken, Adapter.
3. Telemetrie sammeln: Wer nutzt noch das Alte?
4. Kommunikation: Mailings, Release Notes, Prüfstände.
5. Rücknahme: Nach Ablauf des Fensters - Rücknahme mit fester Freigabe.
Beispiele für Veränderungen
REST
Es gab:json
{ "id":"p1", "status":"authorized" }
Wurde (additiv, sicher):
json
{ "id":"p1", "status":"authorized", "risk_score": 0. 12 }
Kunden, die unbekannte Felder ignorieren, brechen nicht zusammen.
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'(Kernel) + 'Zahlung. enriched. v1'(Anreicherung). Die Konsumenten des kritischen Pfades lesen den Kern und sind nicht auf Anreicherungen angewiesen.
Anti-Pattern
Swagger-wash: Die Spezifikation ist formal da, aber das Verhalten des Dienstes steht im Widerspruch dazu.
Breaking by stealth: Typ/Status/Format ohne neue Version und Migrationsfenster geändert.
Rohe CDC-Ereignisse als öffentlicher Auftrag: Leckage von OBD-Schemata, Unmöglichkeit der Evolution.
Harter Client: fällt bei unbekannten Feldern/Werten; Fehlen eines toleranten Lesers.
Überverwendung von Protobuf-Tags: stille Datenkorruption.
Latenz als „non-contracting“: Unerwartet verlängerte p95 - Verbraucher brechen durch Timeouts.
Kompatibilitätscheckliste (vor dem Merge)
- Die Änderungen sind additiv (oder die Hauptversion ist vorbereitet).
- Linters/Diff-Checks sind bestanden, die Kompatibilitätsregeln sind grün.
- Fehler/Codes/Status haben die Semantik nicht verändert.
- Enum erweitert, ohne die alten Werte zu verbieten; Kunden sind tolerant.
- Die Grenzen des MGC sind unverändert.
- Beispiele/Dokumentation/SDK aktualisiert.
- Für Dur - Dual-Write/Dual-Emit-Plan, Sunset-Datum, Kommplan.
- Die Tests CDC/Golden/E2E bestanden.
FAQ
Wie unterscheidet sich backward von forward-Kompatibilität?
Backward - Neue Server brechen keine alten Clients. Vorwärts - Neukunden brechen nicht auf alten Servern ab (durch toleranten Reader und ordentliche Standardwerte).
Wann noch '/v2 'machen?
Wenn sich Invarianten/Semantik ändern, Felder/Methoden entfernt werden, ist ein neues Sicherheitsmodell erforderlich - es ist einfacher und ehrlicher, eine neue Linie zu starten.
Kann ich ohne Schema Registry/Linters leben?
Theoretisch - ja, praktisch - sind dies häufige Rückschritte und „versteckte“ Brüche. Automatisierung zahlt sich aus.
Kann Enum erweitert werden?
Ja, wenn Clients unbekannte Werte korrekt verarbeiten (fallback/ignore). Ansonsten in Major.
Summe
Vertragliche Kompatibilität ist Regeln + Disziplin + Automatisierung. Entwerfen Sie additiv, versionieren Sie brechende Änderungen, wenden Sie toleranten Leser an, überprüfen Sie Diffuse und CDC automatisch, planen Sie Deprecate. So können sich APIs schnell weiterentwickeln und Integrationen stabil bleiben.