So I am currently chaining API calls together using flatMap and it is working very well for my use cases. If one of my calls return a failing response code, then I pass an error single that contains a throwable with a message that says which call failed and it keeps going. Here is how I'm doing it now:
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)
})
Well, now I am realizing that I need to make a different api call if my first api call is successful and any of my other calls fail. This is a sequence of calls to log a user in, if the login call is successful, but the next call fails, we would need to call the api logout endpoint. I know it is bad practice to create another single inside of the subscribe() method, so I don't want to do that. I would rather pass the logout call through, but the problem is that there is no way of knowing which api call is being returned in the subscribe method since both the logout and apiCall3 return empty bodies. I would also like to call the logout endpoint if apiCall3 fails, but not sure if that is possible. Here is what I am trying to do:
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)
})
Is there a better way to do this? My use cases are making three sequential api calls, if the first one fails, send a throwable to the subscriber, if the first one succeeds and any fail after that, make another api call.