Networking & Offline
Consuming APIs on a connection that comes and goes, and designing for offline as the normal case rather than the error case.
The Network Is Not There
That single assumption changes the design. Requests need timeouts and retries, responses need caching, writes need queueing, and the interface needs something honest to show while none of it has arrived.
Consuming REST APIs
Every platform has a settled stack — Retrofit with OkHttp and a JSON serializer on Android, URLSession with Codable on iOS. The library is not the interesting part; the policy around it is.
| Policy | Sensible default |
|---|---|
| Connect timeout | ~10s — a hung socket is worse than a fast failure |
| Retries | Idempotent requests only, with exponential backoff and jitter |
| Auth refresh | One place, deduplicated — not per call site |
| Errors | Typed: network, HTTP status, decoding. They need different messages |
| Payloads | Ask for what the screen needs; mobile data is the user's money |
Decode into your own models rather than passing API shapes into the UI. An extra mapping layer sounds like ceremony until the backend renames a field and the change is contained in one file.
Offline-First & Sync
Offline-first inverts the usual flow: the local database is the source of truth for the UI. Screens read from it and always have something to show; the network's job is to update the database in the background, and connectivity becomes a detail rather than a blocking condition.
| Piece | Job |
|---|---|
| Local store | What the UI reads, always available |
| Sync worker | Pulls updates and pushes queued changes when possible |
| Outbox | Local writes waiting to reach the server, with retry |
| Conflict rule | What happens when both sides changed the same thing |
Conflicts are the hard part and they need a decision, not a default. Last-write-wins is simple and silently destroys work. Server-wins is predictable and frustrating. Merging per field is better where the data allows it, and for anything the user typed, asking is usually kinder than guessing.
Interview Questions
What does offline-first mean in practice?
The local database is the source of truth for the UI. Screens read from it and always render, while a background worker syncs changes both ways. Connectivity stops being a precondition for the app working.
Why is blind retry dangerous?
Non-idempotent requests may have succeeded before the timeout. Retrying a payment or a create can duplicate it — retry only idempotent calls, or send an idempotency key.
How do you resolve sync conflicts?
It is a product decision. Last-write-wins is simple but destroys work, server-wins is predictable but frustrating, field-level merge is better where possible, and user-authored content usually deserves a prompt.
Why map API responses into your own models?
It contains change. If the backend renames or reshapes a field, only the mapping layer moves; the UI and business logic keep their stable types.
What is an outbox?
A local queue of writes made while offline, retried until the server accepts them. It is what lets the user keep working without a connection and without losing anything.
What is the risk with optimistic updates?
The server may reject the change after the UI has already shown it. Unless rejection is surfaced clearly, the user sees their action silently undone later and stops trusting the app.