6.4 Retrofit

Retrofit is a type-safe HTTP client for Android and Java that allows you to retrieve or upload data through a REST-based web service. Let's go through how you can set up Retrofit, integrate Moshi for JSON parsing, and make network requests that handle your API data like a pro!

What is Retrofit?

Retrofit is a type-safe library that simplifies the process of making HTTP requests and converting responses. Instead of writing tons of boilerplate code for HTTP clients, Retrofit lets you define your API routes as Kotlin interfaces and converts them into functions. You can describe each route using annotations like @GET, @POST, @PUT, and @DELETE.

For example, let’s say you want to retrieve data from a RESTful API. Using Retrofit, you’ll create an interface that defines API routes as functions, specifying the type of request (GET, POST, etc.) and any parameters required. Once this interface is ready, you can call these functions as if they were native Kotlin functions.

Why Use Moshi?

When your app communicates with APIs, it will often receive data in JSON format. Instead of manually converting JSON to Kotlin objects, Moshi does this for you. As we discussed in the previous section Moshi allows for the automatic interpretation of JSON objects into Kotlin data classes, making it much easier to handle incoming and outgoing data from the API.

API Documentation: The Starting Point

Before diving into the code, ensure you have the API documentation from your web service. This will tell you:

  • How to call certain API requests.

  • What parameters are required.

  • What the API returns.

You’ll use this information to model your data and define your Retrofit interfaces.

Setting Up Retrofit and Moshi in Your Project

First, you'll need to add the necessary dependencies to your project. Open your build.gradle.kts file and include the following lines:

dependencies {
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.moshi:moshi-kotlin:1.14.0")
    ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.1")
    implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
}

plugins {
    id("com.google.devtools.ksp").version("1.6.10-1.0.4")
}

Additionally, don't forget to add internet permissions to your AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />

Step 1: Model Your Data with Kotlin Data Classes

You’ll need to create data models that represent the structure of the JSON data you’re working with. This is where Moshi comes into play. Use @JsonClass and @Json annotations to map the JSON fields to your Kotlin data class fields.

Here’s an example of how you can model a simple user data object:

data class User(
    @Json(name = "id") val userId: Int,
    @Json(name = "name") val userName: String,
    @Json(name = "email") val userEmail: String
)

Step 2: Define the API Interface

Next, define your API routes by creating an interface. Use annotations like @GET, @POST, @PUT, etc., to specify the HTTP method for each endpoint. You can also include headers, query parameters, or path variables with special annotations.

Here’s how you can define an API interface to fetch user data:

interface UserService {
    @GET("users/{id}")
    @Headers("API_KEY: {your_api_key}")
    suspend fun getUser(
        @Path("id") userId: Int,
    ): User
}

Step 3: Create a Retrofit Instance in a Singleton

You should create a singleton Retrofit instance to make network requests throughout your app. You’ll configure Retrofit to use the Moshi converter for JSON handling.

object RetrofitInstance {
    
    private const val BASE_URL = "https://api.example.com/"

    private val retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(MoshiConverterFactory.create())
            .build()
    }

    val api: UserService = retrofit.create(UserService::class.java)
    
}

This singleton creates a Retrofit instance with the Moshi converter and provides access to the API interface UserService.

Step 4: Making Network Requests

Now that everything is set up, making a network request is as simple as calling the interface function. Since you’re likely to use coroutines for asynchronous calls, don’t forget to run your network request in a coroutine context.

val scope = rememberCoroutineScope()
fun fetchUser(userId: Int, authToken: String) {
    scope.launch {
        withContext(Dispatchers.IO){
            try {
                val user = RetrofitInstance.api.getUser(userId, authToken)
                println("User fetched: $user")
            } catch (e: Exception) {
                println("Error fetching user: ${e.message}")
            }
        }
    }
}
  • We use CoroutineScope with Dispatchers.IO to run the network request on a background thread.

  • The getUser function is called, fetching the user data based on the provided userId and authToken.

  • If the request is successful, the user data is printed. Otherwise, an error message is shown.

By using Retrofit with Moshi, you can make your network code cleaner, more readable, and easy to maintain. No more manually parsing JSON or writing complex HTTP clients from scratch—Retrofit and Moshi handle all of that for you. Whether you're building a small app or working on a large project, this setup simplifies making reliable API calls in Kotlin.

Last updated