Is your feature request related to a problem? Please describe.
Apollo client moving towards KN, there is a need of having KN runtime / client module that is responsible for GraphQL operation execution.
Describe the solution you'd like
One possible and straightforward solution is to port existing Apollo runtime module to KN. Even if this looks like reasonable thing to do there are 2 major concerns regarding this:
ApolloClient related to network / normalized cache, always raised concerns from large companies (like Shopify, Netflix etc.) regarding been too opinionated, the feedback we got Apollo is like all or nothing in solution. Sometimes such companies have own network stack, infra to perform GraphQL operations. We made a huge step towards making our models been used without runtime but we need to redesign our runtime API and make cache layer is truly optional even from API perspective.As a staring point of conversation regarding the vision of new design for our runtime module here is the high level diagram:

Network Transport Layer:
Responsible for network communication, establishing connection, sending and receiving GraphQL request / response
interface GraphQLNetworkTransport {
fun <T> send(request: Request<T>): Flow<Response<T>>
}
class Request<T>(
val operation: Operation<*, T, *>,
val scalarTypeAdapters: ScalarTypeAdapters,
val executionContext: ExecutionContext // similar idea as coroutine context
)
sealed class Response<T> {
data class Success<T>(
val operation: Operation<*, T, *>,
val data: T?,
val errors: List<Error>,
val executionContext: ExecutionContext // similar idea as coroutine context
) : Response<T>()
data class Failure<T>(
val operation: Operation<*, T, *>,
val error: ApolloError,
val executionContext: ExecutionContext // similar idea as coroutine context
) : Response<T>()
}
The reason why send returns Flow instead of being suspended is because of GraphQL subscriptions that can emit multiple responses.
Any implementation of GraphQLNetworkTransport can extend response via context and provide any additional info to the user (such as http response headers in case of Http transport layer, this feature we've been asked for). It works in the same way as coroutine context.
With such abstraction user can easily provide own implementation of transport layer if default Apollo implementations are not suited. By default Apollo is going to provide 2 types of transport layers: Http / Web socket. Both multi-platform targeting Android / iOS.
GraphQL Execution Layer:
Responsible for GraphQL operation execution, Represented as a chain of executors / interceptors. Each executor / interceptor has own responsibility.
interface RequestExecutor {
fun <T> execute(
request: Request<T>,
executorChain: RequestExecutorChain
): Flow<Response<T>>
}
interface RequestExecutorChain {
fun <T> proceed(request: Request<T> ): Flow<Response<T>>
}
Very similar to OkHttp interceptor concept, this abstraction provides flexibility in terms of implementation details and be able to chain different executors. Each executor in the chain can decide if it can short cut and return response right away or pass it down the chain and be able to decorate response.
User can provide own custom implantation of RequestExecutor and add it to the execution chain.
Out of the box Apollo is going to provide several request executors:
NetworkRequestExecutor - should be the last executor in the chain as it performs network execution via provided network transport layerCacheRequestExecutor - normalized cache AutoPersistedQueryRequestExecutor - to support auto persisted queriesSubscriptionRequestExecutor - GraphQL subscription supportBatchedRequestExecutor - nice to have, responsible query batchingAm I correct in understanding that all cancellation mechanisms would be handled through the Flow API, and that's why there's no cancel on any of these?
That's the idea, yes.
Just a question: What is KN?
Just a question: What is KN?
Kotlin Native
Most helpful comment
Kotlin Native