Hey I want to synchronized api in android. I am us...
# android
v
Hey I want to synchronized api in android. I am using interceptor in android. When I am calling api and I get 401 status, I am refreshing my token api which is not calling. Can someone help me how to call refresh api when I used synchronized in kotlin. AuthorizationInterceptor.kt
Copy code
class AuthorizationInterceptor : Interceptor {
 
     override fun intercept(chain: Interceptor.Chain): Response {
         // more code
         return AuthorizationHeader(chain, accessToken)
     }
 
 
     private fun AuthorizationHeader(chain: Interceptor.Chain, accessToken: String): Response = synchronized(this) {
         val api = refreshApiCall() // this api call is not working
         return initialResponse
     }
 }
l
in function intercept, you can check status code of api
Copy code
val req = chain.request()
val statusCode = res.code
after you can handle, refresh token and retry api when code == HTTP_UNAUTHORIZED
i
You can use this approach as well
v
@lam bui my problem is
refreshApiCall
is not calling when I used synchronised in the function
l
Copy code
class AuthInterceptor @Inject constructor(
  private val userLocalSource: UserLocalSource,
  private val apiService: Provider<ApiService>,
) : Interceptor {
  private val mutex = Mutex()

  override fun intercept(chain: Interceptor.Chain): Response {
    val req = chain.request().also { Timber.d("[1] $it") }

    if (NO_AUTH in req.headers.values(CUSTOM_HEADER)) {
      return chain.proceedWithToken(req, null)
    }

    val token =
      runBlocking { userLocalSource.user().first() }?.token.also { Timber.d("[2] $req $it") }
    val res = chain.proceedWithToken(req, token)

    if (res.code != HTTP_UNAUTHORIZED || token == null) {
      return res
    }

    Timber.d("[3] $req")

    val newToken: String? = runBlocking {
      mutex.withLock {
        val user =
          userLocalSource.user().first().also { Timber.d("[4] $req $it") }
        val maybeUpdatedToken = user?.token

        when {
          user == null || maybeUpdatedToken == null -> null.also { Timber.d("[5-1] $req") } // already logged out!
          maybeUpdatedToken != token -> maybeUpdatedToken.also { Timber.d("[5-2] $req") } // refreshed by another request
          else -> {
            Timber.d("[5-3] $req")

            val refreshTokenRes =
              apiService.get().refreshToken(RefreshTokenBody(user.refreshToken, user.username))
                .also {
                  Timber.d("[6] $req $it")
                }

            val code = refreshTokenRes.code()
            if (code == HTTP_OK) {
              refreshTokenRes.body()?.token?.also {
                Timber.d("[7-1] $req")
                userLocalSource.save(
                  user.toBuilder()
                    .setToken(it)
                    .build()
                )
              }
            } else if (code == HTTP_UNAUTHORIZED) {
              Timber.d("[7-2] $req")
              userLocalSource.save(null)
              null
            } else {
              Timber.d("[7-3] $req")
              null
            }
          }
        }
      }
    }

    return if (newToken !== null) chain.proceedWithToken(req, newToken) else res
  }

  private fun Interceptor.Chain.proceedWithToken(req: Request, token: String?): Response =
    req.newBuilder()
      .apply {
        if (token !== null) {
          addHeader("Authorization", "Bearer $token")
        }
      }
      .removeHeader(CUSTOM_HEADER)
      .build()
      .let(::proceed)
}
you can using code here. I success.
@Vivek Modi
v
Sure I'll try this
Can you tell me what is mutex ?
v
thank you so much.
146 Views