Android RxJava2 - Как сделать вызов API, когда выдается ошибка? - PullRequest
0 голосов
/ 29 января 2019

Так что в настоящее время я объединяю вызовы API вместе с помощью flatMap, и это хорошо работает для моих случаев использования.Если один из моих вызовов возвращает ошибочный код ответа, то я передаю сингл с ошибкой, который содержит метод throwable с сообщением, в котором говорится, какой вызов не выполнен, и он продолжает идти.Вот как я это делаю сейчас:

dataManager.apiCall1(dataManager.sessionId!!)
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.ui())
        .flatMap{apiCall1Response ->
            if (apiCall1Response.isSuccessful && apiCall1Response.body() != null) {
                // First api call was successful, execute api call 2.
                return@flatMap dataManager.apiCall2(apiCall1Response.importantVal)
            } else {
                // First api call failed 
                return@flatMap Single.error<Throwable>(Throwable("First api call failed."))
            }
        }.flatMap{apiCall2Response ->
            if (apiCall2Response != null && apiCall2Response.isSuccessful && apiCall2Response.body() != null) {
                // Second api call was successful, execute api call 3.
                return@flatMap dataManager.apiCall3(apiCall2Response.importantVal)
            } else if (apiCall2Response is Throwable) {
                // Api Call 1 Failed.
                return@flatMap Single.error<Throwable>(apiCall2Response)
            } else {
                // Second api call failed
                return@flatMap Single.error<Throwable>(Throwable("Second api call failed."))
            }
        }.subscribe({apiCall3Response ->
            if (apiCall3Response is Response<*> && apiCall3Response.body() != null) {
               // Success!
               navigator?.successful(response)
            } else if (apiCall3Response is Throwable) {
               // Something failed from before.
               navigator?.handleError(apiCall3Response)
            } else {
               // Third api call failed, handle error
               navigator!!.handleError(Throwable("Api call 3 failed."))
            }
        }, {throwable ->
            navigator!!.handleError(throwable)
        })

Что ж, теперь я понимаю, что мне нужно сделать другой вызов API, если мой первый вызов API успешен и любой из моих других вызовов не удался.Это последовательность вызовов для входа пользователя в систему, если вход в систему выполнен успешно, но следующий вызов не удался, нам нужно вызвать конечную точку выхода API.Я знаю, что создавать метод сингла внутри метода subscribe () - плохая практика, поэтому я не хочу этого делать.Я бы предпочел пропустить вызов выхода из системы, но проблема в том, что нет способа узнать, какой вызов API возвращается в методе подписки, так как и выход из системы, и apiCall3 возвращают пустые тела.Я также хотел бы вызвать конечную точку выхода из системы в случае сбоя apiCall3, но не уверен, возможно ли это.Вот что я пытаюсь сделать:

dataManager.apiCall1(dataManager.sessionId!!)
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.ui())
        .flatMap{apiCall1Response ->
            if (apiCall1Response.isSuccessful && apiCall1Response.body() != null) {
                // First api call was successful, execute api call 2.
                return@flatMap dataManager.apiCall2(apiCall1Response.importantVal)
            } else {
                // First api call failed 
                return@flatMap Single.error<Throwable>(Throwable("First api call failed."))
            }
        }.flatMap{apiCall2Response ->
            if (apiCall2Response != null && apiCall2Response.isSuccessful && apiCall2Response.body() != null) {
                // Second api call was successful, execute api call 3.
                return@flatMap dataManager.apiCall3(apiCall2Response.importantVal)
            } else if (apiCall2Response is Throwable) {
                // Api Call 1 Failed.
                return@flatMap Single.error<Throwable>(apiCall2Response)
            } else {
                // Second api call failed, logout
                return@flatMap dataManager.logoutApiCall()
            }
        }.subscribe({apiCall3OrLogoutResponse ->
            // I would like to be able to determine which call this response is from. That is the question. 
            if (apiCall3OrLogoutResponse is Response<*> && apiCall3OrLogoutResponse.body() != null) {
               // Success!
               navigator?.successful(response)
            } else if (apiCall3OrLogoutResponse is Throwable) {
               // Something failed from before.
               navigator?.handleError(apiCall3OrLogoutResponse)
            } else {
               // Third api call or logout call failed, handle error
               if (apiCall3OrLogoutResponse is ApiCall3) {
                  // Api Call 3 failed. 
                  // Somehow call logout api endpoint
               } else if (apiCall3OrLogoutResponse is LogoutCall {
                  // Logout call failed.
                  navigator?.handleError(Throwable("Logout failed."))  
               }       
            }
        }, {throwable ->
            navigator!!.handleError(throwable)
        })

Есть ли лучший способ сделать это?В моих сценариях использования я делаю три последовательных вызова API, в случае сбоя первого из них отправляю подписчику подбрасываемый объект, если первый выполняется успешно и после этого происходит сбой, сделайте еще один вызов API.

1 Ответ

0 голосов
/ 29 января 2019

Я понял это, выбросив пользовательские исключения вместо передачи Single.error и проверив мой последний вызов в flatMapCompletable, а не в подписке.Затем я вызвал конечную точку выхода из системы в doOnError, если исключение не является исключением входа в систему.

dataManager.apiCall1(dataManager.sessionId!!)
    .subscribeOn(schedulerProvider.io())
    .observeOn(schedulerProvider.ui())
    .flatMap{apiCall1Response ->
        if (apiCall1Response.isSuccessful && apiCall1Response.body() != null) {
            // First api call was successful, execute api call 2.
            return@flatMap dataManager.apiCall2(apiCall1Response.importantVal)
        } else {
            // First api call failed 
            throw ApiCall1Exception("Api Call 1 failed.")
        }
    }.flatMap{apiCall2Response ->
        if (apiCall2Response != null && apiCall2Response.isSuccessful && apiCall2Response.body() != null) {
            // Second api call was successful, execute api call 3.
            return@flatMap dataManager.apiCall3(apiCall2Response.importantVal)
        } else {
            // Second api call failed
            throw Throwable("Api call 2 failed.")
        }
    }.flatMapCompletable{apiCall3Response ->
        if (apiCall3Response.body() != null) {
            // All api calls were successful!
            Completable.complete()
        } else {
            // Third api call failed.
            throw Throwable("Api call 3 failed.")
        }    
    }.doOnError{throwable ->
        if (throwable !is ApiCall1Exception) {
            // Api call 1 was successful, but something else failed, call logout endpoint.
            dataManager.logout()
                  .subscribeOn(schedulerProvider.io())
                  .observeOn(schedulerProvider.ui())
        }
    }.subscribe({
        // Success!
        navigator?.success()
    }, {throwable ->
        // Something failed!
        navigator?.handleError(throwable)
    })
...