Hey!
Modifying/intercepting the way the Client communicates with the network is a popular request by the community. Solutions have been proposed in #131 and #172, but have not been accepted. Instead a more generic design akin to Apollo Link was suggested.
I'm interested in having a stab at implementing Apollo Link for apollo-ios.
Before I get down to coding, I'd like to discuss a few points:
Let me know what you think!
@martijnwalraven, @MrAlek, @DarkDust
Really happy you're opening this issue, and I think you're asking exactly the right questions. Would be great to bring more people together to figure this out. I'm traveling right now, but maybe we could set up a meeting for next week.
Let me give you some preliminary answers, but we should probably schedule a call to talk about this in more depth and discuss next steps:
Great to get some good feedback on this!
We鈥榬e having a public holiday today and tomorrow in Germany (or at least in Bavaria), so I won鈥檛 be available before Thursday.
Is there a slack channel or something we could use, so we don鈥檛 pollute this issue with organizational things?
@nubbel I just created an #ios-core channel on the Apollo Slack, so let's continue the discussion there!
I think we can just use this issue to continue the discussion. Here is the gist @nubbel created to discuss a type-safe Context.
Quick update: I've drafted an implementation and like to share some details on some of the design decisions I made.
The changes currently live on my branch: https://github.com/apollographql/apollo-ios/compare/master...nubbel:pr/apollo-link?expand=1#diff-2ada2f86538801e01040a5462880d916
ApolloLink has a concept of terminating and non-terminating links. In the Javascript implementation, the link type is determined at runtime.
I thought we could de better and determine it at compile time by using two distinct types TerminatingLink and NonTerminatingLink. This eliminates some compile time checks. For example, concat is only defined on NonTerminatingLink and returns a terminating or non-terminating link, depending on the type of the second link.
However, it makes it difficult to define a split of a terminating and a non-terminating link or vice-versa, because what should the return type be? Schr枚dingersLink?
Requests need to be cancellable, that means links need to be cancellable. I considered three options to achieve that:
Cancelled state to Promise.onCancel handlers. This was inspired by an experimental Javascript feature, AbortController.I chose the first third option and created an CancelController and CancelSignal similar to AbortController/AbortSignal in Javascript. The signal is passed in the context.
It seemed to be the less invasive solution and I actually really like the design.
LinkOperationDescriptorThis struct is used for the test closure in SplitLink to overcome the Swift limitation that we can't store generic closures as properties. In essence, it is a type-erased wrapper for GraphQLOperation. I don't really like, but couldn't find a better solution.
The current design has a few caveats. Most notably, links can only return one result, which renders them unsuitable for subscriptions.
As a next step, I would like to implement an HTTPLink that pulls configuration from the context and makes a network request.
Then, I'd like to see how we could implement a RetryLink.
I managed to get rid of LinkOperationDescriptor and filed a PR #186, so let's continue the discussion there.
Most helpful comment
Quick update: I've drafted an implementation and like to share some details on some of the design decisions I made.
The changes currently live on my branch: https://github.com/apollographql/apollo-ios/compare/master...nubbel:pr/apollo-link?expand=1#diff-2ada2f86538801e01040a5462880d916
Terminating vs. Non-Terminating Links
ApolloLink has a concept of terminating and non-terminating links. In the Javascript implementation, the link type is determined at runtime.
I thought we could de better and determine it at compile time by using two distinct types
TerminatingLinkandNonTerminatingLink. This eliminates some compile time checks. For example,concatis only defined onNonTerminatingLinkand returns a terminating or non-terminating link, depending on the type of the second link.However, it makes it difficult to define a split of a terminating and a non-terminating link or vice-versa, because what should the return type be?
Schr枚dingersLink?Cancellation
Requests need to be cancellable, that means links need to be cancellable. I considered three options to achieve that:
Cancelledstate toPromise.onCancelhandlers. This was inspired by an experimental Javascript feature,AbortController.I chose the first third option and created an
CancelControllerandCancelSignalsimilar toAbortController/AbortSignalin Javascript. The signal is passed in the context.It seemed to be the less invasive solution and I actually really like the design.
LinkOperationDescriptorThis struct is used for the
testclosure inSplitLinkto overcome the Swift limitation that we can't store generic closures as properties. In essence, it is a type-erased wrapper forGraphQLOperation. I don't really like, but couldn't find a better solution.Caveats
The current design has a few caveats. Most notably, links can only return one result, which renders them unsuitable for subscriptions.
Next steps
As a next step, I would like to implement an
HTTPLinkthat pulls configuration from the context and makes a network request.Then, I'd like to see how we could implement a
RetryLink.