Skip to content

Intermediate: Android basics · Saving data and calling APIs · topic 32 of 50 · 35 min

Networking with Retrofit

Explanation

Retrofit turns a Kotlin interface into an HTTP client. You declare functions with annotations like @GET, @POST, @Path, @Query and @Body, mark them suspend, and Retrofit performs the request on a background thread and converts the JSON response with a converter. You need the INTERNET permission, HTTPS URLs, and a base URL that ends with a slash.

Talking to servers

Most apps get their data from a server through a web API: a set of URLs that return data, usually as JSON. For example, GET https://api.example.com/products/42 might return the details of product 42. HTTP is the protocol used: GET reads data, POST creates, PUT/PATCH update, DELETE removes. Retrofit, an open-source library by Square, is the most widely used way to call such APIs on Android.

Step 1: the permission

xml
<uses-permission android:name="android.permission.INTERNET" />
In AndroidManifest.xml, inside <manifest>. It is a normal permission: granted at install, no dialog.

Step 2: describe the API as an interface

kotlin
@Serializable
data class Product(val id: Int, val name: String, val price: Int)

@Serializable
data class NewReview(val productId: Int, val stars: Int, val text: String)

interface ShopApi {
    @GET("products")
    suspend fun products(@Query("category") category: String): List<Product>   // /products?category=...

    @GET("products/{id}")
    suspend fun product(@Path("id") id: Int): Product                          // /products/42

    @POST("reviews")
    suspend fun addReview(@Body review: NewReview): Response<Unit>             // sends JSON body
}
suspend functions run the request off the main thread and return the parsed result.
AnnotationMeaning
@GET("path") / @POST / @PUT / @DELETEHTTP method and path relative to the base URL
@Path("id")Fills {id} in the path
@Query("category")Adds ?category=value to the URL
@BodySends the object as the request body (JSON)
@Header("Authorization")Adds a header, for example a login token

Response<Unit> in addReview gives you the full HTTP response, including the status code, instead of just the body. Use it when the server returns no body or when you need to check the code yourself.

Step 3: build Retrofit

kotlin
val json = Json { ignoreUnknownKeys = true }

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com/")              // must end with "/"
    .addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
    .build()

val api: ShopApi = retrofit.create(ShopApi::class.java)
The converter turns JSON into your @Serializable classes. Moshi and Gson converters are also common. Build Retrofit once and share it.

Step 4: call it from a repository

kotlin
class ProductRepository(private val api: ShopApi) {
    suspend fun productsIn(category: String): List<Product> = api.products(category)
}

// In a ViewModel:
// viewModelScope.launch { val list = repository.productsIn("kurtas") }
No withContext needed: Retrofit suspend functions are main-safe.

HTTPS and security

Since Android 9 (API 28), apps that target it block plain HTTP (cleartext) traffic by default; use HTTPS URLs. Never put secret API keys in the app: anyone can unpack an APK and read them. Keep secrets on your server and let the app talk to your server.

Seeing what happens: logging

OkHttp, the HTTP engine under Retrofit, has a logging interceptor that prints every request and response in Logcat. Add it only to debug builds, because logs can contain tokens and personal data.

Think of it like this: Retrofit is like a well-trained courier company. Your interface is the order form ("deliver to /products/{id}, bring back a Product"). Retrofit handles the van, the route and the language at the other end (HTTP and JSON), and hands you back a neatly unpacked parcel.

Common mistakes

  • Forgetting the INTERNET permission: requests fail with a SecurityException or "permission denied".
  • A base URL without the trailing slash: Retrofit throws "baseUrl must end in /".
  • Using http:// URLs: blocked as cleartext on modern Android.
  • Calling the API from a composable. Go through a repository and ViewModel.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Networking with Retrofit · 1/6

Retrofit + JSON

Apps get data from web APIs: URLs that return JSON. Retrofit is the standard Android client.

Prefer a video by a teacher? Find free videos on “retrofit android kotlin tutorial suspend coroutines json” on YouTube ↗

In real life: Pincode lookup in a checkout form

When a user types a 6-digit PIN code in a delivery address form, the app calls the company's own address API (GET /pincodes/{pin}) through Retrofit and fills in the city and state. The call is a suspend function in a repository, started from the ViewModel when the PIN field reaches 6 digits, and the form shows "Checking..." while it waits.

kotlin
@Serializable
data class PinInfo(val pin: String, val city: String, val state: String)

interface AddressApi {
    @GET("pincodes/{pin}")
    suspend fun lookup(@Path("pin") pin: String): PinInfo
}
One function, fully typed, no manual JSON parsing.

Practice (0/3 done)

Task 1 · Question

For @GET("orders") suspend fun orders(@Query("status") s: String), what URL does orders("paid") call with base URL https://api.shop.in/?

Task 2 · Question

Why should you not store a secret API key inside the app?

Task 3 · Practice

Using a free public test API (for example one that returns sample posts or users as JSON), create @Serializable models, a Retrofit interface with one GET by id and one GET list with a query, build Retrofit with a JSON converter, and show the results in a LazyColumn via a repository and ViewModel. Add the logging interceptor for debug builds only.

Quick quiz

Question 1

1.Which annotation fills {id} in a Retrofit path?

Question 2

2.What must a Retrofit base URL end with?

Question 3

3.What does the converter factory do?

Question 4

4.Since Android 9, plain http:// requests are…

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which annotation fills {id} in a Retrofit path?

Answer: @Path

@Path replaces the placeholder.

What must a Retrofit base URL end with?

Answer: /

Retrofit requires a trailing slash.

What does the converter factory do?

Answer: Converts JSON to and from Kotlin objects

For example kotlinx.serialization, Moshi or Gson.

Since Android 9, plain http:// requests are…

Answer: Blocked by default (cleartext not permitted)

Cleartext HTTP is blocked by default; use HTTPS.

What does HTTP status 404 mean?Related

Answer: Not found

The requested resource does not exist.

From HTTP requests and FutureBuilder

In https://shop.example.in/cart, which part is the domain?Related

Answer: shop.example.in

The domain names the server: shop.example.in. https:// is the protocol and /cart is the path.

From Browser, server, URL and HTTP

What must the body of a JSON POST be?Related

Answer: A string made with JSON.stringify

fetch sends text; stringify the object.

From fetch: talking to servers

Which part of an HTTP request carries the JSON data you send?Related

Answer: The body

The body comes after the headers and the empty line, and holds the data.

From HTTP requests, responses and methods

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Saving data and calling APIs” before its exam: JSON models and handling errors, Offline-first apps and DataStore.
  2. Module 8 exam: Saving data and calling APIs · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Permissions, Material 3 and polish. 50 topics left in the course before the final exam.

← Previous: Room database