Custom timeouts with retrofit
I recently ran into the problem of customising timeouts for different API calls when using retrofit.
Ideally, you would be able to specify a timeout using a custom annotation.
interface Api {
@Timeout(60000)
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String): Call<List<Repo>>
}
However, without creating a wrapper around retrofit this isn’t possible.
Instead I created a custom interceptor that uses the @Headers
annotation to parse timeouts. (This will override the default timeouts you have set on your OkHttpClient)
class TimeoutInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val timeout = request.header("X-Timeout")?.toInt() ?: 0
return if (timeout > 0) {
chain.withWriteTimeout(timeout, TimeUnit.MILLISECONDS)
.withReadTimeout(timeout, TimeUnit.MILLISECONDS)
.withConnectTimeout(timeout, TimeUnit.MILLISECONDS)
.proceed(request.newBuilder().removeHeader("X-Timeout").build())
} else {
chain.proceed(request)
}
}
}
To use this you add a header with your timeout to the API declaration. The interceptor will consume this and apply the custom timeout to the chain.
@Headers("X-Timeout: 60000")
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String): Call<List<Repo>>
Don’t forget to add your interceptor to your OkHttpClient
val client = OkHttpClient.Builder()
.addInterceptor(TimeoutInterceptor())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(client)
.build()
val service = retrofit.create(GitHubService::class.java)
This functionality was added in OkHttp 3.9.0 so ensure you are targeting the latest version.