<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Retrofit Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/retrofit/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:50:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>Retrofit Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Retrofit With Kotlin Coroutines: What You Need To Know</title>
		<link>https://blog.codersee.com/retrofit-with-kotlin-coroutines-what-you-need-to-know/</link>
					<comments>https://blog.codersee.com/retrofit-with-kotlin-coroutines-what-you-need-to-know/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 08 Nov 2022 06:30:52 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Jackson]]></category>
		<category><![CDATA[Retrofit]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=5503837</guid>

					<description><![CDATA[<p>In this ultimate guide, I will show you how to use Retrofit 2 With Kotlin Coroutines and what exactly you should know to use it. </p>
<p>The post <a href="https://blog.codersee.com/retrofit-with-kotlin-coroutines-what-you-need-to-know/">Retrofit With Kotlin Coroutines: What You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p>Hello! In this article, I would like to show you how to use <strong>Retrofit 2</strong> with <strong>Kotlin coroutines</strong>.</p>
<p>Please keep in mind, that this blog post is a continuation of the <a href="https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/">previous ultimate retrofit guide</a> and we will focus on how to adjust the project to work properly with Kotlin coroutines. If you haven&#8217;t seen it yet, then you should definitely do that before heading to this one.</p>
<p>Either way, I can assure you that <strong>after finishing these two tutorials, you will have a full understanding of Retrofit and its features</strong>.</p>
<blockquote><p>I&#8217;ve created this article as a response to Uduak comment- thank you for your feedback and I&#8217;m always happy to chat with you all 🙂</p></blockquote>
<p>Finally, please keep in mind that the official support for coroutines has been added in Retrofit2 version <a href="https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05" target="_blank" rel="noopener">2.6.0</a>.</p>
<h2 class="article-heading-introduction">2. Retrofit Kotlin Coroutines Imports</h2>
<p>As the first step, we have to add coroutines functionality to our existing project.</p>
<p>To do so, we will use the <strong>kotlinx-coroutines-core</strong>. And to be on the same page, I will be using the version: <strong>1.6.4.</strong><br />
&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img fetchpriority="high" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<p>&nbsp;</p>
<h3 class="article-heading-sub">2.1. Maven</h3>
<p>If you are working with Maven, then you can add it to your project with the following lines:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">&lt;dependency&gt;
  &lt;groupId&gt;org.jetbrains.kotlinx&lt;/groupId&gt;
  &lt;artifactId&gt;kotlinx-coroutines-core&lt;/artifactId&gt;
  &lt;version&gt;(VERSION)&lt;/version&gt;
&lt;/dependency&gt;</pre>
<h3 class="article-heading-sub">2.2. Gradle</h3>
<p>Alternatively, we can use Gradle to fetch the library:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">// build.gradle
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:&lt;VERSION&gt;'
// build.gradle.kts
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:&lt;VERSION&gt;")</pre>
<h2 class="article-heading-introduction">3. Edit UserApi</h2>
<p>Nextly, let&#8217;s navigate to the <strong>UserApi</strong> interface and make the necessary changes.</p>
<p>Please keep in mind, that the changes I&#8217;m gonna cover here can be applied to each function inside the UserApi (but to avoid boilerplate, I&#8217;ll focus on the GET function):</p>
<blockquote><p>Note: as always, you can find the link to GitHub repository with all examples in the end of this article 🙂</p></blockquote>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">interface UserApi {
  @GET("users")
  suspend fun getUsers(): Response&lt;List&lt;User&gt;&gt;
}</pre>
<p>As we can see, only two adjustments are necessary here:</p>
<ul>
<li>add <strong>suspend</strong> modifier- which in the coroutine&#8217;s context means that our function can be <em>suspended</em> (paused) and <em>resumed</em> (without blocking),</li>
<li>replace a <strong>Call</strong> with a <strong>Response </strong>&#8211; per the release notes, underneath it behaves just like <code class="EnlighterJSRAW" data-enlighter-language="kotlin">fun getUsers(): Response&lt;List&lt;User&gt;&gt;</code> invoked with <code class="EnlighterJSRAW" data-enlighter-language="generic">Call.enqueue</code>.</li>
</ul>
<p>Of course, if we are not interested in headers and status codes, then we can simply return the <strong>List of users</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">interface UserApi {
  @GET("users")
  suspend fun getUsers(): List&lt;User&gt;
}</pre>
<h2 class="article-heading-introduction">4. Retrofit Client and Interceptors</h2>
<p>When it comes to the Retrofit client with Kotlin coroutines- we can keep it as it is:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">object RetrofitClient {

  // Base URL must end in /
  private const val BASE_URL = "http://localhost:8090/v1/"

  private val okHttpClient = OkHttpClient()
    .newBuilder()
    .addInterceptor(AuthorizationInterceptor)
    .addInterceptor(RequestInterceptor)
    .build()

  fun getClient(): Retrofit =
    Retrofit.Builder()
      .client(okHttpClient)
      .baseUrl(BASE_URL)
      .addConverterFactory(JacksonConverterFactory.create())
      .build()
}

object RequestInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val request = chain.request()
    println("Outgoing request to ${request.url()}")
    return chain.proceed(request)
  }
}

object AuthorizationInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val requestWithHeader = chain.request()
      .newBuilder()
      .header(
        "Authorization", UUID.randomUUID().toString()
      ).build()
    return chain.proceed(requestWithHeader)
  }
}</pre>
<h2 class="article-heading-introduction">5. Retrofit User Service</h2>
<p>On the other hand, we need to make small adjustments to the <strong>UserService</strong> class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">class UserService {

  private val retrofit = RetrofitClient.getClient()
  private val userApi = retrofit.create(UserApi::class.java)

  suspend fun successfulUsersResponse() {
    val usersResponse = userApi.getUsers()

    val successful = usersResponse.isSuccessful
    val httpStatusCode = usersResponse.code()
    val httpStatusMessage = usersResponse.message()

    val body: List&lt;User&gt;? = usersResponse.body()

  }

  suspend fun errorUsersResponse() {
    val usersResponse = userApi.getUsers()

    val errorBody: ResponseBody? = usersResponse.errorBody()

    val mapper = ObjectMapper()
    val mappedBody: ErrorResponse? = errorBody?.let { notNullErrorBody -&gt;
      mapper.readValue(notNullErrorBody.string(), ErrorResponse::class.java)
    }
  }

  suspend fun headersUsersResponse() {
    val usersResponse = userApi.getUsers()

    val headers = usersResponse.headers()
    val customHeaderValue = headers["custom-header"]
  }
}</pre>
<p>As we can see, we don&#8217;t have to invoke the <code class="EnlighterJSRAW" data-enlighter-language="generic">execute()</code> method anymore. In addition, we must mark functions with <code class="EnlighterJSRAW" data-enlighter-language="raw">suspend</code>&#8211; because the <code class="EnlighterJSRAW" data-enlighter-language="generic">getUsers()</code> can be either called only from a coroutine or another suspend function.</p>
<p>Finally, if we want to read the error body, we have to make use of the <code class="EnlighterJSRAW" data-enlighter-language="generic">string()</code> method, instead of <code class="EnlighterJSRAW" data-enlighter-language="generic">toString().</code> As the name suggests, this one returns the response as a String. When we run the <code class="EnlighterJSRAW" data-enlighter-language="generic">toString(),</code> we will eventually end up with a runtime exception.</p>
<h2 class="article-heading-introduction">6. Test Retrofit With Kotlin Coroutines</h2>
<p>As the last step, let&#8217;s <strong>test</strong> our Retrofit 2 functionality with Kotlin coroutines.</p>
<p>Although most probably, you will incorporate it into your Android project, to keep this blog post universal, I&#8217;ve prepared a simple <code class="EnlighterJSRAW" data-enlighter-language="generic">main()</code> function:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun main() = runBlocking {
  val service = UserService()

  coroutineScope {
    launch(Dispatchers.IO) {
      delay(10_000)

      println("[${Thread.currentThread().name}] One")

      service.successfulUsersResponse()
    }
    launch(Dispatchers.IO) {
      println("[${Thread.currentThread().name}] Two")

      service.successfulUsersResponse()
    }
  }

  println("[${Thread.currentThread().name}] Done!")
}</pre>
<p>If we run our program, we should see the following:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">[DefaultDispatcher-worker-3] Two

# 10 seconds of delay

[DefaultDispatcher-worker-3] One

[main] Done!</pre>
<p>As we can clearly see, everything is working as expected.</p>
<h2 class="article-heading-introduction">7. Retrofit With Kotlin Coroutines Summary</h2>
<p>And that would be all for this blog post about <strong>Retrofit 2 with Kotlin coroutines</strong>.</p>
<p>As always, the source code for this article can be found in <a href="https://github.com/codersee-blog/kotlin-coroutines-retrofit-2" target="_blank" rel="noopener">this GitHub repository</a>.</p>
<p>Finally, if you enjoyed this content, or would like to ask me about anything, please let me know in the comments section below 🙂</p>
<p>The post <a href="https://blog.codersee.com/retrofit-with-kotlin-coroutines-what-you-need-to-know/">Retrofit With Kotlin Coroutines: What You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/retrofit-with-kotlin-coroutines-what-you-need-to-know/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Retrofit With Kotlin- The Ultimate Guide</title>
		<link>https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/</link>
					<comments>https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Mon, 28 Mar 2022 05:20:38 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Jackson]]></category>
		<category><![CDATA[Retrofit]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=2002671</guid>

					<description><![CDATA[<p>In this step by step guide I will show you Retrofit 2 features and how to configure it in a Kotlin project.</p>
<p>The post <a href="https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/">Retrofit With Kotlin- The Ultimate Guide</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>This time, I would like to show you how to use <strong>Retrofit 2</strong> with <strong>Kotlin</strong>. I will walk you step by step through its features, capabilities and a few obstacles you may encounter when using it.</p>



<p>Let&#8217;s start by answering the question: what exactly the <a href="https://square.github.io/retrofit/" target="_blank" rel="noopener">Retrofit</a> is? It is a type-safe HTTP client for <strong>Android</strong> and <strong>Java</strong>. If you are looking for a library, which will help you to integrate external API in your mobile application, or a back-end service written in Java or Kotlin, then Retrofit is definitely worth a try.</p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<a href="https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FlT3-NBWV9HU%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p></div>



<p>If you find this content useful,<strong> please leave a subscription</strong> 🙂</p>



<h2 class="wp-block-heading" id="h-2-imports">2. Imports</h2>



<p>It&#8217;s worth mentioning, that Retrofit requires <strong>at minimum Java 8+ or Android API 21+</strong>, so it won&#8217;t be compatible with the legacy codebase.</p>



<p>Moreover, depending on when you are reading this article, the latest stable version can be different and I recommend using the latest one. In my examples, I will be using version: <strong>2.9.0</strong>.</p>



<h3 class="wp-block-heading" id="h-2-1-maven">2.1. Maven</h3>



<p>If you are working with Maven, then you can add it to your project with the following lines:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;dependency>
  &lt;groupId>com.squareup.retrofit2&lt;/groupId>
  &lt;artifactId>retrofit&lt;/artifactId>
  &lt;version>(VERSION)&lt;/version>
&lt;/dependency></pre>


<p>[elementor-template id=&#8221;9007393&#8243;]</p>



<h3 class="wp-block-heading" id="h-2-2-gradle">2.2. Gradle</h3>



<p>Alternatively, we can use Gradle to fetch the library:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// build.gradle
implementation 'com.squareup.retrofit2:retrofit:&lt;VERSION>'

// build.gradle.kts
implementation("com.squareup.retrofit2:retrofit:&lt;VERSION>")</pre>



<h3 class="wp-block-heading" id="h-2-3-serialization-amp-deserialization">2.3. Serialization &amp; Deserialization</h3>



<p>By default, Retrofit allows us to work only with <strong>OkHttp&#8217;s RequestBody</strong> and <strong>ResponseBody</strong> objects. Although sometimes it might be sufficient, in most cases we would like to make use of some serialization library when dealing with payloads.</p>



<p>Thankfully, we can achieve that pretty easily by importing desired Converter to our project:</p>



<ul class="wp-block-list">
<li><a href="https://github.com/google/gson">Gson</a>: <em>com.squareup.retrofit2:converter-gson</em></li>



<li><a href="https://github.com/FasterXML/jackson">Jackson</a>: <em>com.squareup.retrofit2:converter-jackson</em></li>



<li><a href="https://github.com/square/moshi/">Moshi</a>: <em>com.squareup.retrofit2:converter-moshi</em></li>



<li><a href="https://developers.google.com/protocol-buffers/">Protobuf</a>: <em>com.squareup.retrofit2:converter-protobuf</em></li>



<li><a href="https://github.com/square/wire">Wire</a>: <em>com.squareup.retrofit2:converter-wire</em></li>



<li><a href="http://simple.sourceforge.net/">Simple XML</a>: <em>com.squareup.retrofit2:converter-simplexml</em></li>



<li><a href="https://docs.oracle.com/javase/tutorial/jaxb/intro/index.html">JAXB</a>: <em>com.squareup.retrofit2:converter-jaxb</em></li>



<li>Scalars: <em>com.squareup.retrofit2:converter-scalars</em></li>
</ul>



<p>For the purposes of this tutorial, I&#8217;ve picked the <strong>Jackson</strong> library, so we need to add the following to <strong>build.gradle.kts</strong> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">implementation("com.squareup.retrofit2:converter-jackson:2.9.0")</pre>



<h2 class="wp-block-heading" id="h-3-retrofit-configuration-with-kotlin">3. Retrofit Configuration With Kotlin</h2>



<p>As the next step, let&#8217;s see how can we configure Retrofit to work with Kotlin.</p>



<h3 class="wp-block-heading" id="h-3-1-add-dto">3.1. Add DTO</h3>



<p>Firstly, let&#8217;s add an example user DTO to our project:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class User(
  @JsonProperty("id") val id: Long,
  @JsonProperty("name") val name: String,
  @JsonProperty("age") val age: Int
)</pre>



<p>As we can see, this simple class expects the JSON returned by the external API to be in the following format:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "id": 1,
  "name": "Name-1",
  "age": 21
}</pre>



<h3 class="wp-block-heading" id="h-3-2-implement-retrofitclient">3.2. Implement RetrofitClient</h3>



<p>Following, let&#8217;s add create a <strong>RetrofitClient</strong> object:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object RetrofitClient {

  private const val BASE_URL = "http://localhost:8090/v1/"

  fun getClient(): Retrofit =
    Retrofit.Builder()
      .baseUrl(BASE_URL)
      .addConverterFactory(JacksonConverterFactory.create())
      .build()
}</pre>



<p>The above code is basically responsible for the following:</p>



<ul class="wp-block-list">
<li>setting the base URL for external API</li>



<li>registering converter factory for objects serialization and deserialization</li>



<li>creating Retrofit instance</li>
</ul>



<p>It&#8217;s worth mentioning that by default the <strong>OkHttpClient</strong> will be used underneath, as a factory for calls. Additionally we have to keep in mind that <strong>baseUrl has to end in /</strong>. Otherwise, the build will fail with <strong>IllegalArgumentException</strong>.</p>



<h3 class="wp-block-heading" id="h-3-3-add-okhttpclient-interceptor">3.3. Add OkHttpClient Interceptor</h3>



<p>As the next step let&#8217;s take a look on how to add interceptors to our requests.</p>



<p>If you are wondering why would we need it, then the answer is pretty simple. Oftentimes, when working with external APIs we want to perform some repeatable actions, like:</p>



<ul class="wp-block-list">
<li>adding authorization headers</li>



<li>logging</li>



<li>error handling etc.</li>
</ul>



<p>And to avoid repeating the same code across the whole app, we can simply add an interceptor, which will affect our calls.</p>



<p>With that being said, let&#8217;s implement a simple <strong>RequestInterceptor</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object RequestInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val request = chain.request()
    println("Outgoing request to ${request.url()}")
    return chain.proceed(request)
  }
}</pre>



<p>As we can see, the above code will print the information about outgoing requests URLs to the output. Later in the article, we will see how to add more interceptors.</p>



<p>But for now, let&#8217;s modify the <strong>RetrofitClient</strong> to make use of a new interceptor:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val okHttpClient = OkHttpClient()
  .newBuilder()
  .addInterceptor(RequestInterceptor)
  .build()

fun getClient(): Retrofit =
  Retrofit.Builder()
    .client(okHttpClient)
    .baseUrl(BASE_URL)
    .addConverterFactory(JacksonConverterFactory.create())
    .build()</pre>



<h2 class="wp-block-heading" id="h-4-handle-responses">4. Handle Responses</h2>



<p>As the next step, let&#8217;s see how to handle Retrofit responses in our Kotlin codebase.</p>



<p>Let&#8217;s start with adding the <strong>UserApi</strong> interface:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">interface UserApi {
  @GET("users")
  fun getUsers(): Call&lt;List&lt;User>>
}</pre>



<p>As can be seen, the above function will be used to perform <em>GET</em> requests to <em>http://localhost:8090/v1/users</em> endpoint. In the next chapter we will take a closer look at all supported HTTP methods, but for now, let&#8217;s discuss the <strong>Call interface</strong>.</p>



<p>A <strong>Call</strong> is basically an invocation of a Retrofit method that sends a request to a web server and returns a response. It can be used synchronously with the <strong>execute</strong> or asynchronously with <strong>enqueue</strong> methods. Additionally, each call can be cancelled at any time with <strong>cancel</strong>.</p>



<p>In this article, <strong>we will focus on synchronous calls</strong>. Nevertheless, if you would like to learn how to work with Retrofit and Kotlin coroutines, please let me know in the comments section. I will be more than happy to make a continuation for this topic.</p>



<h3 class="wp-block-heading" id="h-4-1-response-information">4.1. Response Information</h3>



<p>With that being said, let&#8217;s add a <strong>UserService</strong> and make use of our configuration:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class UserService {

  private val retrofit = RetrofitClient.getClient()
  private val userApi = retrofit.create(UserApi::class.java)

}</pre>



<p>Following, let&#8217;s see what information about the response can we obtain with Retrofit:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun successfulUsersResponse() {
  val usersResponse = userApi.getUsers()
    .execute()

  val successful = usersResponse.isSuccessful
  val httpStatusCode = usersResponse.code()
  val httpStatusMessage = usersResponse.message()

}</pre>



<p>Basically, the <strong>execute()</strong> method returns the <strong>Response&lt;T&gt;</strong>, which lets us obtain info about the&#8230; response 🙂</p>



<p>Let&#8217;s have a close look at each line:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val successful = usersResponse.isSuccessful</pre>



<p>The <strong>isSuccessful</strong> returns true, if the HTTP code is in the range <strong>[200&#8230;300]</strong>. It is a really good choice when we don&#8217;t care about the specific codes.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val httpStatusCode = usersResponse.code()</pre>



<p>On the other hand, the <strong>code()</strong> method returns the exact <strong>Integer value</strong> of the response HTTP status code.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val httpStatusMessage = usersResponse.message()</pre>



<p>Finally, the <strong>message()</strong>, might be useful, if we would like to get the HTTP status message, like <strong>OK</strong>.</p>



<h3 class="wp-block-heading" id="h-4-2-successful-response-body">4.2. Successful Response Body</h3>



<p>Following, let&#8217;s see how easily we can obtain the response body:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val body: List&lt;User>? = usersResponse.body()</pre>



<p>Nevertheless, please keep in mind that Retrofit <strong>body() method may return null</strong>, so we should handle it properly with Kotlin.</p>



<h3 class="wp-block-heading" id="h-4-3-retrofit-error-body">4.3. Retrofit Error Body</h3>



<p>Life would be much easier, if there were no errors.</p>



<p>Nevertheless, they happen, and it&#8217;s better to get more information about them:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val errorBody: ResponseBody? = usersResponse.errorBody()</pre>



<p>The rule is pretty simple here: when the response is <strong>successful</strong>, the <strong>body</strong> is populated. Oherwise, the <strong>errorBody</strong> field <strong>is not null</strong>. It&#8217;s worth mentioning here that Retrofit <strong>errorBody()</strong> method is not generic and we have to handle payload manually.</p>



<p>Let&#8217;s see how can we achieve that with Jackson library. Firstly, let&#8217;s add the <strong>ErrorResponse</strong> data class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class ErrorResponse(
  @JsonProperty("message") val message: String
)</pre>



<p>Following, let&#8217;s use the <strong>ObjectMapper</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val errorBody: ResponseBody? = usersResponse.errorBody()

val mapper = ObjectMapper()

val mappedBody: ErrorResponse? = errorBody?.let { notNullErrorBody ->
  mapper.readValue(notNullErrorBody.toString(), ErrorResponse::class.java)
}</pre>



<p>This way, when <strong>Retrofit</strong> populates the <strong>errorBody</strong> property, we use Kotlin&#8217;s <strong>let</strong> function to deserialize payload into the <strong>ErrorResponse</strong> instance.</p>



<h3 class="wp-block-heading" id="h-4-4-read-response-headers">4.4. Read Response Headers</h3>



<p>Finally, let&#8217;s take a look at response headers, because sometimes they can contain useful information:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val headers = usersResponse.headers()
val customHeaderValue = headers["custom-header"]</pre>



<p>As we can see, with these two lines we can simply obtain the value of the <em>custom-header</em> returned from external API.</p>



<h2 class="wp-block-heading" id="h-5-http-methods">5. HTTP Methods</h2>



<p>So far, we&#8217;ve learned how to handle various responses, but <em>GET</em> is not the only option, so let&#8217;s have a look at other possibilities.</p>



<p>Basically, Retrofit comes with 8 built-in annotations: <strong>HTTP, GET, POST, PUT, PATCH, DELETE, OPTIONS</strong> and <strong>HEAD</strong>. Although the choice will depend on the endpoint we query, I would like to take a closer look at <strong>@HEAD </strong>and <strong>@HTTP</strong> annotations.</p>



<h3 class="wp-block-heading" id="h-5-1-retrofit-head">5.1. Retrofit @HEAD</h3>



<p>Let&#8217;s start with the <strong>@HEAD</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@HEAD("users")
fun headUsers(): Call&lt;Void></pre>



<p>As we can see, the return type here is <strong>Void</strong>&#8211; and it must be always be. Otherwise, <strong>Retrofit will throw IllegalArgumentException with: HEAD method must use Void as response type message</strong>.</p>



<h3 class="wp-block-heading" id="h-5-2-retrofit-http-and-delete">5.2. Retrofit @HTTP and @DELETE</h3>



<p>The <strong>@HTTP</strong> annotation is pretty interesting, as well. It lets us use a custom HTTP verb for a request.</p>



<p>Let&#8217;s see an example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users")
fun getUsers(): Call&lt;List&lt;User>>

@HTTP(method = "GET", path = "users")
fun httpUsers(): Call&lt;List&lt;User>></pre>



<p>Basically, both functions work exactly the same and in real-life scenarios we will hardly ever use the second option. Given that, why should we care about it?</p>



<p>Well, let&#8217;s see the following snippet:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@DELETE("users")
fun failingDeleteUser(@Body user: User): Call&lt;User></pre>



<p>As the name of the function suggests, it will fail. And to be more specific, it will fail with the following message: <strong>Non-body HTTP method cannot contain @Body</strong>.</p>



<p>In such a case, the <strong>@HTTP</strong> annotation allows us to set <strong>hasBody</strong> flag, which we can use to perform the <strong>DELETE</strong> request with payload:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@HTTP(method = "DELETE", path = "users", hasBody = true)
fun workingDeleteUser(@Body user: User): Call&lt;User></pre>



<h2 class="wp-block-heading" id="h-6-url-manipulation">6. URL Manipulation</h2>



<p>Until now, we saw how to use a hard-coded URLs and sometimes it will be sufficient. Nevertheless, in real-life scenarios we will have to specify additional <strong>query parameters</strong>, or <strong>path variables</strong> sooner or later.</p>



<h3 class="wp-block-heading" id="h-6-1-use-absolute-path">6.1. Use Absolute Path</h3>



<p>As the first step, let&#8217;s see how can we instruct Retrofit to use a custom, <strong>absolute path</strong> in our Kotlin interface:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("http://localhost:8090/v3/users")
fun getUsersV3(): Call&lt;List&lt;User>></pre>



<p>This might be really helpful, when we would like to query another API, or just another version of the same provider without the need to set up next interface. Just like above handler will perform a <strong>GET</strong> request to <strong>V3</strong> endpoint.</p>



<h3 class="wp-block-heading" id="h-6-2-dynamic-url-with-url">6.2. Dynamic URL With @Url</h3>



<p>On the other hand, Retrofit has the possibility to specify the URL on method invocation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET
fun getUsersDynamic(@Url url: String): Call&lt;List&lt;User>></pre>



<p>This way, we have the possibility to specify desired URL as an argument. Nevertheles, it&#8217;s a good time to have a look on how URLs are resolved in Retrofit:</p>



<ul class="wp-block-list">
<li><strong>userApi.getUsersDynamic(&#8220;users&#8221;)</strong> &#8211; will be resolved to <em>http://localhost:8090/v1/users</em></li>



<li><strong>userApi.getUsersDynamic(&#8220;/users&#8221;)</strong> &#8211; will be treated as <em>http://localhost:8090/users</em></li>



<li><strong>userApi.getUsersDynamic(&#8220;http://localhost:8090/v3/users&#8221;)</strong> &#8211; just like in the previous example, will use the provided, absolute path</li>
</ul>



<h3 class="wp-block-heading" id="h-6-3-use-path-variable">6.3. Use Path Variable</h3>



<p>Following, let&#8217;s see how to make use of replacement blocks:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users/{userId}")
fun getUserById(@Path("userId") userId: Int): Call&lt;User></pre>



<p>As we can see, we can specify the user id when invoking the function. So the following call: <strong>userApi.getUserById(99)</strong>, will result in <strong>GET</strong> request to <strong>http://localhost:8090/v1/users/99</strong>.</p>



<h3 class="wp-block-heading" id="h-6-4-add-query-parameters">6.4. Add Query Parameters</h3>



<p>Another common way of exchanging information are query parameters:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users?sort_order=asc")
fun getUsersStaticQueryParam(): Call&lt;List&lt;User>></pre>



<p>As can be seen, we use a static <strong>sort_order</strong> query parameter. Although I discourage this approach I wanted to show that it is possible when working with Retrofit.</p>



<p>To get a better control over the sent parameters, we can use a <strong>@Query annotation</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users")
fun getUsersDynamicQueryParam(@Query("sort_order") order: String): Call&lt;List&lt;User>></pre>



<p>This way, our function becomes much more generic. Calling it with the <strong>&#8220;desc&#8221;</strong> argument, will result in <strong>sort_order=desc</strong> in our URL.</p>



<p>As the last one, let&#8217;s see how can we add multiple parameters with <strong>@QueryMap</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users")
fun getUsersDynamicQueryMap(@QueryMap parameters: Map&lt;String, String>): Call&lt;List&lt;User>></pre>



<p>This way, when the API requires multiple query parameters, we can encapsulate them in a map. Without that we would end up with a function taking plenty of arguments, which would affect code readability.</p>



<p>So, the following code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">userApi.getUsersDynamicQueryMap(
  mapOf(
    "order" to "asc",
    "name" to "some"
  )
)</pre>



<p>Will be translated to: <strong>http://localhost:8090/v1/users?order=asc&amp;name=some</strong></p>



<h2 class="wp-block-heading" id="h-7-request-headers">7. Request Headers</h2>



<p>Headers are inseparable part of every REST communication. Oftentimes, we will have to send additional information, like <strong>Content-Type</strong>, or <strong>Authorization</strong>. In this chapter we will learn a few possibilities Retrofit gives us to work with them.</p>



<h3 class="wp-block-heading" id="h-7-1-static-headers">7.1. Static Headers</h3>



<p>Let&#8217;s start with a <strong>single header</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Headers("User-Agent: codersee-application")
@GET("users")
fun getUsersSingleStaticHeader(): Call&lt;List&lt;User>></pre>



<p>Similarly, we can append <strong>multiple headers</strong> to the request:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Headers(
  value = [
    "User-Agent: codersee-application",
    "Custom-Header: my-custom-header"
])
@GET("users")
fun getUsersMultipleStaticHeaders(): Call&lt;List&lt;User>></pre>



<h3 class="wp-block-heading" id="h-7-2-dynamic-headers">7.2. Dynamic Headers</h3>



<p>Although the two above will be useful in some cases, oftentimes we will need to pass a dynamic value for a header, like Authorization for instance. To achieve that, we can use a <strong>@Header</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users")
fun getUsersDynamicHeader(@Header("Authorization") token: String): Call&lt;List&lt;User>></pre>



<p>Just like with <strong>@Query</strong> annotation, Retrofit allows us to pass multiple headers in a Map form <strong>with @HeaderMap</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@GET("users")
fun getUsersHeaderMap(@HeaderMap headers: Map&lt;String, String>): Call&lt;List&lt;User>></pre>



<h3 class="wp-block-heading" id="h-7-3-authorization-interceptor">7.3. Authorization Interceptor</h3>



<p>As the next step, I would like to show you how to make life easier and extract logic responsible for tokens generation to Retrofit config. This is way, each request to the given API will contain a generated token and we won&#8217;t need to add it each time.</p>



<p>Let&#8217;s start with adding a Kotlin object called <strong>AuthorizationInterceptor</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object AuthorizationInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val requestWithHeader = chain.request()
      .newBuilder()
      .header(
        "Authorization", UUID.randomUUID().toString()
      ).build()
    return chain.proceed(requestWithHeader)
  }
}</pre>



<p>Just like in the chapter <strong>number 3</strong>, we extend the <strong>Interceptor</strong> interface, but this time we additionally call a <strong>newBuilder()</strong> on the request instance. With that being done, we can modify its behavior, like add headers or tags (and I highly encourage you to check all the possible options). In your project, the <strong>UUID.randomUUID().toString()</strong> would be replaced with a call to another service, or logic responsible for generating real tokens.</p>



<p>As the last step, we have to add it to the <strong>OkHttpClient</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val okHttpClient = OkHttpClient()
  .newBuilder()
  .addInterceptor(AuthorizationInterceptor)
  .addInterceptor(RequestInterceptor)
  .build()</pre>



<p>This way, each request will be enhanced with the <strong>Authorization</strong> header.</p>



<h2 class="wp-block-heading" id="h-8-request-body">8. Request Body</h2>



<p>Finally, we can learn how to attach a payload to Retrofit requests.</p>



<h3 class="wp-block-heading" id="h-8-1-send-object-as-json">8.1. Send Object as JSON</h3>



<p>Let&#8217;s start with the most popular way of sending data- a JSON payload:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@POST("users")
fun postUsersWithPayload(@Body user: User): Call&lt;User></pre>



<p>With the <strong>@Body</strong> annotation, we can pass a User instance, which will be then <strong>serialized using configured Retrofit converter (Jackson in our case)</strong>.</p>



<h3 class="wp-block-heading" id="h-8-2-retrofit-url-encoded-form">8.2. Retrofit URL-Encoded Form</h3>



<p>On the other hand, if we would like to send data in a URL-Encoded Form, we can use the <strong>@FormUrlEncoded </strong>along with <strong>@Field</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@FormUrlEncoded
@POST("users")
fun postUsersFormUrlEncoded(@Field("field_one") fieldOne: String): Call&lt;User></pre>



<h3 class="wp-block-heading" id="h-8-3-multipart">8.3. Multipart</h3>



<p>Lastly, to send the data as a HTTP multipart request, we can use <strong>@Multipart</strong> on a function with <strong>@Part</strong> on each part send to the external REST API:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Multipart
@POST("users")
fun postUsersMultipart(@Part("something") partOne: RequestBody): Call&lt;User></pre>



<h2 class="wp-block-heading" id="h-9-retrofit-with-kotlin-summary">9. Retrofit With Kotlin Summary</h2>



<p>And that would be all for this article on Retrofit with Kotlin. We&#8217;ve learned together almost everything you will need to know when working on your very own project. As always, you can find the source code in this <a href="https://github.com/codersee-blog/kotlin-retrofit-2" target="_blank" rel="noopener">GitHub Repository</a>.</p>



<p>If you would like to learn a bit more, then check out the continuation of this article, in which I show how to use <a href="https://blog.codersee.com/retrofit-with-kotlin-coroutines-what-you-need-to-know/">Retrofit 2 with Kotlin Coroutines.</a> On the other hand, if you would like to combine this knowledge and learn how to create back-end services with Kotlin, you will find step-by-step tutorials in the <a href="https://blog.codersee.com/category/ktor/">Ktor category</a>.</p>



<p>I hope you enjoyed this article and will be really happy if you would like to give me feedback in the comments section.</p>
<p>The post <a href="https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/">Retrofit With Kotlin- The Ultimate Guide</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/retrofit-with-kotlin-the-ultimate-guide/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-05-01 04:47:18 by W3 Total Cache
-->