Series MapLesson 84 / 112
Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Deepen PracticeOrdered learning track

Centralized Contract Strategy

Centralized Contracts OpenAPI AsyncAPI Protobuf gRPC Kafka

Contract governance across HTTP, Kafka, gRPC, and event-driven integrations using OpenAPI, AsyncAPI, protobuf, compatibility matrices, generated clients/servers, and review gates

9 min read1756 words
PrevNext
Lesson 84112 lesson track62–92 Deepen Practice
#openapi#asyncapi#protobuf#grpc+5 more

Part 084 — Centralized Contracts: OpenAPI, AsyncAPI, Protobuf, gRPC, Kafka

Fokus part ini: memperlakukan contract sebagai artifact engineering yang versioned, reviewed, tested, generated, dan enforced; bukan dokumentasi sampingan yang tertinggal dari implementation.

Enterprise backend tidak hanya punya “API”. Ia punya banyak contract:

HTTP request/response contract
Kafka event contract
gRPC service contract
batch file contract
callback/webhook contract
error contract
auth/security contract
observability metadata contract

Jika contract tersebar di code, wiki, Slack, dan asumsi tribal knowledge, maka perubahan kecil bisa menjadi production incident.

Prinsip utama:

A contract is a compatibility boundary.
A compatibility boundary must be explicit, versioned, reviewed, tested, and owned.

1. Core Mental Model

Centralized contract strategy menjawab:

What do we expose?
Who consumes it?
What changes are safe?
How do we detect breaking changes?
How do we generate clients/servers/types?
How do we deprecate old behavior?
How do we prove compatibility before deploy?

Tanpa governance, service integration berubah menjadi runtime guessing game.

Dengan governance:

contract change -> lint -> compatibility check -> generated artifacts -> tests -> review -> release

2. Contract Types in Enterprise Backend

HTTP API contract

Biasanya direpresentasikan dengan:

  • OpenAPI
  • JSON Schema fragments
  • generated client SDK
  • generated server interface/stub
  • API linting rules
  • compatibility diff

Kafka/event contract

Biasanya direpresentasikan dengan:

  • AsyncAPI
  • Avro schema
  • JSON Schema
  • Protobuf schema
  • Schema Registry
  • event catalog
  • compatibility mode

gRPC contract

Direpresentasikan dengan:

  • .proto
  • service definitions
  • message definitions
  • generated Java clients/servers
  • protobuf compatibility rules

Batch/file contract

Bisa berupa:

  • CSV schema
  • fixed-width file spec
  • JSONL schema
  • XML schema
  • checksum/manifest contract
  • naming convention
  • folder/object key convention

Cross-cutting contract

Sering dilupakan:

  • error shape
  • correlation header
  • idempotency key
  • tenant header/claim
  • pagination format
  • timestamp format
  • currency/precision rule
  • auth scope/permission
  • deprecation header

3. OpenAPI for HTTP APIs

OpenAPI cocok untuk mendefinisikan:

paths
methods
request parameters
request body
response body
status codes
headers
security scheme
schema components
examples

OpenAPI sebaiknya tidak hanya dipakai untuk dokumentasi Swagger UI.

Gunakan untuk:

  • linting API style
  • breaking-change detection
  • generated clients
  • generated server interfaces
  • contract tests
  • mock server
  • consumer review
  • API catalog

Contract-first vs code-first

Contract-first

OpenAPI spec -> generated server interface/client -> implementation

Kelebihan:

  • contract jelas sebelum code
  • consumer bisa review lebih awal
  • breaking changes lebih mudah dideteksi

Risiko:

  • spec terlalu jauh dari implementation jika tidak ada validation
  • generated code bisa tidak cocok dengan style internal

Code-first

JAX-RS annotations -> generated OpenAPI spec

Kelebihan:

  • lebih dekat dengan implementation
  • developer friction lebih rendah

Risiko:

  • design API mengikuti code structure
  • docs bisa tidak cukup kaya
  • breaking changes baru terlihat setelah implementation

Senior recommendation:

Pick one source of truth.
Then enforce drift detection.

Yang berbahaya bukan contract-first atau code-first.

Yang berbahaya adalah:

multiple sources of truth with no drift control

4. API Linting

API linting adalah static analysis untuk contract.

Rules bisa mencakup:

path naming
method semantics
status code usage
error response consistency
pagination shape
required headers
operationId naming
schema naming
no anonymous inline schemas for shared models
no unbounded arrays
no ambiguous nullable fields
security requirement present
no undocumented 5xx response

Contoh governance rule:

Every mutating POST endpoint must document:
  - success response
  - validation error
  - auth error
  - conflict error if applicable
  - idempotency behavior if retryable

Linting membuat review lebih murah.

Tanpa linting, reviewer mengulang komentar yang sama di setiap PR.


5. Generated Client and Server

Generated artifact bisa membantu mengurangi drift.

Generated client

Kelebihan:

  • consumer tidak membuat request manual
  • type safety lebih baik
  • endpoint/path/schema konsisten
  • breaking change lebih cepat terlihat saat compile/test

Risiko:

  • generated client menyembunyikan HTTP semantics
  • timeout/retry/error mapping bisa buruk jika tidak dikonfigurasi
  • versi client bisa tertinggal
  • binary compatibility issue

Generated server

Kelebihan:

  • implementation wajib mengikuti contract
  • missing endpoint cepat terlihat
  • response model lebih konsisten

Risiko:

  • generated interface terlalu verbose
  • framework integration tidak natural
  • developer menambahkan bypass endpoint manual

Senior rule

Generate types and boundary interfaces when useful.
Do not let generated code hide resilience, security, and observability policies.

6. AsyncAPI for Event and Messaging Contracts

AsyncAPI bisa mendokumentasikan:

channels/topics
publish/subscribe direction
message schema
headers
bindings
security
examples

Untuk Kafka, AsyncAPI bisa membantu menjawab:

Which service publishes this event?
Which services consume it?
What is the message schema?
What headers are required?
What is the partition key?
What compatibility rule applies?
What is the replay policy?

AsyncAPI bukan pengganti Schema Registry.

Model yang sehat:

AsyncAPI = human/system catalog + integration documentation
Schema Registry = runtime/CI compatibility enforcement for schemas

7. Protobuf and gRPC Contracts

Protobuf/gRPC contract terdiri dari:

syntax = "proto3";

service QuoteService {
  rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse);
}

message GetQuoteRequest {
  string quote_id = 1;
}

message GetQuoteResponse {
  string quote_id = 1;
  string status = 2;
}

Important invariants:

field numbers are part of the contract
field names are less important than field numbers for wire compatibility
never reuse deleted field numbers
reserve removed fields
avoid changing field type incompatibly

Example:

message QuoteEvent {
  reserved 4;
  reserved "old_price_field";

  string quote_id = 1;
  string status = 2;
  int64 version = 3;
}

Protobuf is not automatically “safe”. It is safe only if evolution rules are followed.


8. Kafka Event Contract Strategy

A Kafka event contract should define:

event name
topic name
producer owner
consumer list
schema
schema format
required headers
partition key
ordering expectation
idempotency key
correlation/causation headers
replay support
retention expectation
compatibility mode
deprecation policy

Contract example as conceptual model:

event: QuoteApproved
topic: quote.lifecycle.events
owner: quote-service
schema: quote-approved.avsc
partitionKey: quoteId
compatibility: BACKWARD
headers:
  - traceparent
  - correlation-id
  - causation-id
  - event-id
  - tenant-id
replay: supported
idempotency: event-id
ordering: per quoteId

Senior review asks:

Can a new consumer understand old events?
Can an old consumer ignore new fields?
Can events be replayed safely?
Can duplicate events be detected?
Can event ownership be identified?

9. Compatibility Matrix

A compatibility matrix makes change safety explicit.

Example:

Contract typeAdd optional fieldRemove fieldRename fieldChange typeAdd enum valueRemove enum value
HTTP JSON responseUsually safeBreakingBreakingBreakingRiskyBreaking
HTTP JSON requestUsually safe if ignoredRiskyBreakingBreakingRiskyBreaking
Avro backward modeDepends on defaultBreakingBreakingBreakingRiskyBreaking
ProtobufUsually safe with new field numberReserve onlyRiskyBreakingRiskyBreaking
gRPC serviceAdd method safeBreaking if removedBreakingBreakingRiskyBreaking

Matrix harus dikonkretkan sesuai platform internal.

Internal verification checklist

Cek:

  • Compatibility mode Schema Registry.
  • API diff tooling.
  • OpenAPI lint rules.
  • Protobuf breaking-change checker.
  • Whether enum evolution has special policy.
  • Whether consumers tolerate unknown fields.
  • Whether generated clients are strict or lenient.

10. Backward and Forward Compatibility

Backward compatibility

New producer/server can be consumed by old consumer/client.

Example:

server adds optional response field
old client ignores unknown field

Forward compatibility

Old producer/server output can be consumed by new consumer/client.

Example:

new consumer can read old event that lacks newly optional field

Full compatibility

Both directions work.

In event-driven systems, full compatibility matters because old events can be replayed.

Kafka retention + replay means old messages are part of the future.

11. Error Contract Governance

Error contract harus distandardkan.

Example:

{
  "errorCode": "QUOTE_NOT_FOUND",
  "message": "Quote was not found",
  "correlationId": "c-123",
  "details": [
    {
      "field": "quoteId",
      "reason": "unknown"
    }
  ]
}

Governance questions:

Are error codes stable?
Are messages safe to expose?
Is correlation ID always present?
Are validation errors shaped consistently?
Are retryable errors distinguishable?
Are auth errors consistent?

Do not let every resource class invent its own error shape.


12. Header Contract Governance

Headers are contract too.

Common enterprise headers:

Authorization
traceparent
tracestate
correlation-id
causation-id
idempotency-key
tenant-id
request-id
accept-language
content-type
accept

Rules needed:

  • which headers are required inbound
  • which headers are propagated outbound
  • which headers are generated if missing
  • which headers are forbidden from external clients
  • which headers are internal only
  • how tenant identity is validated
  • how correlation and trace context interact

Header drift is a common integration bug.


13. Contract Ownership

Every contract needs an owner.

Bad ownership model:

Topic exists but no one owns schema.
Endpoint exists but no one owns compatibility.
Generated client exists but no one owns versioning.

Good ownership model:

contract owner
implementation owner
consumer owner
review approver
support/runbook owner

For enterprise CPQ/order systems, contracts may represent business-critical flows:

  • quote creation
  • quote approval
  • catalog update
  • pricing calculation
  • order submission
  • order amendment
  • billing handoff
  • document generation

Changing such contracts without ownership is high-risk.


14. Contract Repository Patterns

Pattern A — Contract in service repository

service-a/
  src/
  contracts/
    openapi.yaml
    asyncapi.yaml
    events/
      quote-approved.avsc

Good when:

  • contract lifecycle tightly follows service
  • service owns producer/server side

Risk:

  • consumers may not discover changes easily
  • cross-service governance harder

Pattern B — Central contract repository

contracts/
  http/
  events/
  grpc/
  schemas/

Good when:

  • many consumers
  • platform governance required
  • shared generated clients

Risk:

  • extra PR coordination
  • implementation drift if not enforced

Pattern C — Hybrid

service owns source contract
central catalog indexes published contracts
CI publishes generated artifacts

Often best in large organizations.


15. CI/CD Contract Gates

A healthy pipeline checks:

OpenAPI lint
OpenAPI breaking diff
schema compatibility
protobuf breaking diff
generated code compile
contract tests
consumer-driven contract verification
artifact publishing
catalog publishing

Example flow:

PR changes API schema
  -> lint contract
  -> compare against latest released version
  -> detect breaking change
  -> require migration/deprecation plan
  -> generate client
  -> run tests
  -> publish versioned artifact

Without gates, compatibility review depends on human memory.

Human memory is not a governance system.


16. Generated Client Versioning

Generated clients need versioning policy.

Questions:

Is generated client published to internal Maven repository?
Does client version match API version or service version?
Can multiple client versions coexist?
How are deprecated endpoints represented?
How do consumers upgrade?
Are generated clients source-compatible or binary-compatible?

Anti-pattern:

Every consumer generates its own client differently.

Problem:

  • inconsistent timeout
  • inconsistent serialization
  • inconsistent auth
  • inconsistent error handling
  • drift from official contract

Better:

generated base client + internal wrapper with platform policies

17. Contract Testing Strategy

Contract tests answer:

Does provider still satisfy the contract?
Does consumer still understand provider output?
Does event consumer still parse valid events?
Does generated client still work against deployed service?

Types:

Provider contract test

Implementation -> must match OpenAPI/AsyncAPI/schema

Consumer contract test

Consumer expectation -> provider must satisfy

Schema compatibility test

New schema -> compatible with previous schema under configured mode

Replay compatibility test

New consumer -> can process old retained/replayed events

For event systems, replay compatibility is often more important than “latest schema only” compatibility.


18. Deprecation and Sunset

Deprecation policy should define:

how to mark deprecated endpoint/event/field
how long it remains supported
how consumers are notified
how usage is measured
what sunset date means
what happens after sunset
who approves removal

HTTP can use headers:

Deprecation
Sunset
Link: rel="deprecation"

Event deprecation requires:

consumer inventory
topic usage metrics
dual-publish period
migration guide
replay consideration
schema compatibility plan

Do not remove contract elements only because “no one should be using it”.

Prove usage.


19. Contract Compatibility and Deployment Strategy

Contract evolution must align with deployment order.

Safe rollout pattern:

1. Expand provider/server schema.
2. Deploy provider accepting old and new forms.
3. Upgrade consumers gradually.
4. Observe usage.
5. Stop producing old field/contract.
6. Remove old support after deprecation window.

For database + API + event changes:

DB expand
server supports both
producer emits backward-compatible event
consumer upgraded
DB contract cleaned later

Contract governance is tightly connected with expand-contract migration and progressive delivery.


20. Failure Modes

Documentation drift

Cause:

OpenAPI manually updated but implementation differs

Detection:

contract test fails
client receives undocumented status/schema

Fix:

single source of truth
drift detection
provider tests

Breaking change shipped silently

Cause:

field removed/renamed without compatibility gate

Detection:

consumer deserialization failure
increase in 4xx/5xx
DLQ spike

Fix:

breaking diff tool
schema registry compatibility
consumer inventory

Generated client hides bad defaults

Cause:

no timeout/retry/error policy wrapper

Detection:

threads stuck
unbounded wait
inconsistent error handling

Fix:

platform client wrapper
mandatory timeout config
central error decoder

Event replay breaks new consumer

Cause:

new consumer assumes new field exists
old retained events lack field

Detection:

replay job fails
consumer crashes after reset offset

Fix:

forward compatibility tests
default values
replay test suite

Enum expansion breaks clients

Cause:

consumer switch statement has no default
unknown enum rejected

Detection:

runtime mapping exception
unknown value error

Fix:

UNKNOWN fallback
consumer tolerance rule
enum change policy

21. Debugging Contract Incidents

When a contract incident happens:

1. Identify contract type: HTTP, event, gRPC, file.
2. Identify producer/provider version.
3. Identify consumer/client version.
4. Compare runtime payload with published contract.
5. Check generated artifact version.
6. Check recent schema/API changes.
7. Check compatibility gate result.
8. Check consumer tolerance for unknown/missing fields.
9. Check deployment order.
10. Check deprecation/removal history.

Evidence to collect:

  • raw sanitized payload
  • OpenAPI/AsyncAPI/proto/schema version
  • producer commit/build version
  • consumer commit/build version
  • generated client version
  • schema registry compatibility logs
  • CI contract check output
  • consumer error logs
  • DLQ messages
  • trace/correlation ID

22. PR Review Checklist

HTTP/OpenAPI

  • Is OpenAPI updated?
  • Is implementation aligned?
  • Are status codes documented?
  • Are headers documented?
  • Is error shape consistent?
  • Is the change backward-compatible?
  • Is deprecation needed?
  • Is API lint passing?
  • Is generated client updated?

Events/AsyncAPI/Schema

  • Is event owner clear?
  • Is schema updated?
  • Is compatibility mode satisfied?
  • Is partition key documented?
  • Are headers documented?
  • Is replay behavior documented?
  • Are duplicate and ordering policies clear?
  • Are consumers identified?

Protobuf/gRPC

  • Are field numbers preserved?
  • Are removed fields reserved?
  • Are service methods backward-compatible?
  • Are generated stubs updated?
  • Is breaking-change checker passing?

Cross-cutting

  • Are correlation/trace headers preserved?
  • Is tenant context represented correctly?
  • Are auth scopes/permissions documented?
  • Are examples updated?
  • Are tests updated?

23. Internal Verification Checklist

For CSG Quote & Order or similar enterprise systems, verify:

HTTP contract

  • Is OpenAPI used?
  • Is it contract-first, code-first, or hybrid?
  • Where is the source of truth?
  • Is OpenAPI linting enforced in CI?
  • Is breaking-change detection enforced?
  • Are generated clients/servers used?

Event contract

  • Is AsyncAPI used?
  • Is Schema Registry used?
  • Which schema format is used: Avro, JSON Schema, Protobuf, custom JSON?
  • What compatibility mode is configured?
  • Is there an event catalog?
  • Are event owners documented?

gRPC/protobuf

  • Is gRPC used internally?
  • Where are .proto files stored?
  • Is breaking-change detection enforced?
  • Are generated stubs published as artifacts?

Governance

  • Who approves contract changes?
  • Is there an API review board/process?
  • Is there a compatibility matrix?
  • Is deprecation policy documented?
  • Are consumers inventoried?
  • Are contract artifacts published to internal registry/catalog?

Runtime validation

  • Are provider contract tests run?
  • Are consumer contract tests run?
  • Are schema compatibility tests run?
  • Are replay compatibility tests run?
  • Are generated clients tested against provider?

24. Senior Engineer Heuristics

Use these rules:

If other teams consume it, it is a contract.
If it is persisted in Kafka, it is a long-lived contract.
If it is generated into client code, it is a compile-time contract.
If it crosses tenant/security boundary, it is also a policy contract.
If it can be replayed, old data must remain readable.
If it can be retried, idempotency must be specified.

A senior engineer does not ask only:

Did we update the docs?

They ask:

What is the source of truth?
Who owns this contract?
What change is compatible?
Which consumers are affected?
What gate prevents accidental breaking change?
How do we deprecate and remove safely?
Can old events still be processed?
Can generated clients be upgraded safely?

25. Summary

Centralized contracts are production controls.

Key takeaways:

  • Contracts are compatibility boundaries.
  • OpenAPI governs HTTP APIs.
  • AsyncAPI helps catalog and describe messaging contracts.
  • Schema Registry enforces event schema compatibility.
  • Protobuf/gRPC require strict field-number discipline.
  • Generated clients reduce drift but must not hide resilience/security policies.
  • API linting prevents repeated governance mistakes.
  • Compatibility matrix makes review concrete.
  • Deprecation requires consumer inventory and telemetry.
  • CI/CD gates should enforce contract safety before deployment.

In enterprise systems, contract governance is not bureaucracy.

It is how teams change independently without breaking each other.

Lesson Recap

You just completed lesson 84 in deepen practice. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.