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 object

Example

interface AccountApi {

    @GET("accounts/{id}")
    suspend fun getAccount(
        @Path("id") accountId: String
    ): AccountResponse

    @POST("payments")
    suspend fun makePayment(
        @Body request: PaymentRequest
    ): PaymentResponse
}

Common annotations

AnnotationPurpose
@GETFetch data
@POSTSend data
@PUTReplace data
@PATCHUpdate partial data
@DELETEDelete data
@PathReplace URL path value
@QueryAdd query parameter
@BodySend request body
@HeaderAdd 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

RetrofitOkHttp
High-level API clientLow-level HTTP client
Defines APIs using annotationsSends actual network requests
Converts JSON into objectsHandles connections and headers
Uses OkHttp internallyCan 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
Server

Example

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 interceptorNetwork interceptor
Runs once for a logical requestRuns for actual network operations
Commonly used for headersUsed for low-level network monitoring
Can work with cached responsesObserves real network traffic
Most commonly usedUsed 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 request

Example

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

InterceptorAuthenticator
Runs on normal requestsRuns after authentication failure
Adds current access tokenRefreshes expired token
Can modify requests and responsesUsually handles 401
Used for common headersUsed for token renewal

---

6. Timeouts

Timeouts prevent a network request from waiting forever.

Types of timeouts

TimeoutMeaning
Connect timeoutTime allowed to connect to server
Read timeoutTime allowed to receive response data
Write timeoutTime allowed to send request data
Call timeoutTotal 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 error

Important 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 seconds

Never 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 Error

Example:

UnknownHostException -> No internet
SocketTimeoutException -> Request timeout
401 -> Session expired
404 -> Data not found
500 -> Server error

Error 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-4cfd

Why 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: ABC123

Example 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 Server

HTTPS 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          Block

Certificate 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 -> Stop

3. 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.