Retrofit: What It Is, Features of Android HTTP Client

Author: IT Sectr Published: 2026-03-07 Reading time: 8 min

Retrofit is a typed HTTP client for Android and Kotlin, developed by Square. The library allows you to turn a REST API into a Java or Kotlin interface using annotations. According to Square, 2025, Retrofit is used in thousands of apps as the standard tool for working with HTTP requests.

Key Takeaways

  • Retrofit is a typed HTTP client from Square for Android and Kotlin with a declarative API
  • Annotations @GET, @POST, @Path, @Query describe HTTP requests without boilerplate code
  • Converters Gson, Moshi, and Kotlinx Serialization transform JSON into Kotlin objects
  • OkHttp is the mandatory transport layer that executes all HTTP requests under the hood of Retrofit
  • Suspend functions integrate Retrofit with Kotlin coroutines for asynchronous calls

What is Retrofit?

Retrofit is a library for typed interaction with REST API on the Android platform, developed by Square. It provides a declarative way to describe HTTP requests through Java interfaces or Kotlin interfaces with annotations, completely eliminating the need for manual JSON parsing and HTTP connection management.

The library emerged in 2013 as an alternative to cumbersome solutions like AsyncTask and HttpURLConnection. By 2025, Retrofit remains the de facto standard for network communication in Android apps thanks to its simplicity and type safety. According to the JetBrains Developer Ecosystem 2024 survey, more than 65% of Android developers use Retrofit in commercial projects.

The key difference of Retrofit from alternatives is the declarative approach: the developer describes what to do (which endpoint to call, which parameters to pass) rather than how to do it (how to open a connection, how to read an InputStream, how to parse JSON). This reduces boilerplate code by 60–70% compared to manual use of HttpURLConnection.

How Retrofit Works

How it works — Retrofit is based on Java dynamic proxies. When a developer calls a method of an interface annotated with Retrofit annotations, Retrofit intercepts the call via the Proxy.newProxyInstance mechanism and converts it into an HTTP request. The entire process happens at runtime without code generation at compile time.

When creating a Retrofit.Builder instance, the base URL and converter factory are specified. The Builder configures OkHttpClient — setting timeouts, interceptors, connection pool, and cache. The create(Class) method generates the interface implementation, returning a proxy object that can be called like a regular class.

The request execution chain looks like this: annotations extract the HTTP method, parameters are substituted into the URL or request body, the converter serializes the body, OkHttp executes the request, the converter deserializes the response, and the result is returned in the specified type. Each stage is isolated and can be replaced with a custom implementation, for example replacing OkHttpClient with MockWebServer for testing or swapping the converter when changing the API.

An important feature — Retrofit does not support streaming data directly. For streaming, OkHttp ResponseBody is used as the return type of the interface method. Retrofit also does not manage request cancellation automatically — to cancel, you need to keep a reference to Call and call cancel(). In Kotlin with suspend functions, request cancellation happens automatically when the parent coroutine is cancelled.

Call Object Lifecycle

Call<T> is an object representing a single HTTP request. After execution (execute or enqueue), a Call cannot be reused — for a repeat request, a new Call must be created by calling the interface method. This prevents accidentally sending the same request twice, which could lead to duplicate operations on the server.

In Kotlin, instead of Call, suspend functions are used, which automatically manage the request lifecycle. Retrofit switches execution to Dispatchers.IO and returns the result to the coroutine. This reduces code by 30–40% compared to the Call and Callback version.

Retrofit Annotations for HTTP Methods

Annotations are the main mechanism for configuring HTTP requests in Retrofit. Each annotation corresponds to a standard HTTP method and accepts a relative path to the endpoint. Retrofit supports GET, POST, PUT, DELETE, PATCH, HEAD, and OPTIONS.

AnnotationHTTP MethodPurpose
@GETGETRetrieve data from the server
@POSTPOSTCreate a new resource
@PUTPUTFully update a resource
@DELETEDELETEDelete a resource
@PATCHPATCHPartially update a resource

Request Parameter Annotations

@Path substitutes a value into a URL segment: @Path("id") Int id replaces {id} in the path. @Query adds a query parameter: @Query("page") Int page turns into ?page=5. @Body passes an object in the request body with automatic serialization via the selected converter. @Header and @Headers manage HTTP headers — static or dynamic.

By combining these annotations, you can describe any REST endpoint. For example, for the endpoint POST /api/users/{id}/posts?limit=10 you need @POST, @Path for id, @Query for limit, and @Body for the passed object. Retrofit will automatically assemble a correct HTTP request. Additionally supported are @Url (dynamic URL), @Field (form-encoded body), @Part and @PartMap for multipart requests with files.

Retrofit Code Examples in Kotlin

Let's look at a practical example — an interface for the GitHub API. A Kotlin interface is created with a method for getting a list of repositories. The Repo data class describes the JSON response structure.

kotlin
data class Repo(
    val name: String,
    val description: String?,
    val stargazersCount: Int,
    val forksCount: Int
)

interface GitHubApi {
    @GET("users/{user}/repos")
    suspend fun getRepos(
        @Path("user") user: String,
        @Query("sort") sort: String = "updated"
    ): List<Repo>
}

After describing the interface, a Retrofit instance is created via Builder. The base URL, converter, and OkHttpClient are configured once and reused through dependency injection.

kotlin
val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .client(OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .build())
    .build()

val api = retrofit.create(GitHubApi::class.java)

Response Handling with Response Wrapper

For flexible handling of HTTP status codes, use the Response<T> wrapper. It provides access to the response code, headers, and body without throwing exceptions on 4xx and 5xx errors. This allows you to handle 404 and 500 without try-catch.

kotlin
interface GitHubApi {
    @GET("users/{user}/repos")
    suspend fun getRepos(
        @Path("user") user: String
    ): Response<List<Repo>>
}

val response = api.getRepos("octocat")
if (response.isSuccessful) {
    println(response.body()?.size)
} else {
    Log.e("API", "Error: ${response.code()}")
}

Converters and Serialization in Retrofit

Converters are Retrofit components responsible for converting objects to HTTP body and back. Retrofit does not embed serialization into its core — instead it uses a modular approach via Converter.Factory, allowing any serialization library to be plugged in.

The most popular converter is GsonConverterFactory by Google based on the Gson library. It works for most projects, supports custom TypeAdapter and JsonDeserializer. However, Gson uses reflection and does not respect Kotlin's null safety, which can lead to NPE on unexpected null fields.

An alternative is MoshiConverterFactory by Square: stricter with types, with better Kotlin support (null safety, default values) and no reflection. For pure Kotlin projects, Kotlinx Serialization Converter is optimal, working with @Serializable annotations at compile time. It uses no reflection, supports sealed class, default values, and multiplatform.

The choice of converter affects performance and type safety. Gson without custom configuration can deserialize null into a non-null Kotlin field, causing NPE on access. Moshi solves this problem through @Json(name) annotation and failOnUnknown. Kotlinx Serialization is the safest — it generates code at compile time, completely eliminating runtime type errors.

Common Mistakes When Working with Retrofit

Lack of HTTP error handling in suspend functions is the most common problem. If the server returns 4xx or 5xx, Retrofit throws HttpException. Without try-catch, the app will crash. Using Response<T> as the return type solves this by allowing you to check isSuccessful before accessing the body.

Incorrect caching configuration leads to excessive traffic. Retrofit does not cache responses by itself — this is handled by OkHttpClient through Cache. Without a cache, every request is fully executed, even when data hasn't changed. Adding a 10 MB Cache in OkHttpClient reduces traffic by 40–60% on repeated requests for the same information.

Creating Retrofit for every request is a common beginner mistake. Retrofit.Builder is a resource-intensive operation involving proxy class generation at runtime. Best practice is to create one Retrofit instance and reuse it through DI frameworks. Hilt, Koin, or Dagger provide a singleton Retrofit instance for the entire app, saving memory and speeding up requests.

Ignoring Interceptor for authorization is the fourth problem. Instead of manually adding the Authorization header to each call, configure a global Interceptor in OkHttpClient. The Interceptor intercepts every request, adds the Bearer token, and the Authenticator handles the 401 response, refreshing the token and retrying the request automatically. This centralizes authentication logic.

Frequently Asked Questions

How is Retrofit different from OkHttp?

Retrofit is a wrapper on top of OkHttp, providing a declarative API through annotations. OkHttp is a low-level HTTP client working with Request and Response directly. Retrofit simplifies typing, serialization, and response handling, using OkHttp as the transport layer.

Which converter should I choose for Retrofit?

For Java projects — GsonConverterFactory. For Kotlin with Moshi — MoshiConverterFactory (safer with types). The optimal choice for pure Kotlin is Kotlinx Serialization Converter. It works without reflection, supports sealed class and default values.

Does Retrofit support coroutines?

Yes, starting from version 2.6.0 Retrofit supports suspend functions. Declare the method as suspend, and Retrofit will execute the request on Dispatchers.IO, returning the result to the coroutine. No need to use Call and enqueue — the code becomes sequential.

How to set up authorization in Retrofit?

Authorization is added through an OkHttp Interceptor. In intercept(), add the Authorization header. For dynamic tokens, use OkHttp's Authenticator — it intercepts the 401 response and automatically refreshes the token, retrying the request with the new header.

Can Retrofit be used without OkHttp?

No — Retrofit always uses OkHttp as the transport layer. OkHttpClient is passed via Builder.client() and manages timeouts, interceptors, caching, and connection pooling. Without OkHttp, Retrofit cannot execute a single request.

Summary

  • Retrofit is a typed HTTP client from Square for Android and Kotlin with a declarative annotation-based API
  • Annotations @GET, @POST, @Path, @Query, and @Body describe REST requests without boilerplate code
  • Java dynamic proxies convert interface method calls into HTTP requests at runtime
  • Converters Gson, Moshi, and Kotlinx Serialization provide JSON serialization into objects
  • OkHttp is the mandatory transport layer with interceptors, caching, and connection pooling
  • Suspend functions integrate asynchronous HTTP calls with Kotlin coroutines
  • Response wrapper handles 4xx and 5xx HTTP errors without unhandled exceptions

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also