Is there a good way to have the client emit a `sea...
# apollo-kotlin
n
Is there a good way to have the client emit a
sealed class
for the response? I’d like to emit various states such as
loading
,
failure
, and
success
but I don’t want to have to implement this on every call, I’d rather just do it in one spot 😄
m
The main thing to be aware of is that in GraphQL, it is possible to have partial responses. So it's possible to have both errors and data
If you don't want to handle partial errors, it's perfectly fine to map all partial responses as errors
Then you can emit loading/failure/success from an Rx Observable or a coroutines Flow
n
ahhh, ok, thanks! I’m thinking something like this? What do you think?
Copy code
sealed class Response<out T> {
    object Loading : Response<Nothing>()
    data class Failure(
        val message: String,
        val errors: List<Error>? = null,
        val cause: Throwable? = null
    ) : Response<Nothing>()

    data class Complete<out T>(
        val value: T?,
        val errors: List<com.apollographql.apollo.api.Error>? = null
    ) : Response<T>()
}

fun <D : Operation.Data, T : Any, V : Operation.Variables> ApolloClient.stateful(
    query: Query<D, T, V>,
    retries: Long = 1,
    fetchType: ResponseFetcher = ApolloResponseFetchers.NETWORK_FIRST
): Flow<Response<T>> {
    return query(
        query
    )
        .toBuilder()
        .responseFetcher(fetchType)
        .build()
        .watcher()
        .toFlow()
        .retry(retries)
        .map {
            Response.Complete(it.data, it.errors)
        }
        .onStart {
            emit(Response.Loading)
        }
}
I’m having an issue with the
onStart
and
catch
since the I’m mapping to a
Complete
, it’s expecting that all types emitted to be
Complete
Any suggestions?
meh, close enough:
Copy code
fun <D : Operation.Data, T : Any, V : Operation.Variables> ApolloClient.stateful(
    query: Query<D, T, V>,
    fetchType: ResponseFetcher = ApolloResponseFetchers.NETWORK_FIRST
) = flow{
    try {
        emit(Response.Loading)
        val response = query(query).toBuilder().responseFetcher(fetchType).build().await()
        emit(Response.Complete(response.data, response.errors))
    } catch (ex: Exception) {
        emit(Response.Failure("Error executing $query", cause = ex))
    }
}
m
This looks promising. Is this not working?
n
i haven’t ran it yet 🙂
😀 1