Mobile Application Network Layer
Request goes out, response doesn't come, timeout — 30 seconds. User stares at a spinner. No network — mobile map in metro. Or network exists, but server returned 200 with HTML error page instead of JSON — and the application crashes on JSONDecoder.decode(). Mobile application network layer must handle these scenarios explicitly, not rely on "connection always exists."
REST and Client Library Choice
Alamofire (iOS) — de facto standard for Swift projects. On top of URLSession, it adds request chaining, response validation, automatic retry, certificate pinning via ServerTrustManager. AF.request() with .validate() returns error for any status code outside 200–299. Without .validate(), Alamofire considers 404 and 500 as successful responses.
AF.request("https://api.example.com/orders")
.validate(statusCode: 200..<300)
.responseDecodable(of: OrdersResponse.self) { response in
switch response.result {
case .success(let orders): // ...
case .failure(let error): // always handle
}
}
With Swift Concurrency — async version via serializingDecodable:
let response = try await AF.request(url)
.validate()
.serializingDecodable(OrdersResponse.self).value
Retrofit (Android) — annotation-based HTTP client on top of OkHttp. Interface with annotations compiles into implementation. @GET, @POST, @Path, @Query, @Body — declarative API description. Converters (GsonConverterFactory, MoshiConverterFactory, KotlinxSerializationConverterFactory) deserialize response automatically.
OkHttp under the hood provides: connection pooling, transparent gzip, HTTP/2 multiplex. HttpLoggingInterceptor — request/response logging in debug build. Authenticator — automatic token refresh on 401.
Ktor (KMM/Flutter) — multiplatform HTTP client. On iOS works via Darwin engine (URLSession), on Android via OkHttp. Single code for both platforms in KMM architecture.
GraphQL: when REST creates problems
REST returns fixed structure. Profile screen needs name, avatar, email — server returns 40 fields. List screen needs only id and name — same endpoint, same 40 fields. Over-fetching.
GraphQL solves this: client requests exactly the fields it needs. This is critical for mobile, where traffic and parsing time are real constraints.
Apollo iOS and Apollo Kotlin — GraphQL clients. Code generation from schema: schema.graphql + query files → typed Swift/Kotlin classes. No string queries, no manual parsing — everything is type-safe at compile time.
Subscriptions via WebSocket are built into Apollo — real-time data updates without polling.
Practical limitation: GraphQL is harder to cache at HTTP level (single POST endpoint). Apollo uses normalized in-memory cache with InMemoryNormalizedCache — queries with overlapping data update the cache without duplication.
WebSocket: real-time without polling
Polling (setInterval every 5 seconds) — battery and traffic waste. WebSocket — persistent bidirectional connection.
iOS: URLSessionWebSocketTask (native, iOS 13+). Send via send(.string(message)), receive via receive() in async loop.
Android: OkHttp WebSocket — newWebSocket() returns WebSocket, WebSocketListener handles events: onOpen, onMessage, onClosing, onFailure.
Mandatory reconnect handling: mobile network is unstable. On onFailure — exponential backoff: 1s → 2s → 4s → 8s → max 60s. Without reconnect logic, application loses connection in metro and doesn't recover.
Socket.IO — abstraction over WebSocket with automatic reconnect, room/namespace, long-polling fallback. Convenient if backend already uses Socket.IO. For new projects, native WebSocket is preferable — fewer dependencies.
gRPC: for high-load services
gRPC with protobuf — binary serialization vs JSON: smaller size, faster parsing. For mobile, this is noticeable on weak devices and slow network.
grpc-swift for iOS, grpc-kotlin for Android. Protobuf schema compiles into typed classes on both platforms. Streaming (server-side, client-side, bidirectional) — native gRPC capability, not abstraction.
Practical threshold: gRPC is justified with high request frequency (trading, IoT, internal microservices) or when latency is critical. For regular CRUD API, REST is simpler to debug and monitor.
Offline Mode and Caching
Mobile application must work without network — at least in read-only mode. User loses connection, sees previously loaded data, not error screen.
iOS: URLCache for HTTP caching (respects Cache-Control headers). Core Data or SwiftData for structured data. NWPathMonitor — network availability tracking.
Android: OkHttp Cache + CacheControl in requests. Room for local storage. ConnectivityManager.NetworkCallback — network state monitoring.
Offline-first pattern: when opening screen, first show data from cache, in parallel make network request, update UI on response. User sees content immediately, not spinner.
Certificate Pinning
Corporate proxy can intercept HTTPS connection via certificate substitution. Certificate pinning prevents this: application accepts only specific certificate or public key.
Alamofire: ServerTrustManager with PinnedCertificatesTrustEvaluator. OkHttp: CertificatePinner with SHA-256 hash of public key.
Operational complexity: when rotating certificate on server, all old app versions stop working. Solution — pinning to public key of CA, not leaf certificate, or supporting multiple pins simultaneously with grace period.
Timeline
Network layer implementation with REST, retry, caching and offline mode — 1–2 weeks. Adding GraphQL or WebSocket — another 1–2 weeks depending on complexity. gRPC with protobuf — 2–3 weeks including code generation and integration. Cost is calculated individually after analyzing API requirements and offline behavior.







