Networking
Networking
1. Networking Flow
Android networking allows an app to communicate with a backend server using HTTP APIs.
UI
|
v
ViewModel
|
v
Repository
|
v
Retrofit
|
v
OkHttp
|
v
Backend Server---
2. Retrofit
What is Retrofit?
Retrofit is a type-safe HTTP client used to define REST APIs using Kotlin interfaces and annotations.
How it works
Kotlin API Interface
|
v
Retrofit creates request
|
v
OkHttp sends request
|
v
JSON response converted into Kotlin objectExample
interface AccountApi {
@GET("accounts/{id}")
suspend fun getAccount(
@Path("id") accountId: String
): AccountResponse
@POST("payments")
suspend fun makePayment(
@Body request: PaymentRequest
): PaymentResponse
}Common annotations
| Annotation | Purpose |
|---|---|
@GET | Fetch data |
@POST | Send data |
@PUT | Replace data |
@PATCH | Update partial data |
@DELETE | Delete data |
@Path | Replace URL path value |
@Query | Add query parameter |
@Body | Send request body |
@Header | Add request header |
---
3. OkHttp
What is OkHttp?
OkHttp is the actual HTTP client that sends requests and receives responses.
Retrofit internally uses OkHttp.
OkHttp handles:
* Network connections
* Request and response processing
* Interceptors
* Authentication
* Timeouts
* Retries
Example
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()Retrofit vs OkHttp
| Retrofit | OkHttp |
|---|---|
| High-level API client | Low-level HTTP client |
| Defines APIs using annotations | Sends actual network requests |
| Converts JSON into objects | Handles connections and headers |
| Uses OkHttp internally | Can work independently |
---
4. Interceptors
What is an interceptor?
An interceptor reads or modifies a request or response before or after the network call.
Common uses:
* Add authorization token
* Add request ID
* Add common headers
* Log requests and responses
Flow
Original Request
|
v
Auth Interceptor
|
v
Request ID Interceptor
|
v
ServerExample
class AuthInterceptor(
private val tokenProvider: TokenProvider
) : Interceptor {
override fun intercept(
chain: Interceptor.Chain
): Response {
val request = chain.request()
.newBuilder()
.header(
"Authorization",
"Bearer ${tokenProvider.getToken()}"
)
.build()
return chain.proceed(request)
}
}Application vs Network interceptor
| Application interceptor | Network interceptor |
|---|---|
| Runs once for a logical request | Runs for actual network operations |
| Commonly used for headers | Used for low-level network monitoring |
| Can work with cached responses | Observes real network traffic |
| Most commonly used | Used less frequently |
---
5. Authenticator
What is an authenticator?
An OkHttp Authenticator handles authentication failure, usually HTTP 401 Unauthorized.
It is commonly used to refresh an expired access token.
Flow
API Request
|
v
401 Unauthorized
|
v
Authenticator
|
v
Refresh token
|
v
Retry original requestExample
class TokenAuthenticator(
private val tokenRepository: TokenRepository
) : Authenticator {
override fun authenticate(
route: Route?,
response: Response
): Request? {
if (responseCount(response) >= 2) {
return null
}
val newToken =
tokenRepository.refreshTokenBlocking()
?: return null
return response.request
.newBuilder()
.header(
"Authorization",
"Bearer $newToken"
)
.build()
}
private fun responseCount(response: Response): Int {
var count = 1
var previous = response.priorResponse
while (previous != null) {
count++
previous = previous.priorResponse
}
return count
}
}Interceptor vs Authenticator
| Interceptor | Authenticator |
|---|---|
| Runs on normal requests | Runs after authentication failure |
| Adds current access token | Refreshes expired token |
| Can modify requests and responses | Usually handles 401 |
| Used for common headers | Used for token renewal |
---
6. Timeouts
Timeouts prevent a network request from waiting forever.
Types of timeouts
| Timeout | Meaning |
|---|---|
| Connect timeout | Time allowed to connect to server |
| Read timeout | Time allowed to receive response data |
| Write timeout | Time allowed to send request data |
| Call timeout | Total time allowed for complete request |
Example
val client = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.callTimeout(45, TimeUnit.SECONDS)
.build()Timeout values should depend on the type of API and network conditions.
---
7. Retries
What is retry?
Retry means repeating a failed network request.
Retries may be useful for:
* Temporary network failure
* Connection reset
* Server temporarily unavailable
* Gateway timeout
Flow
Request failed
|
v
Is the failure temporary?
/ \
Yes No
| |
Retry Return errorImportant rule
Safe to retry:
* GET requests
* Read-only operations
* Idempotent APIs
Be careful retrying:
* Payment creation
* Money transfer
* Order creation
Repeated transaction requests may create duplicate operations.
Retry example
suspend fun <T> retryRequest(
maxAttempts: Int = 3,
request: suspend () -> T
): T {
var lastError: Throwable? = null
repeat(maxAttempts) { attempt ->
try {
return request()
} catch (error: IOException) {
lastError = error
if (attempt < maxAttempts - 1) {
delay(1_000L * (attempt + 1))
}
}
}
throw lastError ?: IOException("Request failed")
}Exponential backoff
First retry -> 1 second
Second retry -> 2 seconds
Third retry -> 4 secondsNever use unlimited retries.
---
8. API Error Mapping
What is API error mapping?
API error mapping converts technical network errors into meaningful application errors.
Technical Error
|
v
Error Mapper
|
v
Application ErrorExample:
UnknownHostException -> No internet
SocketTimeoutException -> Request timeout
401 -> Session expired
404 -> Data not found
500 -> Server errorError classification
sealed interface AppError {
data object NoInternet : AppError
data object Timeout : AppError
data object Unauthorized : AppError
data object NotFound : AppError
data object ServerError : AppError
data class BusinessError(
val code: String,
val message: String
) : AppError
data object Unknown : AppError
}Error mapper example
fun Throwable.toAppError(): AppError {
return when (this) {
is UnknownHostException ->
AppError.NoInternet
is SocketTimeoutException ->
AppError.Timeout
is HttpException -> when (code()) {
401 -> AppError.Unauthorized
404 -> AppError.NotFound
in 500..599 -> AppError.ServerError
else -> AppError.Unknown
}
else -> AppError.Unknown
}
}---
9. Request IDs
What is a request ID?
A request ID is a unique identifier added to every network request.
Example:
X-Request-ID: 52e4b11c-8466-4cfdWhy is it used?
It helps trace one request across:
* Android app logs
* API gateway logs
* Backend service logs
* Monitoring systems
Flow
Android App
Request ID: ABC123
|
v
API Gateway
Request ID: ABC123
|
v
Backend Service
Request ID: ABC123Example interceptor
class RequestIdInterceptor : Interceptor {
override fun intercept(
chain: Interceptor.Chain
): Response {
val requestId = UUID.randomUUID().toString()
val request = chain.request()
.newBuilder()
.header("X-Request-ID", requestId)
.build()
return chain.proceed(request)
}
}Request IDs should not contain sensitive user information.
---
10. Android Networking Security
Android networking security protects data exchanged between the application and backend server.
Main security practices
Use HTTPS
Always use HTTPS for production APIs.
Android App
|
| Encrypted HTTPS request
v
Backend ServerHTTPS provides:
* Data encryption
* Server identity validation
* Data integrity
Disable cleartext traffic
<application
android:usesCleartextTraffic="false" />This prevents normal HTTP communication.
Network Security Configuration
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>Manifest configuration:
<application
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false" />Certificate pinning
Certificate pinning makes the app trust only the expected certificate or public key.
val certificatePinner = CertificatePinner.Builder()
.add(
"api.example.com",
"sha256/PUBLIC_KEY_HASH"
)
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()Server certificate
|
v
Compare with pinned key
/ \
Match Mismatch
| |
Allow BlockCertificate rotation and backup pins must be planned properly.
---
11. Common Mistakes
1. Refreshing tokens in every interceptor
Use the interceptor to add the token and the authenticator to refresh it.
2. Infinite authenticator loop
Always limit token-refresh retries.
401 -> Refresh -> 401 -> Stop3. Retrying every API
Avoid blindly retrying payments or money transfers.
4. Very large timeout values
Large timeouts can make the app appear frozen.
5. Showing raw API errors
Map technical errors into meaningful application errors.
6. Missing request IDs
Without request IDs, production failures are harder to trace.
7. Allowing HTTP traffic
Production APIs should use HTTPS.
8. Incorrect certificate pinning
Wrong pins or missing backup pins can block all network communication.
---
12. Interview Questions and Answers
Q1. What is Retrofit?
Retrofit is a type-safe HTTP client used to define REST APIs through Kotlin interfaces and annotations.
Q2. What is OkHttp?
OkHttp is the HTTP engine that sends requests, receives responses and handles connections, interceptors, authentication and timeouts.
Q3. Retrofit vs OkHttp?
Retrofit defines APIs and converts responses into objects, while OkHttp performs the actual HTTP communication.
Q4. What is an interceptor?
An interceptor reads or modifies requests and responses. It is commonly used for authorization headers and request IDs.
Q5. What is an authenticator?
An authenticator handles authentication failure, refreshes an expired token and retries the original request.
Q6. Interceptor vs authenticator?
The interceptor adds the current token to each request. The authenticator refreshes the token after receiving a 401.
Q7. What are the main timeout types?
Connect, read, write and complete call timeout.
Q8. When should we retry an API?
Retry temporary failures and safe or idempotent requests. Avoid automatically retrying transaction-creation APIs.
Q9. What is API error mapping?
It converts technical errors such as HTTP exceptions and timeouts into meaningful app-level errors.
Q10. What is a request ID?
It is a unique identifier used to trace one API request across mobile and backend systems.
Q11. How do you secure Android networking?
Use HTTPS, disable cleartext traffic, configure network security policies and use certificate pinning when required.
Q12. What is certificate pinning?
Certificate pinning verifies that the server certificate or public key matches the value expected by the application.
---
13. Final Interview Answer
> Retrofit defines APIs and converts responses into Kotlin objects, while OkHttp performs the actual HTTP communication. Interceptors add common headers such as authorization tokens and request IDs. An authenticator handles 401 responses by refreshing the token and retrying the original request. Timeouts control how long requests can wait, retries should be limited to temporary and safe operations, and error mapping converts technical failures into meaningful app errors. Android networking should use HTTPS, block cleartext traffic and use certificate pinning where stronger server verification is required.