What you'll learn
Most apps talk to a server — a weather feed, a product catalog, a social API. Retrofit is the standard Android library for calling REST APIs: you describe the endpoints as a Kotlin interface, and it handles the HTTP and JSON for you. Combined with coroutines, a network call is just a suspend function.
By the end you'll be able to:
- Understand REST endpoints and JSON
- Model API responses as serializable data classes
- Declare an API with Retrofit annotations
- Build Retrofit and handle success and error responses
REST & JSON
A REST API exposes data at URLs (endpoints) you interact with using HTTP methods: GET to read, POST to create, PUT/PATCH to update, DELETE to remove. The server replies with JSON — human-readable text of objects and arrays — plus a status code (200 OK, 404 Not Found, 500 Server Error). Your job: send the right request and turn the JSON reply into Kotlin objects.
Data models
Create a data class that mirrors the JSON. Mark it @Serializable so kotlinx.serialization can parse it, and use @SerialName when a JSON field name doesn't match your Kotlin property. These network classes are often suffixed Dto (Data Transfer Object):
// Mirror the JSON shape. @Serializable enables kotlinx parsing.
@Serializable
data class ArticleDto(
val id: Int,
val title: String,
@SerialName("published_at") val publishedAt: String, // map a JSON name
)Tip
The API interface
Describe each endpoint as a suspend function annotated with its HTTP method and path. @Path fills in a URL segment; @Query adds a ?key=value parameter. Retrofit implements the interface for you:
interface NewsApi {
@GET("v2/top-headlines")
suspend fun getHeadlines(
@Query("country") country: String = "us",
): List<ArticleDto>
@GET("v2/articles/{id}")
suspend fun getArticle(@Path("id") id: Int): ArticleDto
}Building Retrofit
Configure Retrofit once with a baseUrl and a converter that knows how to parse JSON, then create your API. Setting ignoreUnknownKeys = true makes parsing resilient — the app won't crash when the server adds a field you don't model:
private val json = Json { ignoreUnknownKeys = true } // don't crash on extra fields
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
val api: NewsApi = retrofit.create(NewsApi::class.java)Calling & handling errors
Networks fail — no signal, timeouts, server errors — so every call needs error handling. Wrap it in try/catch and return a Result (or your own sealed outcome type) so the ViewModel can turn failures into a friendly UI state rather than a crash:
suspend fun fetchHeadlines(): Result<List<Article>> =
try {
val dtos = api.getHeadlines() // suspends on a background thread
Result.success(dtos.map { it.toDomain() }) // map DTO → your model
} catch (e: IOException) {
Result.failure(e) // no connection / timeout
} catch (e: HttpException) {
Result.failure(e) // 4xx / 5xx response
}Watch out
INTERNET permission in the manifest (network calls fail silently without it), and never assume a call succeeds. The two exceptions to expect are IOException (no connection) and HttpException (a non-2xx response).Recap & quick check
Key takeaways
- REST APIs expose data at URL endpoints using HTTP methods (GET/POST/…), replying with JSON and a status code.
- Model responses as @Serializable data classes (DTOs); use @SerialName to map mismatched field names.
- Declare endpoints as suspend functions with @GET/@POST, @Path, and @Query annotations.
- Build Retrofit once with a baseUrl and a JSON converter; ignoreUnknownKeys makes parsing resilient.
- Always handle IOException and HttpException; map DTOs to domain models and return a Result.
Quick check
1. Which HTTP method reads data?
2. How do you declare a Retrofit endpoint that fetches headlines?
3. Why keep DTOs separate from domain models?
4. What does ignoreUnknownKeys = true do?
5. Which exceptions should you catch around a Retrofit call?
You can read local and remote data. The final Phase 4 piece ties them together cleanly — the repository pattern.