In 1980 Jon Postel wrote into the TCP specification: be conservative in what you do, be liberal in what you accept from others. Tolerant Reader applies this robustness principle to integration. A consumer reads only the fields it uses, ignores the rest, and treats absent optional data as a case to handle, not an error. Strict schema binding does the opposite, turning every producer-side addition into a consumer-side parse failure.
Tolerance applies to structure the consumer never reads, not to values it does read. Producers still owe additive-only discipline, pinned down by consumer-driven contract tests.
How It Works
- Bind only a subset DTO of the fields the consumer uses; configure the deserializer to ignore unknown properties (e.g. Jackson’s ignoreUnknown).
- Path extraction (JSON pointer, XPath) serves the same end for document-oriented formats.
- An unknown value in an enum field the consumer does read is an error: reject, alert, or route to a manual fallback queue — never a silent default.
- Apply explicit defaults for absent optional elements; fail only when required data is missing or invalid.
- Validate the extracted values — types, ranges, invariants — not the document structure around them.
Failure Modes
- A producer renames a field: the reader substitutes its default and processes wrong data without an error; drift surfaces downstream.
- A new enum value falls back to a default: a
PARTIALLY_REFUNDEDpayment reads as unpaid, and refund logic misfires. - Tolerance masks producer bugs: malformed payloads that a strict parser would reject flow into the domain.
Verification
- Contract tests run each consumer against current and previous producer schemas; all pass (CI gate per release).
- Unknown-field injection passes with zero errors; an injected unknown enum value lands in the fallback path, never a silent default.
- Production monitors the default-substitution rate per field; an alert past a threshold (e.g. > 1% of messages) signals contract drift.
Variants and Related Tactics
- Schema registry with compatibility rules — rejects breaking producer changes at publish time, complementing consumer-side tolerance with a producer-side gate.
Example
A payment provider’s webhook initially sends id, amount, currency, and status. The shop’s reader binds exactly those four fields to a small DTO, unknown properties ignored. Over two years the provider adds fee_breakdown, risk_score, and a nested metadata object — the shop deploys nothing. When the provider later renames status to state, a breaking change, the contract tests catch it before production does.
References
- TolerantReader — Martin Fowler, bliki, 2011
- RFC 761: Transmission Control Protocol — Jon Postel (ed.), IETF, 1980 — origin of the robustness principle
- RFC 9413: Maintaining Robust Protocols — Martin Thomson, David Schinazi, IETF, 2023 — a critical counterpoint: tolerance without active protocol maintenance ossifies ecosystems