DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Retrofit + Jetpack Compose — API Communication Patterns

Integrate Retrofit with Jetpack Compose for robust network operations.

Retrofit API Interface

Define suspend functions for async operations:

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

    @POST("users")
    suspend fun createUser(@Body user: User): User

    @DELETE("users/{id}")
    suspend fun deleteUser(@Path("id") userId: String)
}
Enter fullscreen mode Exit fullscreen mode

Retrofit Builder with OkHttp

Configure Retrofit with interceptors:

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val request = chain.request()
            .newBuilder()
            .addHeader("Authorization", "Bearer $token")
            .build()
        chain.proceed(request)
    }
    .addInterceptor(HttpLoggingInterceptor().setLevel(BODY))
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    .create(UserApi::class.java)
Enter fullscreen mode Exit fullscreen mode

Safe API Call Error Handling

Wrap API calls with error handling:

suspend inline fun <T> safeApiCall(
    crossinline apiCall: suspend () -> T
): Result<T> = try {
    Result.success(apiCall())
} catch (e: HttpException) {
    when (e.code()) {
        404 -> Result.failure(Exception("Not found"))
        401 -> Result.failure(Exception("Unauthorized"))
        else -> Result.failure(e)
    }
} catch (e: Exception) {
    Result.failure(e)
}
Enter fullscreen mode Exit fullscreen mode

ViewModel with Compose State

Integrate API calls into ViewModel:

@HiltViewModel
class UserViewModel @Inject constructor(
    private val userApi: UserApi
) : ViewModel() {
    private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
    val uiState: StateFlow<UiState> = _uiState

    fun loadUser(userId: String) {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            _uiState.value = safeApiCall {
                userApi.getUser(userId)
            }.fold(
                onSuccess = { UiState.Success(it) },
                onFailure = { UiState.Error(it.message ?: "Unknown error") }
            )
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

HttpException Code Mapping

Handle specific HTTP status codes:

sealed class ApiError(message: String) : Exception(message) {
    object NotFound : ApiError("Resource not found")
    object Unauthorized : ApiError("Authentication required")
    object ServerError : ApiError("Server error")
    class Unknown(msg: String) : ApiError(msg)
}

fun HttpException.toApiError(): ApiError = when (code()) {
    404 -> ApiError.NotFound
    401 -> ApiError.Unauthorized
    in 500..599 -> ApiError.ServerError
    else -> ApiError.Unknown(message())
}
Enter fullscreen mode Exit fullscreen mode

Build reliable, type-safe API integration with Retrofit and Compose.


8 production-ready Android app templates on Gumroad.

Browse templatesGumroad

Top comments (0)