DEV Community

myougaTheAxo
myougaTheAxo

Posted on • Originally published at zenn.dev

Retrofit and OkHttp Guide for Android - API Definition and Interceptors (v2)

Retrofit and OkHttp power network operations in Android apps. Master API definitions, custom interceptors, and token-based authentication.

Defining Retrofit API Interface

Create type-safe API endpoints:

interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") userId: String): User

    @POST("posts")
    suspend fun createPost(@Body post: PostRequest): PostResponse

    @GET("posts")
    suspend fun listPosts(
        @Query("page") page: Int = 1,
        @Query("limit") limit: Int = 20
    ): List<Post>
}
Enter fullscreen mode Exit fullscreen mode

Setting Up Retrofit with OkHttp

Configure HTTP client with interceptors:

val httpClient = OkHttpClient.Builder()
    .addInterceptor(LoggingInterceptor())
    .addNetworkInterceptor(StethoInterceptor())
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(30, TimeUnit.SECONDS)
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(httpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
    .build()

val apiService = retrofit.create(ApiService::class.java)
Enter fullscreen mode Exit fullscreen mode

Adding Authentication Interceptor

Automatically attach tokens to requests:

class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        val token = tokenProvider.getAuthToken()

        val authenticatedRequest = originalRequest.newBuilder()
            .header("Authorization", "Bearer $token")
            .build()

        return chain.proceed(authenticatedRequest)
    }
}

// Add to OkHttpClient
httpClient.addInterceptor(AuthInterceptor(tokenProvider))
Enter fullscreen mode Exit fullscreen mode

Error Handling and Retry Logic

Implement robust error handling:

class ErrorInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var response = chain.proceed(chain.request())

        if (response.code == 401) {
            // Token expired, refresh and retry
            refreshToken()
            response = chain.proceed(chain.request())
        }

        return response
    }
}

// Use with coroutines
viewModelScope.launch {
    try {
        val user = apiService.getUser("123")
        updateUI(user)
    } catch (e: HttpException) {
        showError("HTTP Error: ${e.code()}")
    } catch (e: IOException) {
        showError("Network Error")
    }
}
Enter fullscreen mode Exit fullscreen mode

Retrofit simplifies API integration. Combine it with proper interceptor setup for production-ready networking.

8 Android app templates on Gumroad

Top comments (0)