Data contracts for producers and consumers

A contract is an agreement about what a producer sends and what a consumer can rely on. A schema handles structure; the complete contract also describes meaning, change policy, delivery behavior, and ownership.

Field definitions and ownership
Invoice contract exampleContract · v1

ProducerAccounts receivable

ConsumerInvoice projection

idinv_1042
One invoice in the agreed source namespace.
currencyGBP
A supported currency, with its precision agreed.
amountMinor125000
Integer minor units.
GBP 1,250.00.

The contract defines each field’s format, meaning and owner.

Cover meaning as well as structure

Document the grain, identifier rules, units, time semantics, source authority, and allowed null values. A numeric amount without a currency and rounding convention is not a complete interface. Distinguish an absent field from an explicit null and from a value that was redacted by policy.

Assign a producer owner and identify important consumers. Specify how breaking changes are proposed, how compatibility is checked, and who responds when the contract is violated. A schema registry can store versions, but it cannot resolve a disagreement about whether invoice status means a source state or a derived assessment.

Two colleagues reviewing a field definition on a shared screen.
Source owners confirm field definitions before publication.

Validate structure at the boundary

JSON Schema can express types, required fields, allowed values, and numeric constraints. The invoice schema requires an identifier, currency and an amount in integer minor units. Additional properties are permitted, allowing compatible consumers to accept new optional fields.

Choose the schema dialect explicitly and configure the validator consistently. In JSON Schema 2020-12, format handling depends on the vocabulary and implementation configuration; a date format annotation should not be assumed to enforce every business time rule. Structural validation must be complemented by semantic checks and authorization.

json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["id", "currency", "amountMinor"],
  "properties": {
    "id": { "type": "string", "minLength": 1 },
    "currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
    "amountMinor": { "type": "integer", "minimum": 0 }
  }
}

Example invoice schema. Validate supported currencies and precision in the business rules.

Agree on delivery and invalid records

Specify whether messages can repeat, arrive late, or be delivered out of order. Define event identity, the applicable retention window, and how consumers request replay. A payload can be perfectly valid while still being unusable because it arrives after the decision window or refers to an unknown entity.

Choose a quarantine policy for invalid records. Store enough diagnostic context to repair the problem without copying sensitive payloads into unrestricted logs. Acknowledge only according to the agreed durability boundary, and make rejected records visible to an accountable owner. Silent dropping hides data loss behind an apparently healthy pipeline.

Test compatibility with consumers

Keep representative fixtures for each published contract version, including optional fields, nulls, boundary values, and unknown enumeration values. Run producer validation and consumer compatibility checks during change review. An added field can break consumers that reject unknown properties, and a new enum value can break consumers that exhaustively match existing values.

Include a deprecation window and migration evidence rather than relying on a version number alone. For semantic changes, reconcile old and new outputs on the same input set. The contract should let a team explain what changed, which consumers are affected, and how a rollback or correction would be performed.

References