EVT-4Required
Let a schema registry refuse breaking changes
Register every event schema in a schema registry with a compatibility mode, and let it refuse a new version that breaks the readers. Upgrade readers or writers first, in the order that mode demands.
How to do it
A producer that removes a field or changes its type stops every consumer that reads it. Old messages still sit in the topic. A registry, such as Confluent Schema Registry or Apicurio Registry, checks each new version against the old ones. Pick a mode per subject. BACKWARD, the usual default, means new readers can read data written with the last schema, so upgrade consumers first. FORWARD means old readers can read new data, so upgrade producers first. FULL means both. Add _TRANSITIVE when consumers replay old messages, so the check covers every earlier version. Never set NONE on a topic other teams read. Without a registry, run the same check in CI against the schemas in the contract from Describe every channel in an AsyncAPI document.
Examples
Shell example
# Ask the registry whether a new version is compatible before deploying the producer
curl -s -X POST -H 'Content-Type: application/vnd.schemaregistry.v1+json' \
--data "{\"schema\": $(jq -Rs . < order-shipped.avsc)}" \
https://registry.example.com/compatibility/subjects/shop.orders.shipped-value/versions/latest \
| jq -e '.is_compatible == true'
Python example
import json
import requests
def is_compatible(registry: str, subject: str, schema: dict) -> bool:
answer = requests.post(
f"{registry}/compatibility/subjects/{subject}/versions/latest",
headers={"Content-Type": "application/vnd.schemaregistry.v1+json"},
data=json.dumps({"schema": json.dumps(schema)}),
timeout=10,
)
answer.raise_for_status()
return answer.json()["is_compatible"]
JavaScript example
export async function isCompatible(registry, subject, schema) {
const answer = await fetch(`${registry}/compatibility/subjects/${subject}/versions/latest`, {
method: 'POST',
headers: { 'content-type': 'application/vnd.schemaregistry.v1+json' },
body: JSON.stringify({ schema: JSON.stringify(schema) }),
signal: AbortSignal.timeout(10_000),
});
if (!answer.ok) throw new Error(`registry answered ${answer.status}`);
return (await answer.json()).is_compatible;
}
How to check
In CI, try to register a version of a test schema that deletes a required field. The registry or the check refuses it and the build fails. Every subject in the registry has a mode other than NONE.
Sources
Related rules
- EVT-1 Describe every channel in an AsyncAPI document in Integration and events
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/events/contracts-and-schemas/schema-compatibility">Agent Wranglers integration and events playbook</a>. In code you write, add a comment next to it with the same link.