Background: I have a graphql server that supports a web application using apollo, and am building an ios app using TCA that will utilize the same graphql endpoint.
Where I am struggling is with Effects
in TCA, specifically getting it to work with the non async/await structure of apollo-ios. Can anyone help me out here? I'm looking to simply make an api call with apollo and update the state but I'm really not sure how to do that with completionhandlers
. Here's a ReducerProtocol I have setup to work with my apollo client dependency which specifies all my network calls
APIClient:
import ComposableArchitecture
import Apollo
import os
private let graphqlEndpointKey = "com.example.app.apiClient.baseUrl"
public struct APIClient {
// API
public var fetchCurrentTime: @Sendable (
_ completion: @escaping (Result<GraphQLResult<GeneratedSchema.CurrentTimeQuery.Data>, Error>) -> Void
) -> Cancellable
private static func createClient (graphqlEndpoint: URL) -> ApolloClient {
let cache = InMemoryNormalizedCache()
let store = ApolloStore(cache: cache)
let client = URLSessionClient()
let provider = NetworkInterceptorProvider(store: store, client: client)
let requestChainTransport = RequestChainNetworkTransport(
interceptorProvider: provider,
endpointURL: graphqlEndpoint
)
return ApolloClient(networkTransport: requestChainTransport, store: store)
}
}
extension APIClient: DependencyKey {
public static let liveValue = APIClient.live()
public static func live(graphqlEndpoint defaultEndpoint: URL = URL(string: "https://api.example.com/graphql")!) -> Self {
let url = UserDefaults.standard.url(forKey: graphqlEndpointKey) ?? defaultEndpoint
let apollo: ApolloClient = self.createClient(graphqlEndpoint: url)
return Self(
fetchCurrentTime: { completion in
apollo.fetch(query: GeneratedSchema.CurrentTimeQuery(), resultHandler: completion)
}
)
}
}
And here is my Reducer Protocol (which I am aware does not work as an effect as is, but I am also wondering how to refactor so that it does)
struct SignIn: ReducerProtocol {
@Dependency(\.apiClient) var apiClient
struct State: Equatable {
var testText: String
}
enum Action {
case buttonTapped
}
var body: some ReducerProtocol<State, Action> {
Reduce { state, action in
switch action {
case .buttonTapped:
apiClient.fetchCurrentTime { result in
switch result {
case .success(let graphQLResult):
print("success, update the state.testText")
// TODO: update the testText
case .failure(let error):
print("error")
}
}
}
}
}
}
The apiClient works and the correct data returns, the issue I'm having is fitting this into the Effect framework of TCA. The desired design here is to use apollo-ios 's code gen and then breakdown each network call into api client to be called by the reducers. Appreciate any help in advance!