Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OKHttp Authenticator not working with Retrofit suspend fun

I recently updated Retrofit to 2.7.0 and OKHttp to 3.14.4 to take advantage of suspend fun on Retrofit interfaces.

Besides that, I'm also trying to implement Authenticator for the refresh token logic.

This is the retrofit interface

interface OfficeApi {
    @Authenticated
    @POST
    suspend fun getCharacter(): Response<CharacterResponse>
}

This is my Authenticator

class CharacterAuthenticator : Authenticator {

    override fun authenticate(
        route: Route?,
        response: Response
    ): Request? {
        if (responseCount(response) >= 2) return null

        return response.request()
                        .newBuilder()
                        .removeHeader("Authorization")
                        .addHeader("Authorization", "Bearer $newToken")
                        .build()

        return null
    }

    private fun responseCount(response: Response?): Int {
        var result = 1
        while (response?.priorResponse() != null) result++
        return result
    }

}

This is the retrofit fun call

    override suspend fun getCharacter() = safeApiCall(moshiConverter) {
        myApi.getCharacter()
    }

This is the safeApiCall:

suspend fun <T> safeApiCall(
    moshiConverter: MoshiConverter,
    apiCall: suspend () -> Response<T>
): Result<T?, ResultError.NetworkError> {
    return try {
        val response = apiCall()
        if (response.isSuccessful) Result.Success(response.body())
        else {
            val errorBody = response.errorBody()
            val errorBodyResponse = if (errorBody != null) {
                moshiConverter.fromJsonObject(errorBody.string(), ErrorBodyResponse::class.java)
            } else null

            Result.Error(
                ResultError.NetworkError(
                    httpCode = response.code(),
                    httpMessage = response.message(),
                    serverCode = errorBodyResponse?.code,
                    serverMessage = errorBodyResponse?.message
                )
            )
        }
    } catch (exception: Exception) {
        Result.Error(ResultError.NetworkError(-1, exception.message))
    }
}

The Authenticator is working properly, trying to refresh the token twice and then giving up. The problem is: when it gives up (return null), the execution of retrofit (safeApiCall function) does not continue. I don't have any feedback if the call was successful or not.

Is there any problem using Authenticator and Coroutines suspend fun?

like image 621
Guilherme Lima Pereira Avatar asked Dec 11 '19 17:12

Guilherme Lima Pereira


1 Answers

Isn't this an infinite loop?

while (response?.priorResponse() != null)

Shouldn't it be

var curResponse: Response? = response
while (curResponse?.priorResponse() != null) {
    result++
    curResponse = curResponse.priorResponse()
}
like image 164
ImNotAnUser Avatar answered Oct 18 '22 20:10

ImNotAnUser