Issue
I am trying to figure out what is the best practice for handling a retrofit response.
I provide the retrofit singlton like this:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor())
.addInterceptor(httpLoggingInterceptor)
.build()
val retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutinesResponseCallAdapterFactory())
.build()
val service = retrofit.create(ShowsService::class.java)
The service interface is this:
interface ShowsService {
@GET("popular")
suspend fun fetchPopularShows(): Response<PopularShows>
}
I get a list of shows from API and parse it in a repository like this:
override suspend fun getShows(): Result<List<Show>?> {
val shows = service.fetchPopularShows()
val body = shows.body()
val errorBody = shows.errorBody()
return when {
body != null -> {
Result.Success(body.shows)
}
errorBody != null -> {
Result.Error(Exception(errorBody.string()))
}
else -> {
Result.Error(Exception("Unknown error: ${shows.raw().message}"))
}
}
}
However, this feels very non-kotlin and also would probably result in code duplication eventually, can anyone point me to a sample where this is implemented in the best practice?
Solution
In principle, you could create an unwrapResponse() generic function that takes a Response<T> and returns a Result<T?> and incorporates your algorithm. By eyeball, something like this:
suspend fun <T> unwrapResponse(response: Response<T>): Result<T> {
val body = response.body()
val errorBody = response.errorBody()
return when {
body != null -> {
Result.Success(body)
}
errorBody != null -> {
Result.Error(Exception(errorBody.string()))
}
else -> {
Result.Error(Exception("Unknown error: ${response.raw().message}"))
}
}
}
You could then call unwrapResponse(service.fetchPopularShows()) to get a Result<PopularShows>.
If you really wanted to allow unwrapResponse() to return a Result<List<Show>?>, you would wind up with something like:
suspend fun <T, R> unwrapResponse(response: Response<T>, unpacker: (T) -> R?): Result<R?> {
val body = response.body()
val errorBody = response.errorBody()
return when {
body != null -> {
Result.Success(unpacker(body))
}
errorBody != null -> {
Result.Error(Exception(errorBody.string()))
}
else -> {
Result.Error(Exception("Unknown error: ${response.raw().message}"))
}
}
}
unwrapResponse(service.fetchPopularShows()) { it.shows } would then give your Result<List<Show>?>.
Again, this is all by eyeball — adjustments are likely to be needed here.
Answered By - CommonsWare
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.