CEng
CEng

Reputation: 53

How to retry rxjava request with refresh token in request body?

The project work with OAuth2 protocol. But there is token in request body, not in header. So I couldn't find a way send request again with new token. Flow: request -> fail -> refresh token -> request

Request exp:
{"request": "asd", "token":"...", "request_data":{} } I'm sending same request with same token when error occurs, as follows:

requestExp().flatMap(resource -> {
          return Single.just(new Object());
    }).retryWhen(th-> {
        AtomicInteger counter = new AtomicInteger();
        return th.takeWhile(e -> {
            if (Objects.equals(e.getMessage(), "test")) {
                return counter.getAndIncrement() != 1;
            } 
        });
    });

Any help?

Upvotes: 0

Views: 573

Answers (1)

Dominik Setniewski
Dominik Setniewski

Reputation: 400

You can try something like this:

    .retryWhen {
            return@retryWhen it.flatMapSingle { throwable ->
                if (throwable is HttpException && throwable.code() == 401) {
                    // when 401 error, let's update the token and retry after that
                    println("Invalid token")
                    return@flatMapSingle refreshToken() // token source will be updated
                }
                // other error, no retry
                return@flatMapSingle Single.error<Any>(throwable)
            }
        }

Example:

fun main() {
    class Params(val token: String)
    class Result

    val tokenSource = BehaviorSubject.create<String>()
    tokenSource.onNext("invalid_token")

    fun request(params: Params): Single<Result> {
        if (params.token != "valid_token") {
            val responseBody = "".toResponseBody("application/json".toMediaTypeOrNull())
            val response = retrofit2.Response.error<Any>(401, responseBody)
            return Single.error(HttpException(response))
        }
        return Single.just(Result())
    }

    fun refreshToken(): Single<String> {
        return Single.fromCallable {
            val token = "valid_token"
            tokenSource.onNext(token)
            return@fromCallable token
        }
    }  

    val s = tokenSource.firstOrError() // get latest token
            .flatMap { request(Params(it)) }
            .retryWhen {
                return@retryWhen it.flatMapSingle { throwable ->
                    if (throwable is HttpException && throwable.code() == 401) {
                        println("Invalid token")
                        return@flatMapSingle refreshToken() // token source will be updated
                    }
                    return@flatMapSingle Single.error<Any>(throwable)
                }
            }
            .subscribe(
                    {
                        println("Success")
                    },
                    {
                        println("Error $it")
                    }
            )

}

Upvotes: 2

Related Questions