GH GambleHub

API Contract Compatibility

Why Contract Compatibility

Contract compatibility is the ability of an API to evolve without breaking existing integrations. In growing systems, APIs change more often than client code; compatibility allows you to release features iteratively, without arranging "big moves."

The key idea: the contract is primary, changes are carried out according to compatibility rules and are checked automatically.

Basic concepts

Contract - formal interface specification: resources/methods/events, data schemas, error codes, limits, SLAs, security requirements.
Provider - The owner of the API. Consumer - Client/Integration.

Compatibility:
  • Backward: The new supplier works with old consumers.
  • Forward: The old supplier works with new consumers (usually achieved by "tolerant readers").
  • Full: both backward and forward (the strongest option) are observed.
  • Additivity - add optional elements without breaking existing ones.

Versioning Policy

Semantic Versioning (recommended):
  • MAJOR - breaking changes (only when a new API line is released: '/v2 ',' service. v2`).
  • MINOR - additive changes (new optional fields/methods).
  • PATCH - fixes without changing the contract.
  • Rejection Policy: declaration of obsolete elements, support window (sunset), warnings in headers/metadata, withdrawal plan.

Safe vs dangerous changes

Secure (usually backward-compatible)

Add an optional field to JSON/Protobuf/Avro.
Add a new endpoint/method/event.
Extending enum with new values if consumers are tolerant of unknown values.
Raising limits (for example, 'maxItems') without tightening the minimum.
Adding nullable with correct defaults.
Edit description/example text.

Dangerous (breaks compatibility)

Rename/delete fields, change their type or mandatory.
Status code/error semantics change (for example, was' 200 ', became' 204'or' 404 ').
Changing the format of identifiers (UUID → int).
Tightening of validation (stricter minimums/patterns) without version.
Changing the order and structure in gRPC streams/events.
Reuse tag numbers in Protobuf for new fields.

Interoperability by Interaction Style

REST/HTTP + JSON Schema

Additivity: we mark new fields as' optional '/' nullable '.
Tolerant Reader at the client: ignore unknown fields; not relying on order.
Versioning: major - on the way ('/v2 ') or in the media type (' application/vnd. example. v2+json`).
ETag/If-Match: for safe updates without racing.
Errors: single format ('type', 'code', 'title', 'detail', 'trace _ id'), do not change the value of'code' without a major.
Pagination: cursors are preferable to offset; add 'next _ cursor' fields, do not change the meaning of existing ones.

gRPC / Protobuf

Tag numbering is unchanged. Deleted tags cannot be reused.
The new fields are 'optional '/' repeated' with reasonable defaults on the server.
Do not change the order and mandatory messages in streaming-RPC.
Error statuses are stable ('INVALID _ ARGUMENT', 'FAILED _ PRECONDITION', etc.); new semantics → a new version of the method/service.

Event-driven (Kafka/NATS/Pulsar) + Avro/JSON Schema

Naming events: 'domain. action. v{major}`.
New fields are optional; isolate core and enrichment ('.enriched').
Schema registers: compatibility rules (BACKWARD/FORWARD/FULL) on theme/event.
The enum extension is valid for consumer-side tolerant reader.
Partition/order key change for aggregate = breaking changes.

GraphQL

Adding fields/types is safe; delete/rename - only through @ deprecated and the migration window.
Do not change types/non-nullable without major.
Control complexity/depth - limits are part of the contract.

Sustainable evolution patterns

Additive-first: Expand without breaking.
Capability negotiation: clients report that they support (headers/parameters/agreements), the server adjusts.
Contract boundaries: Fix MGC (minimum warranty contract) and separate extensions (reverse pyramid model).
Tolerance by default: clients ignore unnecessary and correctly handle unknown enum (fallback) values.
Dual-write/Dual-emit: for major changes, release 'v1' and 'v2' in parallel for a while.
Sunset headers/Events: Notify in advance when versions are removed.

Governance and Automation

API Linters:
  • OpenAPI/Spectral: naming, pagination, error codes, field formats.
  • Buf/Protobuf: disallowing re-use of tags, packet notation.
  • AsyncAPI/Schema Registry: CI-level schema compatibility.
  • Contract Catalog (SSOT): Centralized schema/version register with diffuse history.
  • API Guild: guild/committee that adopts rules, templates and review changes.
  • Change Management: RFC/ADR, release notes, migration guides.

Compatibility testing

Schema-diff in CI: block breaking cakes (OpenAPI-diff, Buf breaking, SR compatibility).
Consumer-Driven Contracts (CDC): Pact/Similar - Supplier vs. Consumer-Specific Contracts.
Golden samples: reference queries/responses and events for regression.
E2E Canary: rolling out to the share of traffic/individual consummer groups.
Chaos/latency: Timeout/Retray check - A latency-SLO change is considered a contract change.

Migrations and deprecate

1. Declare deprecate: Mark the item, specify sunset term and alternative.
2. Maintain compatibility period: dual-write/dual-emit, bridges, adapters.
3. Collect telemetry: who else uses the old?
4. Communication: mailings, release notes, test stands.
5. Removal: after the window expires - removal with a fixed release.

Examples of changes

REST

It was:
json
{ "id":"p1", "status":"authorized" }
Became (additive, safe):
json
{ "id":"p1", "status":"authorized", "risk_score": 0. 12 }

Clients that ignore unknown fields do not break.

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 '(core) +' payment. enriched. v1 '(enrichment). Critical path consumers read the core and are not dependent on enrichment.

Antipatterns

Swagger-wash: there is formally a specification, but the behavior of the service is at odds with it.
Breaking by stealth: changed type/status/format without a new version and migration window.
Raw CDC events as a public contract: leaked DB schemes, impossibility of evolution.
Hard client: drops at unknown fields/values; absence of a tolerant reader.
Re-using protobuf tags: quiet data corruption.
Latency as "non-contract": p95 was unexpectedly lengthened - consumers break down in timeouts.

Compatibility checklist (before merge)

  • Changes are additive (or major version prepared).
  • Linters/diff checks passed, compatibility rules are green.
  • Errors/codes/statuses did not change semantics.
  • Enum extended without prohibiting old values; clients - tolerant.
  • The boundaries of the MGC are unchanged.
  • Updated samples/documentation/SDK.
  • For major - dual-write/dual-emit plan, sunset-date, comm-plan.
  • Tests CDC/Golden/E2E passed.

FAQ

How does backward differ from forward compatibility?
Backward - new servers do not break old clients. Forward - new clients do not break on old servers (via tolerant reader and neat defaults).

When do you do '/v2 '?
When invariants/semantics change, fields/methods are deleted, a new security model is required - it is easier and more honest to start a new line.

Can you live without Schema Registry/linters?
Theoretically - yes, practically - these are frequent regressions and "hidden" breakdowns. Automation pays off.

Enum can be extended?
Yes, if clients correctly handle unknown values (fallback/ignore). Otherwise - major.

Total

Contract compatibility is rules + discipline + automation. Design additively, version breaking changes, apply a tolerant reader, automatically check diffs and CDC, plan deprecate. This way APIs can evolve quickly and integrations can remain stable.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Telegram
@Gamble_GC
Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.