Mobile API Best Practices · Designing APIs for Mobile Clients

Errors Mobile Clients Can Act On

Stable machine-readable codes, localized messages and retry hints.

A mobile app needs to decide what to do with an error: retry, re-authenticate, show a field error, ask the user to update, or give up. Use RFC 9457 problem details with a stable type/code the app branches on, field-level errors for forms, a retryable hint or Retry-After, and a request ID users can quote to support. Keep user-facing text localizable: either the server localizes via Accept-Language or the app maps codes to its own strings (safer for old versions, which keep their mapping).

Error → client action

Error Status Client action
Validation 422 + errors[] Highlight fields; no retry
Access token expired 401 + invalid_token Refresh once, replay request
Refresh token invalid 401 Log out, show sign-in
Rate limited / overloaded 429 / 503 + Retry-After Wait, then retry
Version unsupported 426 + upgrade-required Show upgrade screen
Conflict / stale version 409 / 412 Fetch latest, rebase or ask user
Server bug 500 + request id Generic message; report with request id
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
X-Request-Id: req_7Hq2…

{
  "type": "https://api.example.com/problems/validation",
  "title": "Some fields are invalid",
  "status": 422,
  "errors": [{"pointer": "/delivery/postcode", "code": "postcode_invalid"}],
  "request_id": "req_7Hq2…"
}

Common pitfalls

  • Apps parsing English error messages.
  • Changing error codes between releases.
  • 200 OK with an error body.

Key points

  • Stable codes, not messages
  • Field-level errors + request IDs
  • Unknown code → safe fallback

Further reading: RFC 9457: Problem Details for HTTP APIs

Practice questions

Why should apps branch on error codes rather than messages?

Answer

Messages change and get localized; codes are a stable contract that old app versions can keep relying on.

How should a mobile client handle a 401 for an expired access token?

Answer

Refresh the token once (serializing concurrent refreshes) and replay the original request; if refresh fails, sign the user out.

Open in the app to mark lessons complete, take notes and track your progress.