Mobile API Best Practices · Versioning, Upgrades & Remote Control
Versioning With Old Clients in the Wild
Additive changes, tolerant readers and version telemetry.
Assume every response field you ever shipped is read by some installed app. Rules: only additive changes within a version, never change a field's type or meaning, give enums an unknown fallback on clients (tolerant reader), and send the app version with every request (User-Agent: ExampleApp/5.12.0 (iOS 18.1) or X-App-Version) so you can measure who still uses old behavior before removing it.
Change safety matrix
| Change | Safe for old apps? | How to do it safely |
|---|---|---|
| Add optional response field | Yes | Clients ignore unknown fields |
| Add enum value | Only if clients have a fallback | Ship 'unknown' handling first |
| Rename / remove field | No | Add new field, keep old, remove after usage → 0 |
| Make request field required | No | Default it server-side for old versions |
| Change pagination/format | No | New endpoint or version |
| Change error codes | Risky | Keep codes stable; add details |
@Serializable
enum class OrderStatus { PENDING, PAID, SHIPPED, @SerialName("unknown") UNKNOWN }
val json = Json {
ignoreUnknownKeys = true // new fields don't crash old apps
coerceInputValues = true // unknown enum values → default
}
@Serializable data class Order(val id: String, val status: OrderStatus = OrderStatus.UNKNOWN)
enum OrderStatus: String, Decodable {
case pending, paid, shipped, unknown
init(from decoder: Decoder) throws {
let raw = try decoder.singleValueContainer().decode(String.self)
self = OrderStatus(rawValue: raw) ?? .unknown
}
}
Common pitfalls
- Strict decoders that crash on unknown fields or enum values.
- Removing a field because the latest app doesn't use it.
- No app-version telemetry, so you can't tell who is affected.
Key points
- Additive-only within a version
- Tolerant readers on clients
- Track app versions per request
Further reading: Martin Fowler: Tolerant Reader
Practice questions
How do you safely add a new enum value to a mobile API?
Answer
First ship client versions that map unknown values to a fallback; then, once old strict versions are rare (or handled server-side per version), start returning the new value.
Why should mobile clients send their app version?
Answer
So the server can measure usage per version, gate behavior for old clients and know when it's safe to remove deprecated fields.
Open in the app to mark lessons complete, take notes and track your progress.