Cross-service contracts¶
When two services produce and consume the same message, the contract registry enforces field-shape agreement across language boundaries with case-tolerant validation.
Producer service¶
"produces_contracts": [{
"name": "events.raw",
"transport": "kafka:events.raw",
"fields": [
{"name": "id", "type": "str"},
{"name": "received_at", "type": "str"},
{"name": "headers", "type": "dict[str, str]"},
{"name": "payload", "type": "str"}
]
}]
Consumer service¶
"consumes_contracts": [{"contract_name": "events.raw", "role": "consumes"}]
How the registry works¶
- The producer's run writes its declaration to disk (the contract registry).
- The consumer's run resolves the named contract and validates that its
ConsumedEvententity carries the same field names verbatim. - Validation is case-tolerant across language boundaries: Java's
receivedAtmatches Python'sreceived_at(both normalize toreceivedat). - A renamed field (e.g.
bodyvspayload) still fails — case-tolerance is for naming-convention drift, not semantic drift.
Multi-language example¶
# Run producer in Python:
squeaky generate --problem-file producer_problem.json
# Run consumer in Java against the same contract:
squeaky generate --problem-file consumer_problem.json
Both projects' generated code reference the same contract; the Java consumer's ConsumedEvent carries the producer's field names verbatim (with Java's idiomatic camelCase normalized for matching).
See also¶
- Your first ProblemSpec — full schema in context.
- Architecture deep-dive — how the contract registry is wired into the pipeline.