Hello all, quite simple question, I’m experimentin...
# coroutines
a
Hello all, quite simple question, I’m experimenting a bit with coroutines, and I wonder what is the best approach to handle multiple endpoints inside single
UseCase
, I guess
flow
should be used?
s
End points, like network requests?
a
Yep, I can do the same logic if I leave objects as Single’s but I guess that not really coroutine way?
s
For Singles and Maybes just use
suspend fun …
a
Yep but inside that one
s
Not sure what you mean?
Copy code
class UseCase { 
    suspend fun getDataFromNetwork(input: Data): Response {
        val request1Result = repo.getResult1(input.field1)
        val request2Result = repo2.getResult2(input.field2)
        return combineResults(request1Result, request2Result)
    }
    ...
}
a
If request1 fails then I want to try out with result2, but both should be returning same value
s
Based on your example (could you post that later in this thread @antoniomarin?):
Copy code
suspend fun buildUseCase(params: None) : CharSequence {
    val clientId = sessionRepository.getLoggedInClientId()
    return try {
        val content = contentsRepository.getHtmlContent(CONTENT_NAME, clientId)
        content.contentValue.toHtml()
    } catch (error: Throwable) {
        contentsRepository.getHtmlContent(CONTENT_NAME, DEFAULT_CLIENT_ID)
    }
}
And if you need to go from a
Single<T>
to a
Flow<T>
, in case you can’t change the function/method signatures of your repos, take a look at this: https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/kotlinx-coroutines-rx2
a
Hi @streetsofboston this is my existing code!
Copy code
override fun buildUseCase(params: None): Single<CharSequence> {
    return sessionRepository.getLoggedInClientId()
        .flatMap { clientId -> contentsRepository.getHtmlContent(CONTENT_NAME, clientId) }
        .onErrorResumeNext(contentsRepository.getHtmlContent(CONTENT_NAME, DEFAULT_CLIENT_ID))
}
Thanks for helping, one question tho, how to handle error for second api which is in catch block. Does that means I would need to add other
try
block inside existing one? I’m trying to figure out are there more elegant solutions 😄
s
The second call to
getHtmlContent
is part of the onErrorResumeNext. If that second call emits an exception/throwable, the final Single returned by buildUseCase will emit that exception as well. The same will happen in the
suspend fun buildUseCase
snippet as well: If the second call to
getHtmlContext
throws an exception, the
suspend fun buildUseCase
will throw an exception. Your Rx example and the corresponding
suspend
example are behaving in similar ways.
You can wrap the calls inside a
runCatching
block followed by a
.mapCatching
block, which allows you to avoid nested try-catch clauses .
a
Uh haven’t heard about those two, gonna check them out btw can similar be achieved by
flow
, going
flowOf(api1, api2)
and then doing some kind of reactive flow? Sorry if I’m making nonsenses 😄
s
Using flow is overkill for async functions that just emit at most one value. In general, you’d consider: Completable ==> suspend fun function() Unit Maybe<T> ==> suspend fun function() : T? Single<T> ==> suspend fun function(): T Observable<T> or Flowable<T> ==> Flow<T>
👍 4
a
I ended up using something similar if someones needs it
Copy code
try {
   val result = runCatching {
      repository.api(params1)
   }.getOrElse {
      repository.api(params2)
   }
   handleSuccess(result)
catch(exp: Exception) {
   handleError(exp)
}