Kotlin Coroutines Retrofit

Kotlin Coroutines await() extension for Retrofit Call
Alternatives To Kotlin Coroutines Retrofit
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
Unitask6,125212 days ago37November 01, 2022mitC#
Provides an efficient allocation free async/await integration for Unity.
Coobjc3,850
102 years ago2March 06, 201925apache-2.0Objective-C
coobjc provides coroutine support for Objective-C and Swift. We added await method、generator and actor model like C#、Javascript and Kotlin. For convenience, we added coroutine categories for some Foundation and UIKit API in cokit framework like NSFileManager, JSON, NSData, UIImage etc. We also add tuple support in coobjc.
Cppcoro2,446
a year ago104mitC++
A library of C++ coroutine abstractions for the coroutines TS
Asyncawait1,8705681764 years ago22November 20, 20195mitTypeScript
Callback heaven for Node.js with async/await
Concurrencpp1,709
6 days ago7mitC++
Modern concurrency for C++. Tasks, executors, timers and C++20 coroutines to rule them all
Kotlin Coroutines Retrofit768
264 years ago20February 11, 20193apache-2.0Kotlin
Kotlin Coroutines await() extension for Retrofit Call
Swiftcoroutine745
2 years ago3October 11, 20214mitSwift
Swift coroutines for iOS, macOS and Linux.
Libcopp663
6 months ago1mitC++
cross-platform coroutine library in c++
Posterus544342 years ago28April 19, 2021JavaScript
Composable async primitives with cancelation, control over scheduling, and coroutines. Superior replacement for JS Promises.
Asyncawait410
6 years ago9apache-2.0Kotlin
async/await for Android built upon coroutines introduced in Kotlin 1.1
Alternatives To Kotlin Coroutines Retrofit
Select To Compare


Alternative Project Comparisons
Readme

Kotlin Coroutines for Retrofit

CircleCI codecov codebeat badge

This is a small library that provides the Kotlin Coroutines suspending extension Call.await() for Retrofit 2

Based on kotlinx.coroutines implementation.

New version of library (after 1.0.0) support only Kotlin 1.3

Kotlin 1.2 and experimental coroutines are not supported anymore, but you can use version 0.13.0 for old projects.

Download

Download the JAR:

Gradle:

implementation 'ru.gildor.coroutines:kotlin-coroutines-retrofit:1.1.0'

Maven:

<dependency>
  <groupId>ru.gildor.coroutines</groupId>
  <artifactId>kotlin-coroutines-retrofit</artifactId>
  <version>1.1.0</version>
</dependency>

How to use

NOTE: All examples in this README use runBlocking to build coroutine but it is only useful for testing or examples.

For a real application you probably want to use some other coroutines builder that does not block a thread, for example launch from kotlinx.coroutines.

If you want to use this library for UI please also check the Guide to UI programming with coroutines

There are three suspending extensions:

.await()

Common await API that returns a result or throws an exception

fun Call<T>.await(): T

In case of an HTTP error or an invocation exception await() throws an exception

// You can use retrofit suspended extension inside any coroutine block
fun main(args: Array<String>): Unit = runBlocking {
    try {
        // Wait (suspend) for result
        val user: User = api.getUser("username").await()
        // Now we can work with result object
        println("User ${user.name} loaded")
    } catch (e: HttpException) {
        // Catch http errors
        println("exception${e.code()}", e)
    } catch (e: Throwable) {
        // All other exceptions (non-http)
        println("Something broken", e)
    }
}

.awaitResponse()

Common await API that returns a Response or throws an exception

fun Call<T>.awaitResponse(): Response<T>

In case of an invocation exception awaitResponse() throws an exception

// You can use retrofit suspended extension inside any coroutine block
fun main(args: Array<String>): Unit = runBlocking {
    try {
        // Wait (suspend) for response
        val response: Response<User> = api.getUser("username").awaitResponse()
        if (response.isSuccessful()) {
          // Now we can work with response object
          println("User ${response.body().name} loaded")
        }
    } catch (e: Throwable) {
        // All other exceptions (non-http)
        println("Something broken", e)
    }
}

.awaitResult()

API based on sealed class Result:

fun Call<T>.awaitResult(): Result<T>
fun main(args: Array<String>): Unit = runBlocking {
    // Wait (suspend) for Result
    val result: Result<User> = api.getUser("username").awaitResult()
    // Check result type
    when (result) {
        //Successful HTTP result
        is Result.Ok -> saveToDb(result.value)
        // Any HTTP error
        is Result.Error -> log("HTTP error with code ${result.error.code()}", result.error)
        // Exception while request invocation
        is Result.Exception -> log("Something broken", e)
    }
}

Also, Result has a few handy extension functions that allow to avoid when block matching:

fun main(args: Array<String>): Unit = runBlocking {
    val result: User = api.getUser("username").awaitResult()
    
    //Return value for success or null for any http error or exception
    result.getOrNull()
    
    //Return result or default value
    result.getOrDefault(User("empty-user"))
    
    //Return value or throw exception (HttpException or original exception)
    result.getOrThrow()
    //Also supports custom exceptions to override original ones
    result.getOrThrow(IlleagalStateException("User request failed"))
}

All Result classes also implemented one or both interfaces: ResponseResult and ErrorResult You can use them for access to shared properties of different classes from Result

fun main(args: Array<String>): Unit = runBlocking {
  val result: User = api.getUser("username").awaitResult()
  
  //Result.Ok and Result.Error both implement ResponseResult
  if (result is ResponseResult) {
      //And after smart cast you now have an access to okhttp3 Response property of result
      println("Result ${result.response.code()}: ${result.response.message()}")
  }
  
  //Result.Error and Result.Exception implement ErrorResult
  if (result is ErrorResult) {
      // Here yoy have an access to `exception` property of result
      throw result.exception
  }
}

Nullable body

To prevent unexpected behavior with a nullable body of response Call<Body?> extensions .await() and .awaitResult() are available only for non-nullable Call<Body> or platform Call<Body!> body types:

fun main(args: Array<String>): Unit = runBlocking {
  val user: Call<User> = api.getUser("username")
  val userOrNull: Call<User?> = api.getUserOrNull("username")
  
  // Doesn't work, because User is nullable
  // userOrNull.await()
    
  // Works for non-nullable type
  try {
      val result: User = user.await()  
  } catch (e: NullPointerException) {
      // If body will be null you will get NullPointerException
  }
  
  // You can use .awaitResult() to catch possible problems with nullable body
  val nullableResult = api.getUser("username").awaitResult().getOrNull()
  // But type of body should be non-nullable
  // api.getUserOrNull("username").awaitResult()
  
  // If you still want to use nullable body to clarify your api
  // use awaitResponse() instead:
  val responseBody: User? = userOrNull.awaitResponse().body()
}

Parallel requests

By wrapping call with kotlinx.coroutines async(), you may run a few requests parallelly without waiting for the previous request.

fun main(args: Array<String>): Unit = runBlocking {
  val users = listOf("user1", "user2", "user3")
      .map { username ->
        // Pass any coroutine context that fits better for your case
        // Coroutine Dispatcher also controls parallelism level 
        // for CommonPool parallelism is `availableProcessors - 1`
        // But you can use any custom dispatcher with any parallelism strategy
        async(CommonPool) {
            // Send request. We use `awaitResult()` here to avoid try/catch, 
            // but you can use `await()` and catch exceptions
            api.getUser(username).awaitResult() 
        }
      }
      // Handle results
      // in this example we get result or null in case of error and filter all nulls
      .mapNotNull {
        // Wait (suspend) for result of `async()` and get result of request
        // We must call first `await()` only when all `async` blocks are created for parallel requests
        it.await().getOrNull()
      }
}

You can read more about concurrent usage of async in the kotlinx.coroutines guide

Popular Async Await Projects
Popular Coroutine Projects
Popular Control Flow Categories
Related Searches

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.
Kotlin
Coroutines
Await
Retrofit2
Kotlin Coroutines