Middle
How to safely evolve contracts between services?
sobes.tech AI
Answer from AI
Secure evolution of contracts between services is achieved through principles of backward compatibility and gradual implementation of changes. Main approaches:
- Versioning of contracts: adding a new version of the API or schema, while old versions continue to work.
- Adding new fields as optional: not deleting or changing existing fields, but expanding the contract with new optional parameters.
- Using schemas supporting evolution (e.g., Avro, Protobuf), which allow adding new fields without breaking old clients.
- Agreements on behavior when new fields are absent: clients should handle the absence of new data correctly.
- Compatibility testing: automated tests to ensure that new versions do not break old clients.
Example using JSON Schema, where a new optional field is added:
from jsonschema import validate, ValidationError
schema_v1 = {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"}
},
"required": ["id", "name"]
}
schema_v2 = {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"email": {"type": "string"} # new optional field
},
"required": ["id", "name"]
}
# Clients supporting v1 will be able to ignore the email field if it exists
try:
validate(instance={"id": 1, "name": "Alice"}, schema=schema_v2) # valid
validate(instance={"id": 2, "name": "Bob", "email": "bob@example.com"}, schema=schema_v2) # valid
except ValidationError as e:
print(f"Validation error: {e}")