Adding a response field looks harmless: nothing has been removed, so the change should be backward compatible. It should. In integration work, “should” is often the most expensive word in the plan.
Three layers of compatibility
| Layer | Question | Example risk |
|---|---|---|
| Source | Does client code still compile? | An SDK generator changes a signature or type. |
| Wire | Can an old client receive and deserialize the new response? | Strict mode rejects an unknown property. |
| Semantic | Does the client still receive the behaviour a reasonable developer expected? | A new enum value or changed default selects the wrong branch. |
Google AIP-180 makes this distinction between source, wire and semantic compatibility. It also warns that compatibility guidance is indicative rather than proof for every technology stack.
Optional does not mean irrelevant
An optional request field means an old client need not send it. An optional response field means the server may omit it. Neither statement proves that a particular client accepts an unknown property or handles a new value safely.
An additive change is usually safer than removing a field, but it can expose a hidden contract: strict deserialization, an exhaustive enum switch, a database length limit or logic coupled to an undocumented format. An API contract includes behaviour, not just an OpenAPI file.
A pre-release matrix
| Change | Initial assessment | What to verify |
|---|---|---|
| New optional response field | Usually additive | Unknown fields, generated models, proxies and validators. |
| New response enum value | Elevated risk | Fallback branches and generated-code behaviour. |
| Changed default value | Semantically incompatible | Clients that omit the field. |
| Optional field becomes required | Incompatible | Every existing request producer. |
| Existing value changes format | Semantically risky | Parsers, validation, indexes and column lengths. |
How to verify an API change
- Define compatibility rules. Record evolution rules: whether clients ignore unknown fields, whether enums are extensible and how long a version is supported.
- Inventory consumers. Owner, library version, deserialization mode and upgrade window matter more than the endpoint count.
- Test representative versions. Replay a response containing the new field in contract tests and run the oldest supported client.
- Limit exposure. Roll out gradually, observe deserialization failures and retain a way to stop exposing the field.
- Version when existing compatibility rules cannot be maintained. Introduce a new version when existing behaviour cannot be preserved or consumer upgrades cannot be controlled.
deliveryWindow to an order response. OpenAPI does not mark it as required, but an older mobile app rejects every unknown property. Before broad rollout, the team tests a supported client version, changes its deserialization rule and only then exposes the field progressively.Boundary of this advice
Not every integration needs public versioning. When the producer controls every consumer and can enforce a coordinated update, a simpler process may be enough. The team must still verify the actual version mix during deployment. “It is only a field” is not a migration strategy.
Practise the new-field decision →
Discuss this article
Share a constructive observation or an anonymised example. Comments are checked by AI before publication. Uncertain cases go to the moderator.