Retrofit in Kotlin: A Guide to Using a Type-Safe HTTP Client
Retrofit is a popular library for Android and Java/Kotlin developers that allows them to easily interact with web services using HTTP requests. Retrofit can handle the serialization and deserialization of data, as well as the network communication, using a simple and declarative interface.
In this article, we will learn how to use Retrofit in Kotlin to make GET, POST, PUT and DELETE requests to a RESTful API. We will also see how to use coroutines to perform asynchronous operations with Retrofit.
What is Retrofit?
Retrofit is a type-safe HTTP client that turns your HTTP API into a Kotlin interface. For example, suppose we have an API that provides information about users. We can define an interface like this:
interface UserService {
@GET("users")
suspend fun getUsers(): List<User>
@GET("users/{id}")
suspend fun getUserById(@Path("id") id: Long): User @POST("users")
suspend fun createUser(@Body user: User): User @PUT("users/{id}")
suspend fun updateUser(@Path("id") id: Long, @Body user: User): User @DELETE("users/{id}")
suspend fun deleteUser(@Path("id") id: Long): Response<Unit>
}
The annotations on the interface methods and parameters indicate how the HTTP request will be handled. For example, @GET
specifies the HTTP method and the relative URL, @Path
replaces a placeholder in the URL with a value, @Body
converts an object into a request body, and suspend
marks the function as a coroutine that can be executed asynchronously.
Retrofit can generate an implementation of this interface using the Retrofit.Builder
class. For example:
val retrofit = Retrofit.Builder()
.baseUrl("https://example.com/api/")
.addConverterFactory(JacksonConverterFactory.create())
.build()
val userService = retrofit.create(UserService::class.java)
The baseUrl
method sets the base URL for all requests. The addConverterFactory
method adds a converter factory that can serialize and deserialize data using a library like Jackson, Gson or Moshi. The create
method creates an instance of the interface using reflection.
How to make HTTP requests with Retrofit?
Once we have an instance of the interface, we can use it to make HTTP requests to the API. For example, to get a list of users, we can write:
val users = userService.getUsers()
This will make a GET request to https://example.com/api/users
and return a list of User
objects. Similarly, to create a new user, we can write:
val user = User(name = "Alice", age = 25)
val createdUser = userService.createUser(user)
This will make a POST request to https://example.com/api/users
with the user object as the request body and return the created user object.
To update an existing user, we can write:
val user = User(name = "Bob", age = 30)
val updatedUser = userService.updateUser(1L, user)
This will make a PUT request to https://example.com/api/users/1
with the user object as the request body and return the updated user object.
To delete an existing user, we can write:
val response = userService.deleteUser(1L)
This will make a DELETE request to https://example.com/api/users/1
and return a response object that contains information about the status code, headers and body of the response.
How to use coroutines with Retrofit?
One of the advantages of using Retrofit in Kotlin is that we can use coroutines to perform asynchronous operations without blocking the main thread. Coroutines are lightweight threads that can be suspended and resumed without blocking other coroutines.
To use coroutines with Retrofit, we need to mark our interface functions with the suspend
modifier. This tells the compiler that these functions can be called from within a coroutine scope and that they can be suspended until the result is available.
We also need to add the kotlinx-coroutines-android
dependency to our project:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
Then, we can use the lifecycleScope
or viewModelScope
extensions from the androidx.lifecycle:lifecycle-runtime-ktx
library to launch coroutines in our activities or view models:
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
For example, to get a list of users and display them in a RecyclerView, we can write:
class MainActivity : AppCompatActivity() {
private val userService: UserService by lazy {
val retrofit = Retrofit.Builder()
.baseUrl("https://example.com/api/")
.addConverterFactory(JacksonConverterFactory.create())
.build() retrofit.create(UserService::class.java)
} private val adapter: UserAdapter by lazy {
UserAdapter()
} override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) recyclerView.adapter = adapter lifecycleScope.launch {
try {
val users = userService.getUsers()
adapter.submitList(users)
} catch (e: Exception) {
Toast.makeText(this@MainActivity, e.message, Toast.LENGTH_SHORT).show()
}
}
}
}
The lifecycleScope.launch
function creates a coroutine that is bound to the lifecycle of the activity. The try-catch
block handles any exceptions that may occur during the network request. The submitList
function updates the RecyclerView with the list of users.
Conclusion
In this article, we learned how to use Retrofit in Kotlin to make HTTP requests to a RESTful API. We also learned how to use coroutines to perform asynchronous operations with Retrofit.
Retrofit is a powerful and easy-to-use library that can simplify the integration of web services in our Android and Java/Kotlin applications.