100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Kotlin

Networking with Retrofit

Retrofit turns a REST API into a type-safe Kotlin interface, pairing annotation-driven HTTP calls with coroutines and converters like Moshi or kotlinx.serialization.

Data & NetworkingIntermediate10 min readJul 8, 2026
Analogies

Networking with Retrofit

Retrofit is a type-safe HTTP client for Android and Java built on top of OkHttp. Rather than manually constructing HttpURLConnection requests, parsing raw JSON, and managing threads, you describe your API as a Kotlin interface annotated with HTTP verbs, path parameters, query parameters, and request bodies. Retrofit's runtime generates an implementation of that interface using dynamic proxies, translating each annotated function call into an actual network request and converting the response body into a Kotlin object through a pluggable converter, most commonly Moshi or kotlinx.serialization for JSON. Because each API function can be declared suspend, calling it from a coroutine suspends until the response arrives without blocking a thread, and errors surface as ordinary exceptions you can catch with try/catch or model explicitly with a sealed Result type.

🏏

Cricket analogy: Retrofit is like handing a translator a simple order-sheet of 'request scorecard for match 42' rather than personally wiring a satellite uplink, parsing raw broadcast signal, and formatting it yourself; declaring the function suspend is like the translator working during the tea break without stopping play.

Defining the API interface

Each function in a Retrofit interface corresponds to one endpoint. @GET, @POST, @PUT, @DELETE, and @PATCH annotations specify the HTTP method and the relative path, with {placeholders} filled in by parameters annotated @Path. Query parameters use @Query, and a JSON request body is supplied via a parameter annotated @Body, which Retrofit serializes using the configured converter. Response types are ordinary Kotlin data classes; Retrofit deserializes the JSON response into them field by field, matching property names unless a converter-specific annotation like @Json(name = ...) remaps a field.

🏏

Cricket analogy: Each Retrofit function is like a dedicated request form for a specific stadium action: @GET fetches today's scorecard with {matchId} filled from @Path, @Query narrows it to a specific innings, and @Body posts a new team-sheet submission that the server deserializes into a Player data class.

Building the Retrofit instance and error handling

A Retrofit instance is constructed once with Retrofit.Builder, given a baseUrl, a converter factory, and typically an OkHttpClient configured with interceptors for logging, authentication headers, or timeouts. That single instance then creates implementations of any number of API interfaces via retrofit.create(ApiInterface::class.java). Because network calls can fail for many reasons — no connectivity, a 4xx/5xx response, a malformed body — production code typically wraps each call in a try/catch that distinguishes IOException (connectivity-level failures) from HttpException (a well-formed response with a non-2xx status code), often mapping both into an app-specific sealed Result type so the UI layer never has to reason about Retrofit's own exception hierarchy directly.

🏏

Cricket analogy: Retrofit.Builder configured once with baseUrl and interceptors is like a broadcaster setting up one satellite uplink for the whole tournament, then reusing it for every match; distinguishing IOException (signal dropout) from HttpException (a malformed scorecard feed with a bad status) mirrors mapping both into one clean on-air graphic.

kotlin
data class WeatherResponse(
    val cityName: String,
    val temperatureCelsius: Double,
    val condition: String
)

interface WeatherApi {
    @GET("v1/weather/{city}")
    suspend fun getWeather(
        @Path("city") city: String,
        @Query("units") units: String = "metric"
    ): WeatherResponse

    @POST("v1/favorites")
    suspend fun addFavorite(@Body city: FavoriteRequest): Response<Unit>
}

object NetworkModule {
    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC })
        .build()

    val weatherApi: WeatherApi = Retrofit.Builder()
        .baseUrl("https://api.example.com/")
        .client(okHttpClient)
        .addConverterFactory(MoshiConverterFactory.create())
        .build()
        .create(WeatherApi::class.java)
}

suspend fun fetchWeather(city: String): Result<WeatherResponse> = try {
    Result.success(NetworkModule.weatherApi.getWeather(city))
} catch (e: IOException) {
    Result.failure(e) // no connectivity
} catch (e: HttpException) {
    Result.failure(e) // non-2xx response
}

Retrofit itself never performs the HTTP transaction — it delegates to OkHttp underneath. This is why interceptors, connection pooling, caching, and timeout configuration are all set on the OkHttpClient you hand to Retrofit.Builder.client(), not on Retrofit directly.

A frequent mistake is creating a new Retrofit (and OkHttpClient) instance per request or per screen. This throws away OkHttp's connection pool, forces a fresh TLS handshake on every call, and wastes battery and latency. Build one Retrofit instance and one OkHttpClient, and share both across the app, typically via dependency injection.

  • Retrofit converts an annotated Kotlin interface into a working HTTP client via a generated dynamic proxy.
  • @GET/@POST/@PUT/@DELETE with @Path, @Query, and @Body describe each endpoint declaratively.
  • Suspend functions let API calls be awaited directly from coroutines without manual threading.
  • A converter factory such as Moshi or kotlinx.serialization handles JSON (de)serialization.
  • IOException signals connectivity failures; HttpException signals a non-2xx HTTP response.
  • Retrofit and its OkHttpClient should be constructed once and shared, not recreated per call.

Practice what you learned

Was this page helpful?

Topics covered

#Kotlin#AndroidWithJetpackComposeStudyNotes#MobileDevelopment#NetworkingWithRetrofit#Networking#Retrofit#Defining#API#StudyNotes#SkillVeris