Developing REST API for Mobile Application
REST API for mobile app isn't just endpoints. Mobile client operates in conditions absent for web clients: unstable connection, limited traffic, multi-version support (App Store has 2-year-old versions). This impacts architecture from day one.
Designing for Mobile Client
Response granularity. Common mistake — endpoints returning too much data. Profile screen shouldn't fetch entire user object with nested relations if only avatar and name needed. BFF (Backend for Frontend) pattern solves: separate API layer optimized for mobile screens. Alternative — fields parameter in request (?fields=id,name,avatar).
Pagination. Offset-based (?page=2&limit=20) fails for real-time feeds — when new records added, offset shifts, user sees duplicates. Cursor-based (?after=eyJpZCI6MTIzfQ==) lacks this problem. Must return hasMore flag and nextCursor in response.
API versioning. Start with version in URL (/api/v1/). Mobile doesn't force update — 15–20% stay on old versions months. v1 must live alongside v2 minimum 6–12 months.
Network Layer on Client
Android (Kotlin): Retrofit 2 + OkHttp + Kotlin Coroutines — established stack. OkHttp Interceptor for Authorization header, logging (debug only) and retry:
class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
override fun intercept(chain: Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer ${tokenProvider.getToken()}")
.build()
val response = chain.proceed(request)
if (response.code == 401) {
tokenProvider.refresh()
// retry with new token
}
return response
}
}
iOS (Swift): Native URLSession or Alamofire. For type-safe requests — Codable models. RequestInterceptor in Alamofire for auto token refresh analogous to OkHttp Interceptor.
Flutter: dio package with Interceptor — same logic. retrofit_dart generates type-safe client from annotations like Retrofit.
Error Handling
Structured error codes more important than HTTP status for client logic:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "User with specified ID does not exist",
"field": null
}
}
code — machine-readable, client switches by it. message — for developer, not user. Client shows localized strings by code, not raw API message.
Validation errors should return field — field name that failed. Allows highlighting specific field in form.
Caching and Offline
HTTP caching via Cache-Control and ETag reduces load and speeds UX. OkHttp supports HTTP cache out of box with directory and size. But for offline work need separate layer: Room (Android) or CoreData/SwiftData (iOS) as local data copy. Repository pattern separates data sources.
Security
- Certificate Pinning:
OkHttp.CertificatePinneron Android,URLSessionDelegatewithdidReceive challengeon iOS. Complicates MITM but requires certificate rotation plan. - Don't store JWT in
SharedPreferences(Android) orUserDefaults(iOS). UseEncryptedSharedPreferences/Keychain. - HTTPS everywhere, no exceptions. No
cleartextin production.
What's Included
Design endpoints with mobile specifics, implement client network layer with interceptors, error handling and retry, configure caching. Document API via OpenAPI/Swagger for mobile team convenience.
Timeline: 5–12 days depending on endpoint count and backend necessity.







