Kotlin Retrofit Basics

Retrofit is the most widely used HTTP client for Android. It turns REST API calls into simple Kotlin functions. You define an interface describing the API endpoints, and Retrofit generates all the networking code automatically. Combine it with coroutines for clean, non-blocking API calls.

How Retrofit Works


Your Code:
  val users = apiService.getUsers()

Retrofit generates:
  1. Build HTTP request: GET https://api.example.com/users
  2. Send request over the network
  3. Receive JSON response
  4. Parse JSON → Kotlin data class
  5. Return result to your function

You write the interface. Retrofit does everything else.

Step 1: Add Dependencies

// In app/build.gradle.kts:
dependencies {
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")  // JSON parsing
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")  // request logging
}

// In AndroidManifest.xml — add internet permission:
// <uses-permission android:name="android.permission.INTERNET" />

Step 2: Define Data Classes

import com.google.gson.annotations.SerializedName

data class User(
    val id: Int,
    val name: String,
    val email: String,
    @SerializedName("phone") val phoneNumber: String,  // maps JSON "phone" → phoneNumber
    val address: Address?
)

data class Address(
    val street: String,
    val city: String,
    @SerializedName("zipcode") val pinCode: String
)

data class Post(
    val id: Int,
    val userId: Int,
    val title: String,
    val body: String
)

data class CreatePostRequest(
    val title: String,
    val body: String,
    val userId: Int
)

Step 3: Define the API Interface

import retrofit2.http.*

interface ApiService {

    @GET("users")
    suspend fun getUsers(): List

    @GET("users/{id}")
    suspend fun getUserById(@Path("id") userId: Int): User

    @GET("posts")
    suspend fun getPosts(@Query("userId") userId: Int? = null): List

    @POST("posts")
    suspend fun createPost(@Body request: CreatePostRequest): Post

    @PUT("posts/{id}")
    suspend fun updatePost(@Path("id") id: Int, @Body request: CreatePostRequest): Post

    @DELETE("posts/{id}")
    suspend fun deletePost(@Path("id") id: Int)

    @GET("users")
    suspend fun searchUsers(
        @Query("name_like") nameQuery: String,
        @Query("_limit") limit: Int = 10
    ): List
}

Step 4: Build the Retrofit Instance

import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitClient {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"

    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY  // logs full request/response
    }

    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()

    val apiService: ApiService = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(ApiService::class.java)
}

Step 5: Use in a Repository

class UserRepository(private val api: ApiService = RetrofitClient.apiService) {

    suspend fun getUsers(): Result> = runCatching {
        api.getUsers()
    }

    suspend fun getUser(id: Int): Result = runCatching {
        api.getUserById(id)
    }

    suspend fun createPost(title: String, body: String, userId: Int): Result =
        runCatching {
            api.createPost(CreatePostRequest(title, body, userId))
        }
}

Step 6: Call from ViewModel

class UserViewModel : ViewModel() {
    private val repo = UserRepository()

    private val _users = MutableStateFlow>(emptyList())
    val users: StateFlow> = _users.asStateFlow()

    private val _error = MutableStateFlow(null)
    val error: StateFlow = _error.asStateFlow()

    fun loadUsers() {
        viewModelScope.launch {
            repo.getUsers()
                .onSuccess { _users.value = it }
                .onFailure { _error.value = it.message }
        }
    }
}

// In Activity:
// viewModel.loadUsers()
// lifecycleScope.launch {
//     viewModel.users.collect { users -> adapter.submitList(users) }
// }

Common Retrofit Annotations


Annotation        │ Purpose
──────────────────┼────────────────────────────────────────
@GET("path")      │ HTTP GET request
@POST("path")     │ HTTP POST request
@PUT("path")      │ HTTP PUT request
@DELETE("path")   │ HTTP DELETE request
@Path("id")       │ Replaces {id} in the URL path
@Query("key")     │ Adds ?key=value to the URL
@Body             │ Sends object as JSON request body
@Header("key")    │ Adds a single HTTP header
@Headers(...)     │ Adds multiple static HTTP headers
@FormUrlEncoded   │ Sends data as form fields
@Field("key")     │ One field in a form-encoded request

Leave a Comment

Your email address will not be published. Required fields are marked *