Retrofit turns an HTTP API into a type-safe Kotlin interface:
interface ApiService {
@GET("users/{id}")
suspend fun fetchUser(@Path("id") id: Int): User
@GET("users")
suspend fun fetchAllUsers(): List<User>
}
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
Combining this with the Repository pattern from Module 3 and error handling with a sealed class gives you a robust, testable data layer:
class UserRepository(private val api: ApiService, private val dao: UserDao) {
suspend fun getUser(id: Int): NetworkResult<User> {
return try {
val user = api.fetchUser(id)
dao.insertUser(user)
NetworkResult.Success(user)
} catch (e: IOException) {
// No internet connection — fall back to cached data if we have it
dao.getUserById(id)?.let { NetworkResult.Success(it) }
?: NetworkResult.Error("No connection and no cached data")
} catch (e: HttpException) {
NetworkResult.Error("Server error: ${e.code()}")
}
}
}
Catching IOException and HttpException separately matters: the first means “no network,” where falling back to cache is reasonable; the second means “the server responded, but with an error,” where a cache fallback usually isn’t appropriate.
- Image
- SKU
- Rating
- Price
- Stock
- Availability
- Add to cart
- Description
- Content
- Weight
- Dimensions
- Additional information