The Core Rule
an API change is BACKWARD COMPATIBLE if existing clients
keep working unchanged after the server ships it
old client + new server = works ← the invariant to protect
new client + old server = your choice (forward compat, later lesson)
You can’t force-deploy clients; mobile apps lag months, third parties lag years. Server-side changes must therefore assume the oldest supported client is still out there.
What’s Safe to Change
| Change | Safe? | Notes |
|---|---|---|
| Add optional response field | ✓ | Clients ignoring unknown fields stay fine |
| Add optional request param | ✓ | Old clients just don’t send it |
| Add new endpoint | ✓ | Pure addition |
| Add new enum value | ⚠ | Breaks exhaustive-switch clients! |
| Remove field | ✗ | Deserialization errors / data loss |
| Rename field | ✗ | Same as remove + add |
| Make optional → required | ✗ | Old requests now fail |
| Change field type/semantics | ✗ | Silent corruption worst case |
| Tighten validation | ✗ | Previously-valid calls start failing |
The enum trap deserves emphasis: adding status=refunded breaks any client with a closed switch statement. Either version the resource or require tolerant readers.
The Tolerant Reader Pattern
CLIENT side discipline that makes evolution possible:
- ignore unknown fields (never fail on extra JSON keys)
- treat unknown enum values as "unrecognized" not error
- never assume response contains exactly what docs promised
servers evolve freely ⇔ clients read tolerantly.
enforce via codegen defaults and lint rules, not hope
Deprecation Mechanics
When removal is truly needed:
1. announce changelog + direct notice to active consumers
2. mark docs say deprecated; responses add Sunset header
Deprecation: true
3. observe log which clients still call the dead path
4. migrate contact holdouts; offer migration window
5. remove only when observed traffic ≈ zero
typical runway: 6–12 months for public APIs,
one release cycle for internal ones
Versioning Strategies (preview)
URL path /v2/trips explicit, cacheable, most common
header Accept: vnd.api+json;version=2 cleaner URLs, hidden
query param ?version=2 simple but pollutes caching keys
full versioning is a LAST resort — most changes should fit
inside additive-compatible evolution. version when you must
make a BREAKING change, and run v1/v2 side by side during
migration, then retire v1 on the same deprecation schedule
Interview Framing
“How do you evolve this API?” tests operational empathy. Scored shape: state the invariant (old client × new server), classify candidate changes against the safe table, name the enum/tolerant-reader subtlety unprompted, sketch deprecation-with-observability rather than big-bang removal. That sequence signals someone who has shipped breaking changes before — or wisely avoided it.
Premium Content
Unlock Backward-Compatible API Evolution and all premium lessons with a subscription.
From ₹199.99/year — See plans