I've been working on GraphQL for a while and I wanted to use custom publisher and Apollo together. But some kind of custom publisher didn't work, I've been dealing with it for days. I couldn't find what I missed
note: After running fetchPublisher(), no error or data is returned.
Custom Publisher
import Foundation
import Apollo
import Combine
struct ApolloPublisher<Query: GraphQLQuery>: Publisher {
typealias Output = GraphQLResult<Query.Data>
typealias Failure = Error
private let client: ApolloClient
private let query: Query
init(client:ApolloClient,
query: Query) {
self.client = client
self.query = query
}
func receive<S>(subscriber: S) where S : Subscriber, S.Failure == Error, S.Input == GraphQLResult<Query.Data> {
let subscription = ApolloSubscription(client: self.client,
query: self.query,
subscriber: subscriber)
subscriber.receive(subscription: subscription)
}
}
Custom Subscription
import Foundation
import Apollo
import Combine
final class ApolloSubscription<GraphQuery: GraphQLQuery, SubscriberType: Subscriber>: Subscription where SubscriberType.Input == GraphQLResult<GraphQuery.Data>, SubscriberType.Failure == Error {
private let subscriber: SubscriberType
private var cancelable: Apollo.Cancellable?
init(client: ApolloClient,
query: GraphQuery,
subscriber: SubscriberType) {
self.subscriber = subscriber
self.cancelable = client.fetch(query: query,
resultHandler: self.handle)
}
deinit {
cancelable?.cancel()
}
func request(_ demand: Subscribers.Demand) {}
func cancel() {
cancelable?.cancel()
cancelable = nil
}
func handle(result: Result<GraphQLResult<GraphQuery.Data>, Error>) {
switch result {
case .success(let resultSet):
_ = subscriber.receive(resultSet)
case .failure(let error):
subscriber.receive(completion: .failure(error))
}
subscriber.receive(completion: .finished)
}
}
extension for ApolloClient
extension ApolloClient {
func fetchPublisher<Query: GraphQLQuery>(query: Query) -> ApolloPublisher<Query> {
return ApolloPublisher(client: self,
query: query)
}
}
Client side.
let apollo = ApolloClient(url: URL(string: "https://api.spacex.land/graphql/")!)
func fetch() -> AnyPublisher<String, Error> {
return apollo.fetchPublisher(query: GetLaunchesQuery())
.mapError { error in
return error
}
.map { response in
return response.data?.launches?.description ?? ""
}
.eraseToAnyPublisher()
}