{ }
GET
REST API · Backward Compatibility · Versionierung · OpenAPI
Backward Compatibility in API-Schemas
technisch absichern

Ein Breaking Change in einer REST-API ist kein Versionsproblem – es ist ein Vertragsproblem. Wenn Konsumenten sich auf ein Schema verlassen und der Provider es still verändert, entstehen Produktionsausfälle ohne Vorwarnung. Technische Absicherung bedeutet: Breaking Changes automatisch erkennen, Deprecation-Zyklen durchsetzen und Consumer-Driven Contract Tests als strukturelles Sicherheitsnetz einzusetzen.

16 Min. Lesezeit Breaking Changes · Versionierung · OpenAPI-Diff · Deprecation · Pact REST · HTTP · OpenAPI 3.x

1. Was ist ein Breaking Change und was nicht

Die Grenze zwischen einem harmlosen Update und einem Breaking Change ist in REST-APIs präzise definierbar, wird aber in der Praxis häufig intuitiv – und damit unzuverlässig – beurteilt. Ein Breaking Change ist jede Änderung, die bestehende Konsumenten dazu zwingt, ihren Code anzupassen, um die API weiterhin korrekt nutzen zu können. Das Umbenennen eines Feldes im Response-Body ist ein Breaking Change. Das Entfernen eines optionalen Feldes ist ein Breaking Change. Das Ändern des Datentyps eines bestehenden Feldes von string zu integer ist ein Breaking Change.

Was hingegen kein Breaking Change ist: Ein neues optionales Feld im Response hinzufügen. Einen neuen optionalen Query-Parameter einführen. Einen neuen HTTP-Statuscode für einen neuen Fehlerfall hinzufügen, solange bestehende Statuscodes unverändert bleiben. Einen neuen Endpunkt einführen. Gut implementierte API-Konsumenten schreiben defensiven Code: Sie ignorieren unbekannte Felder im Response und prüfen nur die Felder, die sie tatsächlich benötigen. Dieses Muster – bekannt als Robustheitsprinzip oder Postel's Law – ist Voraussetzung für stabile Schema-Evolution.

Die systematische Unterscheidung ist deshalb so wichtig, weil viele Teams Breaking Changes versehentlich einführen, weil sie nicht wissen, was genau als Breaking gilt. Eine klare, dokumentierte Klassifikation – idealerweise mit automatischer Prüfung in der CI-Pipeline – ist die Grundlage jeder verlässlichen Backward-Compatibility-Strategie.

2. Breaking Changes systematisch klassifizieren

Breaking Changes in REST-APIs lassen sich in vier Kategorien einteilen: Request-Breaking (Änderungen, die gültige Requests ungültig machen), Response-Breaking (Änderungen, die die Response-Struktur verändern), Semantic-Breaking (Änderungen, die die Bedeutung eines Endpunkts verändern, ohne das Schema zu ändern) und Protocol-Breaking (Änderungen an HTTP-Methoden, Statuscodes oder Auth-Mechanismen).

Semantic Breaking Changes sind die gefährlichsten, weil sie nicht automatisch erkannt werden können. Ein Endpunkt, der bisher alle aktiven Benutzer zurückgab, liefert nach einer stillen Änderung nur noch Benutzer der letzten 30 Tage – das Schema ist identisch, das Verhalten hat sich geändert. Diese Kategorie erfordert Consumer-Driven Contract Tests, die das erwartete Verhalten explizit beschreiben, nicht nur das Schema.


# Install openapi-diff for automated breaking change detection
npm install -g @openapitools/openapi-diff

# Compare two OpenAPI specs and detect breaking changes
openapi-diff old-openapi.json new-openapi.json

# Use oasdiff (Go-based, very fast)
brew install oasdiff
oasdiff breaking old-openapi.yaml new-openapi.yaml

# Integrate into CI: fail if breaking changes detected
oasdiff breaking old-openapi.yaml new-openapi.yaml --fail-on ERR

# Generate changelog between versions
oasdiff changelog old-openapi.yaml new-openapi.yaml --format text

3. API-Versionierungsstrategien im Vergleich

API-Versionierung ist kein Selbstzweck, sondern das Werkzeug, das Breaking Changes kontrollierbar macht. Es gibt vier gängige Ansätze: URI-Versionierung (/api/v1/, /api/v2/), Header-Versionierung (Accept: application/vnd.api+json;version=2), Query-Parameter-Versionierung (?version=2) und Content-Negotiation via Media Types. Jeder Ansatz hat unterschiedliche Konsequenzen für Caching, Routing, Client-Implementierung und Wartungsaufwand.

URI-Versionierung ist der populärste Ansatz, weil sie für Menschen lesbar ist und von Caching-Proxies korrekt behandelt wird. Der Nachteil: Versionsnummern in URIs verleiten dazu, zu früh zu versionieren und die alte Version zu lange zu pflegen. Die beste Strategie ist, Breaking Changes so lange wie möglich durch nicht-brechende Schema-Evolution zu vermeiden und Versionierung nur einzuführen, wenn fundamentale Umgestaltungen unvermeidlich sind. Kein Versionierungsschema ersetzt die Disziplin, Breaking Changes zu minimieren.

Strategie Caching Sichtbarkeit Empfehlung
URI /v1/ /v2/ Optimal Sehr hoch Standardfall, einfach zu handhaben
Accept-Header Vary-Header nötig Niedrig Sauber, aber komplexer für Clients
Query ?version= Funktioniert Mittel Einfach, aber semantisch fragwürdig
Media Type vnd. Komplex Sehr niedrig Nur für hypermedia-reife APIs

4. OpenAPI-Diff in der CI-Pipeline

Der wirksamste Mechanismus zur Verhinderung unbeabsichtigter Breaking Changes ist die automatische Diff-Prüfung in der CI-Pipeline. Werkzeuge wie oasdiff, openapi-diff oder Bump.sh vergleichen die OpenAPI-Spezifikation eines Pull-Requests mit der aktuell produktiven Version und klassifizieren jede Änderung als non-breaking, breaking oder potentially-breaking. Der Build schlägt fehl, wenn Breaking Changes ohne explizite Kennzeichnung eingeführt werden.

Die Prüfung läuft in zwei Schritten: Zuerst wird die OpenAPI-Spezifikation aus dem Quellcode generiert (bei API Platform via bin/console api:openapi:export, bei manuell gepflegten Specs durch Linting mit Spectral). Dann wird die generierte Spec gegen die zuletzt gemergte Version im Hauptbranch verglichen. Entwickler, die einen Breaking Change einführen müssen, können diesen explizit mit einem Release-Label kennzeichnen – der Build akzeptiert dann die Änderung, aber erzeugt automatisch einen Eintrag im Changelog und triggert den Deprecation-Workflow.

5. Deprecation-Header und Sunset richtig einsetzen

HTTP definiert standardisierte Mechanismen für die Ankündigung von API-Änderungen. Der Deprecation-Header (RFC 8594) signalisiert, dass ein Endpunkt oder ein Feature als veraltet gilt und in Zukunft entfernt wird. Der Sunset-Header (RFC 8594) gibt das genaue Datum an, ab dem der Endpunkt nicht mehr verfügbar sein wird. Der Link-Header mit rel="deprecation" verweist auf die Migrationsdokumentation. Diese drei Header zusammen bilden eine maschinenlesbare Deprecation-Kommunikation.

Gut implementierte API-Clients loggen Deprecation-Header automatisch und alarmieren die Entwickler, wenn veraltete Endpunkte aufgerufen werden. In Symfony lässt sich dieses Verhalten über einen Event-Subscriber implementieren, der bei jedem Response mit Deprecation-Header eine Log-Meldung schreibt. Die Kombination aus HTTP-Standard-Headern und automatisiertem Monitoring stellt sicher, dass der Sunset-Termin keine Überraschung für API-Konsumenten ist.


# Example HTTP response headers for a deprecated endpoint
# Deprecation: Tue, 01 Oct 2026 00:00:00 GMT
# Sunset: Tue, 01 Jan 2027 00:00:00 GMT
# Link: <https://api.mironsoft.de/migration/v2>; rel="deprecation"

# Check deprecation headers on live API with curl
curl -I https://api.mironsoft.de/v1/products/1 \
  -H "Accept: application/json" | grep -E "Deprecation|Sunset|Link"

# Monitor deprecated endpoint usage in application logs
grep "Deprecated endpoint called" /var/log/app/api.log | \
  awk '{print $5}' | sort | uniq -c | sort -rn

# Set Sunset date in Symfony response (EventSubscriber approach)
# $response->headers->set('Deprecation', 'Tue, 01 Oct 2026 00:00:00 GMT');
# $response->headers->set('Sunset', 'Tue, 01 Jan 2027 00:00:00 GMT');

6. Schema-Evolution ohne Breaking Changes

Die effektivste Strategie zur Absicherung von Backward Compatibility ist, Breaking Changes von Anfang an zu vermeiden. Das gelingt durch Techniken der additiven Schema-Evolution: Neue Felder werden als optional hinzugefügt. Bestehende Felder werden nie umbenannt – stattdessen wird ein neues Feld mit dem gewünschten Namen hinzugefügt, das alte bleibt als Deprecated bestehen. Werte-Enumerationen werden nur erweitert, nie verkleinert.

Ein besonders effektives Muster ist das Expand and Contract-Vorgehen für Request-Parameter: Zuerst wird der neue Parameter optional eingeführt (Expand). Wenn alle Konsumenten migriert haben, wird der alte Parameter als Deprecated markiert. Erst nach dem Sunset-Datum wird der alte Parameter entfernt (Contract). Dieses Muster erfordert Koordination und Monitoring, macht aber Breaking Changes vermeidbar – ohne auf die gewünschte Schema-Verbesserung zu verzichten.

7. Consumer-Driven Contract Tests mit Pact

Pact ist das bekannteste Framework für Consumer-Driven Contract Tests. Die Idee: Nicht der API-Anbieter definiert, was kompatibel ist – sondern jeder Konsument beschreibt in einem maschinenlesbaren "Pact"-Dokument, welche Anfragen er stellt und welche Responses er erwartet. Der Provider-Service verifiziert bei jedem Release, dass er alle Pacts aller bekannten Konsumenten erfüllt. Ein Breaking Change wird sofort sichtbar, bevor er die Konsumenten trifft.

Pact funktioniert mit einem zentralen Broker, dem Pact Broker (SaaS oder self-hosted), der alle Pact-Dokumente speichert und die Verifikationsergebnisse tracked. Der can-i-deploy-Befehl des Pact-Brokers beantwortet die Frage "Kann Provider v2.3 sicher deployed werden, ohne dass Konsumenten brechen?" mit einem maschinenlesbaren Ja oder Nein. Dieser Check wird als letzter Schritt vor jedem Deployment in der CI-Pipeline ausgeführt und verhindert, dass Breaking Changes unbemerkt in Produktion gelangen.

8. Breaking Changes kontrolliert einführen

Wenn ein Breaking Change unvermeidlich ist, folgt die kontrollierte Einführung einem strukturierten Prozess. Zuerst wird die neue Version des Endpunkts parallel zur alten eingeführt (zwei gleichzeitig verfügbare Versionen). Dann wird die alte Version mit Deprecation- und Sunset-Header versehen. Konsumenten werden aktiv kontaktiert und erhalten eine Migrationsfrist. Nach dem Sunset-Datum wird die alte Version in der Applikation deaktiviert, zunächst mit einer 410 Gone-Response statt einem 404 – das zeigt Konsumenten, die noch die alte Version aufrufen, dass der Endpunkt absichtlich entfernt wurde.

Der kritischste Schritt ist das Monitoring während der Migrationsfrist: Wie viele Requests kommen noch gegen die alte Version? Von welchen Clients? Welche Teams müssen noch migriert werden? Ohne dieses Monitoring ist es unmöglich, den Sunset-Termin verantwortungsvoll zu setzen. API-Gateways wie Kong, AWS API Gateway oder Nginx-Logs liefern diese Daten. Ein Dashboard mit der API-Version-Nutzung über Zeit ist das wichtigste Werkzeug für das Management von Breaking-Change-Migrationen.


# Analyze which API versions are still in use (Nginx log analysis)
awk '{print $7}' /var/log/nginx/api-access.log | \
  grep "^/api/" | \
  sed 's|/api/\(v[0-9]*\)/.*|\1|' | \
  sort | uniq -c | sort -rn

# Check if any clients still hit deprecated v1 endpoints
grep "/api/v1/" /var/log/nginx/api-access.log | \
  awk '{print $1, $7}' | tail -100

# After sunset: return 410 Gone for removed endpoints
# In Symfony routing: configure a catch-all for /api/v1/*
# that returns JSON: {"error": "API v1 has been sunset. Please migrate to /api/v2/"}

# Run Pact can-i-deploy check before every deployment
./vendor/bin/pact-broker can-i-deploy \
  --pacticipant "ProductAPI" \
  --version "2.3.0" \
  --to-environment production \
  --broker-base-url https://pact-broker.mironsoft.de

9. API-Kompatibilität im Betrieb überwachen

Backward Compatibility endet nicht mit dem Deployment – sie muss im Betrieb kontinuierlich überwacht werden. Das bedeutet: Monitoring der Fehlerraten pro API-Version, Tracking der noch genutzten deprecated Endpunkte, Alerting wenn ein Konsument einen Endpunkt aufruft, der in weniger als 30 Tagen seinen Sunset-Termin erreicht. Diese Informationen kommen aus Access-Logs, API-Gateway-Metriken und Application-Performance-Monitoring-Systemen.

Ein praktisches Werkzeug ist das API-Kompatibilitäts-Dashboard: Es zeigt für jede API-Version die Anzahl aktiver Konsumenten, die Aufruffrequenz deprecated Endpunkte und den verbleibenden Zeitraum bis zum nächsten Sunset-Termin. Dieses Dashboard ist nicht nur für das Entwicklungsteam relevant – es ist das wichtigste Kommunikationsmittel mit Konsumenten-Teams, Partnern und Stakeholdern, die wissen müssen, wann sie migrieren müssen.

10. Zusammenfassung

Backward Compatibility in REST-API-Schemas technisch abzusichern bedeutet, vier Mechanismen gleichzeitig zu betreiben: Automatische Breaking-Change-Erkennung mit OpenAPI-Diff-Tools in der CI-Pipeline. Deprecation-Kommunikation über standardisierte HTTP-Header (Deprecation, Sunset, Link). Consumer-Driven Contract Tests mit Pact, die sicherstellen, dass kein Deployment Konsumenten bricht. Migration-Monitoring, das zeigt, welche Konsumenten noch migriert werden müssen und ob der Sunset-Termin realistisch ist.

Die technischen Werkzeuge sind nur so wirksam wie die Disziplin, sie konsequent einzusetzen. Eine OpenAPI-Diff-Prüfung, die manuell umgangen werden kann, schützt nicht. Ein Deprecation-Header ohne Monitoring ist wirkungslos. Consumer-Driven Contract Tests ohne aktive Teilnahme der Konsumenten-Teams sind leer. Backward Compatibility ist kein technisches Problem allein – es ist eine Koordinationsaufgabe, die technische Werkzeuge als Grundlage und Teamdisziplin als Überbau braucht.

Mironsoft

API-Design, Backward Compatibility und Migrationsstrategie

API-Kompatibilität strukturell absichern?

Wir analysieren Ihre API-Schnittstellen, richten OpenAPI-Diff in der CI-Pipeline ein und implementieren Consumer-Driven Contract Tests mit Pact – damit kein Breaking Change unbemerkt in Produktion gelangt.

Breaking-Change-Audit

Analyse bestehender APIs auf undokumentierte Breaking Changes und Versionierungslücken

CI-Diff-Pipeline

oasdiff oder openapi-diff in GitHub Actions/GitLab CI mit automatischem Changelog integrieren

Pact-Integration

Consumer-Driven Contract Tests einrichten und can-i-deploy vor jedem Deployment prüfen

Backward Compatibility in API-Schemas — Das Wichtigste auf einen Blick

Breaking vs. Non-Breaking

Felder umbenennen/entfernen = Breaking. Optionale Felder hinzufügen = Non-Breaking. Enumerate erweitern = Non-Breaking. Typen ändern = Breaking.

OpenAPI-Diff in CI

oasdiff oder openapi-diff vergleichen Specs automatisch. Build schlägt fehl bei ungekennzeichneten Breaking Changes. Changelog wird generiert.

Deprecation-Header

Deprecation + Sunset + Link-Header (RFC 8594) sind maschinenlesbar. Clients loggen sie automatisch. Sunset-Termin kommuniziert verbindlich.

Consumer-Driven Pact

Konsumenten definieren ihre Erwartungen als Pact. Provider verifiziert alle Pacts vor jedem Deployment. can-i-deploy als letzter CI-Check.

11. FAQ: Backward Compatibility in API-Schemas

1Was ist ein Breaking Change?
Jede Änderung, die Konsumenten zwingt, ihren Code anzupassen: Felder umbenennen, Typen ändern, Pflichtfelder hinzufügen, HTTP-Methoden ändern.
2Neues Feld im Response = Breaking Change?
Nein – solange Clients unbekannte Felder ignorieren (Postel's Law). Optionale Felder hinzufügen ist immer non-breaking.
3Welche Versionierungsstrategie empfehlen?
URI-Versionierung (/api/v1/) ist am pragmatischsten. Wichtiger: Versionierung erst einführen, wenn Breaking Changes wirklich unvermeidlich sind.
4oasdiff vs. openapi-diff?
oasdiff ist schneller, aktiver gepflegt und klassifiziert Änderungen granular (ERR/WARN/INFO). Direkte CI-Integration mit --fail-on ERR.
5Wie lange deprecated Endpunkt verfügbar lassen?
Mindestens 6 Monate intern, 12 Monate für öffentliche APIs. Sunset-Termin erst setzen, wenn Monitoring zeigt, dass alle Konsumenten migriert sind.
6Deprecation vs. Sunset-Header?
Deprecation = veraltet, keine Weiterentwicklung. Sunset = konkretes Entfernungsdatum. Beide RFC 8594, maschinenlesbar, loggbar durch API-Clients.
7Wie funktioniert Pact?
Consumer schreibt Erwartungen als Pact-Dokument. Provider verifiziert alle Pacts. can-i-deploy prüft vor jedem Deployment, ob alle Konsumenten kompatibel sind.
8Was nach dem Sunset-Termin?
HTTP 410 Gone (nicht 404) mit erklärendem JSON-Body und Migrationsdokumentation. 410 signalisiert absichtliche Entfernung.
9Semantic Breaking Changes automatisch erkennen?
Nicht durch Schema-Diff allein möglich. Consumer-Driven Contract Tests und BDD-Tests (Cucumber/Behat) sind die einzigen automatischen Erkennungsmechanismen.
10Was ist Expand and Contract?
Breaking-Change-freies Migrationsmuster: Neue Version parallel einführen (Expand), nach Migration alte entfernen (Contract). Zwischen beiden Schritten können Monate liegen.

Backward Compatibility in REST-APIs erfordert Disziplin und klare Prozesse. Mit OpenAPI als Single Source of Truth, automatisierten Breaking-Change-Checks in der CI und einem Expand-Contract-Migrationsmuster lassen sich API-Schemas langfristig stabil halten.