Backwards Compatibility: API Evolution
Maintaining backwards compatibility is the discipline of allowing a system to change while ensuring that existing consumers continue to function without modification.
1. Defining Breaking Changes
A "Breaking Change" is any modification to the API contract that causes a consumer to fail.
- Structural: Removing a field, renaming a field, or changing a data type (e.g.,
Int to String). - Behavioral: Changing the side effects (e.g., an endpoint that was read-only now triggers an email).
- Semantic: Changing the meaning of data (e.g., changing a currency field from USD to EUR without a unit change).
2. Versioning Strategies
| Strategy | Example | Pros | Cons |
|---|
| URI | /v1/users | Easy to route/cache. | Pollutes URI namespace. |
| Header | Accept-Version: 2 | Clean URIs. | Harder for browser testing. |
| Media Type | Accept: application/vnd.v2+json | REST purest. | Complex client implementation. |
Expert Recommendation: Use URI versioning for major architectural shifts (e.g., moving from XML to JSON). Use Header-based versioning for iterative data model changes.
3. The "Expand and Contract" Pattern
To safely remove or rename a field, follow this three-phase rollout:
- Phase 1 (Expand): Add the new field (
new_email) to the response but keep the old field (email). Both fields return the same data. - Phase 2 (Migrate): Update documentation and issue Deprecation Headers (e.g.,
Sunset: Wed, 15 May 2025). Encourage clients to switch. - Phase 3 (Contract): Once telemetry shows 0% usage of the old field, remove it.
4. Schema Evolution: Protobuf and JSON
- Protobuf: Uses Tag Numbers for field identification. You can rename a field in the
.proto file as long as the tag number remains the same; the binary format is unaffected. Rule: Never reuse a tag number from a deleted field. - JSON Schema: Use "Open Content" models. Ensure your clients are programmed to ignore unknown fields rather than throwing an error (Standard in most JSON parsers like Jackson/Gson).
5. Automated Verification
- Consumer-Driven Contracts (CDC): Use tools like Pact. Consumers provide a "contract" of what they expect. The provider runs these tests before every deployment. If a change breaks a consumer's contract, the build fails.
See Also: