Careeroza
Retrofit with Coroutines
Suspend API Interface
Retrofit turns an HTTP API into a Kotlin interface. Declare functions as suspend and Retrofit does the call on OkHttp's background threads. Non-2xx responses throw HttpException, network failures throw IOException.
@Serializable
data class ProductDto(val id: Long, val name: String, val price: Int, val stock: Int)
interface ShopApi {
@GET("products")
suspend fun getProducts(@Query("page") page: Int = 0, @Query("size") size: Int = 20): List<ProductDto>
@GET("products/{id}")
suspend fun getProduct(@Path("id") id: Long): ProductDto
@POST("orders")
suspend fun placeOrder(@Body request: OrderRequest): Response<OrderDto> // Response<T> to read status/headers
}
object Network {
private val json = Json { ignoreUnknownKeys = true }
private val client = OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC })
.connectTimeout(15, TimeUnit.SECONDS)
.build()
val api: ShopApi = Retrofit.Builder()
.baseUrl("https://api.myshop.example/")
.client(client)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
.create(ShopApi::class.java)
}Repository: Network + Cache
class ProductRepository(
private val api: ShopApi,
private val dao: ProductDao,
private val io: CoroutineDispatcher = Dispatchers.IO,
) {
fun observeProducts(): Flow<List<Product>> = dao.observeAll().map { list -> list.map { it.toDomain() } }
/** Offline-first: show cached rows at once, refresh from the network in the background. */
suspend fun refresh(): Result<Unit> = withContext(io) {
try {
val fresh = api.getProducts()
dao.replaceAll(fresh.map { it.toEntity() })
Result.success(Unit)
} catch (e: CancellationException) {
throw e
} catch (e: IOException) {
Result.failure(e)
} catch (e: HttpException) {
Result.failure(e)
}
}
}Example
A typical request/response seen in the OkHttp log:
GET https://api.myshop.example/products?page=0&size=20Example output
<-- 200 OK (142ms)
[{"id":1,"name":"Basmati Rice 5kg","price":649,"stock":40},
{"id":2,"name":"Toor Dal 1kg","price":189,"stock":0}]Tip: Add <uses-permission android:name="android.permission.INTERNET" /> to AndroidManifest.xml, or every call fails with a SecurityException.