I’m having a moment of “what was I thinking” here ...
# apollo-kotlin
s
I’m having a moment of “what was I thinking” here with smth related to error handling and flows. I always seem to find something that I didn’t quite get regarding flows and how to error handle with them 😅 More in thread 🧵
The snippet reads:
Copy code
fun <D : Query.Data> ApolloCall<D>.safeWatch(): Flow<QueryResult<D>> {
  return try {
    watch().map(ApolloResponse<D>::toQueryResult)
  } catch (apolloException: ApolloException) {
    flowOf(QueryResult.Error.NetworkError(apolloException.localizedMessage))
  } catch (throwable: Throwable) {
    if (throwable is CancellationException) {
      throw throwable
    }
    flowOf(QueryResult.Error.GeneralError(throwable.localizedMessage))
  }
}
where .toQueryResult and QueryResult, basically a way to handle exception cases in a typed manner to avoid try catching on all the consumer sites. But I now realized that the entire try/catch there does nothing since I’m catching errors on creating the flow, but that’s not the thing that fails, the failure happens inside the collection of flow right? I think I want something more like:
Copy code
fun <D : Query.Data> ApolloCall<D>.safeWatch(): Flow<QueryResult<D>> {
  return watch(fetchThrows = true)
    .map(ApolloResponse<D>::toQueryResult)
    .catch { exception ->
      when (exception) {
        is CancellationException -> throw exception
        is ApolloException -> {
          emit(QueryResult.Error.NetworkError(exception.localizedMessage))
        }
        else -> {
          emit(QueryResult.Error.GeneralError(exception.localizedMessage))
        }
      }
    }
}
right?
The fact that normally the consumers have to do try catches on each place they’re collecting a flow coming from apollo (in all cases now since 3.x is all flow based) was kinda annoying that’s why we’re tried to introduce these safecollecting functions to make it simple. What’s your experience? I know the docs suggest doing a try/catch in all consumers of these flows basically, like when you do
execute()
. Have you tried abstracting this a bit before with smth like what I was trying to do here? Maybe there’s an opportunity for a lib on top of apollo, kinda like what EitherNet from slack does for Retrofit. But maybe this isn’t optimal for Apollo since you also need to model the partial success cases 🤔
b
an important difference between
.catch
and
try / catch
is that
catch
will not be called for a cancelation - which is usually what you want 🙂
(meaning the
is CancellationException
in the snippet above is probably unneeded)
s
Oh that’s good to know, yes indeed I was trying to throw it back again anyway to let the proper cancellation propagation continue, thanks for that!