Anshul Tripathi
Anshul Tripathi

Reputation: 11

How to replace/change a URL if a request fails

I want to change the URL of my request after it fails once. Let me elaborate... So if I made a call to www.abc.com/whatever and for some reason this call fails (maybe because of HTTP exception, parsing exceptions or anything else), I want to make the subsequent retries to www.abc-2.com/whatever. Now the problem is, I have been using a utility method to wrap my API calls around try-catch and retry logic. It looks something like this:

suspend fun <T> safeApiCall(apiCall: suspend () -> Response<T>): Result<T> {
    val maxRetries = 5
    val retryCount = 0
    while (retryCount < maxRetries) {
        try {
            val response = apiCall.invoke()
            if (response.isSuccessful) {
                return Result.success(response.body)
            } else {
                retryCount++  
            }
        } catch(e: Exception) {
            // do some logging
            retryCount++  
        }
    }
} 

... and the API service interface looks something like this:

interface MyApiService {
    @GET
    suspend fun getApiData(
        @Url completeUrl: String,
        @QueryMap queries: Map<String, String>,
        @HeaderMap headerMap: Map<String, String> = hashMapOf()
    ): Response<MyApiData>
}

In my repository or ViewModel, I make the API call something like this:

suspend fun getMyApiResponse(): Result<MyApiData> {
    return safeApiCall {
        apiService.getApiData(
            completeUrl = "www.abc.com/whatever",
            queries = listOf(),
        )
    }
}

Now, in safeApiCall method, if the first API call fails, I want to change the host of my api endpoint, but this isn't straight forward since safeApiCall has no information about the request object. I tried changing the methods in my API service to return call objects like this:

interface MyApiService {
    @GET
    fun getApiData(
        @Url completeUrl: String,
        @QueryMap queries: Map<String, String>,
        @HeaderMap headerMap: Map<String, String> = hashMapOf()
    ): Call<MyApiData>
}

but now I have a new problem, while I have access to the request object and the original endpoint to which the request was made, I cannot create a new Call object with the new endpoint to enqueue it since retrofit does that internally, at runtime (AFAIK). Also, it is important to retrieve the origin endpoint since the decision for obtaining the new endpoint depends on the original one.

Is there any method through which I can achieve the URL switching without changing much with safeApiCall method. I know I could've used an Interceptor but then I would have to move all the retry related logic to it and Interceptors just don't seem to the right choice for retrial logic. Any help will be highly appreciated.

Upvotes: 0

Views: 50

Answers (0)

Related Questions