Problem
Strict consumers that validate entire payloads break whenever a provider adds a field or reorders data. This forces lockstep deployments between services that should evolve independently.
Also known as: robustness-principle, lenient-consumer
Let consumers read only what they need and ignore unknown data, so providers can evolve without breaking them.
Strict consumers that validate entire payloads break whenever a provider adds a field or reorders data. This forces lockstep deployments between services that should evolve independently.
The Tolerant Reader pattern applies Postel's law to integration: be conservative in what you send and liberal in what you accept. A consumer reads the minimum it needs and ignores everything else, which makes additive changes safe.
Instead of deserialising a response into a class mirroring the entire provider schema, the consumer picks fields.
// strict: fails on any unknown property
Order o = mapper.readValue(json, Order.class);
// tolerant: select what is needed
id = json.path("id").asText();
amount = json.path("total").path("amount").asLong();
status = parseStatus(json.path("status").asText("UNKNOWN"));
With JSON binding libraries, disable fail-on-unknown-properties. With Protobuf and Avro, rely on built-in unknown-field handling and schema resolution. For enums, map unrecognised values to UNKNOWN and choose a safe behaviour. Consumer-driven contracts, for example Pact, record the exact fields each consumer uses so providers see what is safe to change.
None - coding practice
Low - contract tests
Low - simple principle
Missing required field silently becomes a default and corrupts data
Unknown enum value crashes a switch statement
Leniency masks a genuinely broken contract