Kotlin REST API and Retrofit
Most Android apps fetch data from the internet — a news feed, weather info, user profiles. Retrofit is the most popular library for making HTTP network requests in Android. It turns your API endpoints into simple Kotlin function calls.
What is a REST API
A REST API is a server that responds to HTTP requests with data, usually in JSON format. Your Android app sends a request to a URL, and the server sends back data your app can display.
Diagram — Client–Server Communication
Android App (Client) Server (REST API)
──────────────────── ─────────────────
GET https://api.example.com/users
│
▼ HTTP Request
────────────────────────────────►
Server processes request
◄────────────────────────────────
│ HTTP Response (JSON)
▼
[{"id":1,"name":"Priya"},
{"id":2,"name":"Arun"}]
│
▼
App parses JSON → displays list
Adding Dependencies
// build.gradle.kts (app level)
dependencies {
// Retrofit — HTTP client
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Gson converter — converts JSON to Kotlin data classes
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// Coroutines support
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// ViewModel + LiveData
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
}
Also add internet permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Step 1 — Define the Data Model
Create a Kotlin data class that matches the JSON structure the API returns.
// JSON from API:
// { "id": 1, "name": "Leanne Graham", "email": "sincere@april.biz" }
data class User(
val id: Int,
val name: String,
val email: String
)
Step 2 — Create the API Interface
Define an interface where each function represents one API endpoint. Retrofit reads the annotations and builds the actual HTTP calls for you.
import retrofit2.http.*
interface UserApiService {
// GET all users
@GET("users")
suspend fun getUsers(): List<User>
// GET a single user by ID
@GET("users/{id}")
suspend fun getUserById(@Path("id") userId: Int): User
// POST — create a new user
@POST("users")
suspend fun createUser(@Body user: User): User
// PUT — update an existing user
@PUT("users/{id}")
suspend fun updateUser(@Path("id") id: Int, @Body user: User): User
// DELETE
@DELETE("users/{id}")
suspend fun deleteUser(@Path("id") id: Int)
// GET with query parameters: /users?page=2&limit=10
@GET("users")
suspend fun getUsersPaged(
@Query("page") page: Int,
@Query("limit") limit: Int
): List<User>
}
Step 3 — Build the Retrofit Instance
Create one Retrofit instance for your entire app. Use a singleton object to avoid creating it multiple times.
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
val apiService: UserApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(UserApiService::class.java)
}
}
Diagram — Retrofit Architecture
Your Code Retrofit Server
────────── ──────── ──────
apiService.getUsers()
│
▼
Retrofit reads @GET("users")
│
▼
Builds HTTP request:
GET https://jsonplaceholder.typicode.com/users
│
────────────────────────────────────────►
Sends JSON response
◄────────────────────────────────────────
│
▼
GsonConverterFactory parses JSON
│
▼
Returns List<User> to your code
Step 4 — Create the Repository
class UserRepository {
private val api = RetrofitClient.apiService
suspend fun fetchUsers(): Result<List<User>> {
return try {
val users = api.getUsers()
Result.success(users)
} catch (e: Exception) {
Result.failure(e)
}
}
}
Step 5 — Create the ViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class UserViewModel : ViewModel() {
private val repository = UserRepository()
val users = MutableLiveData<List<User>>()
val error = MutableLiveData<String>()
val isLoading = MutableLiveData<Boolean>()
fun loadUsers() {
viewModelScope.launch {
isLoading.value = true
val result = repository.fetchUsers()
result
.onSuccess { users.value = it }
.onFailure { error.value = it.message }
isLoading.value = false
}
}
}
Step 6 — Display in Activity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel.isLoading.observe(this) { loading ->
binding.progressBar.visibility = if (loading) View.VISIBLE else View.GONE
}
viewModel.users.observe(this) { userList ->
// Update RecyclerView adapter with userList
binding.tvOutput.text = userList.joinToString("\n") { it.name }
}
viewModel.error.observe(this) { msg ->
Toast.makeText(this, "Error: $msg", Toast.LENGTH_LONG).show()
}
viewModel.loadUsers()
}
}
Sending Headers and Auth Tokens
// Static header
@Headers("Content-Type: application/json")
@GET("profile")
suspend fun getProfile(): User
// Dynamic header
@GET("profile")
suspend fun getProfile(@Header("Authorization") token: String): User
// Usage:
val profile = api.getProfile("Bearer eyJhbGciOiJIUzI1NiIsInR...")
Complete Request–Response Flow
User taps "Load"
│
▼
Activity calls viewModel.loadUsers()
│
▼
ViewModel launches coroutine on viewModelScope
│
▼
Repository calls api.getUsers() on Dispatchers.IO
│
▼
Retrofit sends GET /users to server
│
▼
Server returns JSON array
│
▼
Gson converts JSON → List<User>
│
▼
Repository returns Result.success(users)
│
▼
ViewModel posts to users LiveData
│
▼
Activity observe block runs
│
▼
RecyclerView displays list on screen
Testing With a Free Public API
JSONPlaceholder (jsonplaceholder.typicode.com) is a free fake REST API for testing and prototyping. It has ready-made endpoints for users, posts, comments, albums, and todos — no sign-up required. Use it to practice Retrofit without setting up a backend.
// Example endpoints: // GET https://jsonplaceholder.typicode.com/users // GET https://jsonplaceholder.typicode.com/users/1 // GET https://jsonplaceholder.typicode.com/posts // POST https://jsonplaceholder.typicode.com/posts
