💾 Data, Network और Architecture · Lesson 33
Retrofit: REST API call करें
REST API क्या है?
REST API एक web address है जो web page की जगह data (आमतौर पर JSON) लौटाता है। Apps इसे products लाने, orders भेजने या login करने के लिए call करती हैं। Retrofit Kotlin interface को इन HTTP calls में बदलता है और Gson JSON को Kotlin objects में।
जो JSON पढ़ेंगे
Student Diary के "Tip of the day" के लिए हमने codingeasily.in पर असली JSON endpoint बनाया है:
JSON
GET https://codingeasily.in/api/android-tips.json
{
"tips": [
{
"id": 1,
"title": "Use View Binding",
"text": "Replace findViewById with binding.myView – it is null-safe and type-safe.",
"image": "https://codingeasily.in/assets/img/tutorials/android/tip-1.png",
"link": "https://codingeasily.in/tutorial/android/android-view-binding/"
},
…
]
}
Step 1: Permission और dependencies
XML + TOML + Kotlin DSL
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
# libs.versions.toml
retrofit = "2.11.0"
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
// app/build.gradle.kts
implementation(libs.retrofit)
implementation(libs.retrofit.converter.gson)Step 2: Model classes
Property names JSON keys से मेल खाने चाहिए (या @SerializedName("json_key") use करें)।
Kotlin – network/Tip.kt
package com.codingeasily.studentdiary.network
/** Matches one object in https://codingeasily.in/api/android-tips.json */
data class Tip(
val id: Int,
val title: String,
val text: String,
val image: String,
val link: String
)
data class TipsResponse(val tips: List<Tip>)Step 3: API interface + Retrofit
Kotlin – network/TipsApi.kt
package com.codingeasily.studentdiary.network
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
/** Retrofit turns this interface into real HTTP code. */
interface TipsApi {
@GET("api/android-tips.json")
suspend fun getTips(): TipsResponse
companion object {
private const val BASE_URL = "https://codingeasily.in/"
val service: TipsApi by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TipsApi::class.java)
}
}
}Step 4: ViewModel से call करें
Kotlin
// From Student Diary – NoteViewModel
private val _tip = MutableLiveData<TipState>()
val tip: LiveData<TipState> = _tip
fun loadTip(force: Boolean = false) {
if (!force && _tip.value is TipState.Success) return
_tip.value = TipState.Loading
viewModelScope.launch {
_tip.value = try {
val tips = TipsApi.service.getTips().tips
if (tips.isEmpty()) TipState.Error("No tips yet")
else TipState.Success(tips[(System.currentTimeMillis() / 86_400_000L % tips.size).toInt()])
} catch (e: Exception) {
TipState.Error(e.message ?: "Network error")
}
}
}Query, path, POST और headers
KartEasy e-commerce app अपनी PHP API को ठीक ऐसी ही calls करती है:
Kotlin
interface ShopApi {
// GET products.php?category=3&page=1
@GET("products.php")
suspend fun products(@Query("category") categoryId: Int, @Query("page") page: Int = 1): ProductListResponse
// GET product/15
@GET("product/{id}")
suspend fun product(@Path("id") id: Int): ProductResponse
// POST JSON body {"email": "...", "password": "..."}
@POST("auth/login.php")
suspend fun login(@Body body: LoginRequest): LoginResponse
// POST form fields (application/x-www-form-urlencoded)
@FormUrlEncoded
@POST("feedback.php")
suspend fun feedback(@Field("name") name: String, @Field("message") message: String): SimpleResponse
// header for logged-in calls
@GET("orders.php")
suspend fun orders(@Header("Authorization") bearer: String): OrdersResponse
// when you need the status code
@GET("profile.php")
suspend fun profile(): Response<ProfileResponse>
}| Annotation | Result |
|---|---|
| @Query("q") | ?q=value |
| @Path("id") | path में {id} बदलता है |
| @Body | object JSON के रूप में |
| @Field + @FormUrlEncoded | form fields (HTML form जैसे) |
| @Header | इस call के लिए एक header |
Errors, timeouts और logging
Kotlin
try {
val res = api.profile() // Response<ProfileResponse>
if (res.isSuccessful) show(res.body()!!)
else if (res.code() == 401) logout()
else showError("Server error ${res.code()}")
} catch (e: IOException) { // no internet, timeout
showError("Check your internet connection")
} catch (e: HttpException) { // non-2xx when return type is not Response<>
showError("HTTP ${e.code()}")
}
// timeouts + logging (add com.squareup.okhttp3:logging-interceptor)
val client = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY })
.build()
Retrofit.Builder().baseUrl(BASE_URL).client(client).addConverterFactory(GsonConverterFactory.create()).build()आम गलतियाँ
- INTERNET permission नहीं →
SecurityException/ "Permission denied"। - Suspend के बिना main thread से API call →
NetworkOnMainThreadException। - Field names JSON से मेल नहीं खाते → values null (या 0)।
- हर call के लिए नया Retrofit instance → धीमा; एक बार बनाएँ (lazy singleton)।
- R8 के साथ release build crash → model classes keep करें (project का proguard-rules.pro देखें)।
सारांश
- INTERNET permission + Retrofit + Gson converter।
- Data classes JSON से मेल खाएँ; interface methods @GET/@POST के साथ
suspend। - viewModelScope से call करें, try/catch में रखें, sealed UI state expose करें।
✅ Practice
https://codingeasily.in/api/android-tips.json call करके सारे tips RecyclerView में (title + text) दिखाइए। SwipeRefreshLayout से pull-to-refresh जोड़िए।
अक्सर पूछे जाने वाले प्रश्न (FAQ)
Base URL slash पर खत्म क्यों होना चाहिए?
Retrofit base URL और @GET का path जोड़ता है। आख़िर में / न हो तो "baseUrl must end in /" error देता है।
क्या http:// (https नहीं) URLs call कर सकते हैं?
Android 9 से Android default रूप से clear-text HTTP block करता है। HTTPS use करें। Local test server के लिए network security config से allow कर सकते हैं, पर उसे कभी ship न करें।
Gson, Moshi या kotlinx.serialization?
तीनों Retrofit के साथ चलते हैं। शुरुआत के लिए Gson सबसे आसान है और इस course में use हुआ है; बड़ी apps के लिए Moshi और kotlinx.serialization ज़्यादा Kotlin-friendly हैं।
