@@ -40,6 +40,17 @@ public class ApolloClient {
4040 private let queue : DispatchQueue
4141 private let operationQueue : OperationQueue
4242
43+ public enum ApolloClientError : Error , LocalizedError {
44+ case noUploadTransport
45+
46+ public var localizedDescription : String {
47+ switch self {
48+ case . noUploadTransport:
49+ return " Attempting to upload using a transport which does not support uploads. This is a developer error. "
50+ }
51+ }
52+ }
53+
4354 /// Creates a client with the specified network transport and store.
4455 ///
4556 /// - Parameters:
@@ -117,6 +128,30 @@ public class ApolloClient {
117128 @discardableResult public func perform< Mutation: GraphQLMutation > ( mutation: Mutation , context: UnsafeMutableRawPointer ? = nil , queue: DispatchQueue = DispatchQueue . main, resultHandler: GraphQLResultHandler < Mutation . Data > ? = nil ) -> Cancellable {
118129 return send ( operation: mutation, shouldPublishResultToStore: true , context: context, resultHandler: wrapResultHandler ( resultHandler, queue: queue) )
119130 }
131+
132+ /// Uploads the given files with the given operation.
133+ ///
134+ /// - Parameters:
135+ /// - operation: The operation to send
136+ /// - files: An array of `GraphQLFile` objects to send.
137+ /// - queue: A dispatch queue on which the result handler will be called. Defaults to the main queue.
138+ /// - completionHandler: The completion handler to execute when the request completes or errors
139+ /// - Returns: An object that can be used to cancel an in progress request.
140+ /// - Throws: If your `networkTransport` does nto also conform to `UploadingNetworkTransport`.
141+ @discardableResult public func upload< Operation: GraphQLOperation > ( operation: Operation , context: UnsafeMutableRawPointer ? = nil , files: [ GraphQLFile ] , queue: DispatchQueue = . main, resultHandler: GraphQLResultHandler < Operation . Data > ? = nil ) -> Cancellable {
142+ let wrappedHandler = wrapResultHandler ( resultHandler, queue: queue)
143+ guard let uploadingTransport = self . networkTransport as? UploadingNetworkTransport else {
144+ assertionFailure ( " Trying to upload without an uploading transport. Please make sure your network transport conforms to `UploadingNetworkTransport`. " )
145+ wrappedHandler ( . failure( ApolloClientError . noUploadTransport) )
146+ return EmptyCancellable ( )
147+ }
148+
149+ return uploadingTransport. upload ( operation: operation, files: files) { result in
150+ self . handleOperationResult ( shouldPublishResultToStore: true ,
151+ context: context, result,
152+ resultHandler: wrappedHandler)
153+ }
154+ }
120155
121156 /// Subscribe to a subscription
122157 ///
@@ -132,33 +167,40 @@ public class ApolloClient {
132167
133168 fileprivate func send< Operation: GraphQLOperation > ( operation: Operation , shouldPublishResultToStore: Bool , context: UnsafeMutableRawPointer ? , resultHandler: @escaping GraphQLResultHandler < Operation . Data > ) -> Cancellable {
134169 return networkTransport. send ( operation: operation) { result in
135- switch result {
136- case . failure( let error) :
137- resultHandler ( . failure( error) )
138- case . success( let response) :
139- // If there is no need to publish the result to the store, we can use a fast path.
140- if !shouldPublishResultToStore {
141- do {
142- let result = try response. parseResultFast ( )
143- resultHandler ( . success( result) )
144- } catch {
145- resultHandler ( . failure( error) )
146- }
147- return
170+ self . handleOperationResult ( shouldPublishResultToStore: shouldPublishResultToStore,
171+ context: context,
172+ result,
173+ resultHandler: resultHandler)
174+ }
175+ }
176+
177+ private func handleOperationResult< Operation> ( shouldPublishResultToStore: Bool , context: UnsafeMutableRawPointer ? , _ result: Result < GraphQLResponse < Operation > , Error > , resultHandler: @escaping GraphQLResultHandler < Operation . Data > ) {
178+ switch result {
179+ case . failure( let error) :
180+ resultHandler ( . failure( error) )
181+ case . success( let response) :
182+ // If there is no need to publish the result to the store, we can use a fast path.
183+ if !shouldPublishResultToStore {
184+ do {
185+ let result = try response. parseResultFast ( )
186+ resultHandler ( . success( result) )
187+ } catch {
188+ resultHandler ( . failure( error) )
148189 }
149-
150- firstly {
151- try response. parseResult ( cacheKeyForObject: self . cacheKeyForObject)
152- } . andThen { ( result, records) in
153- if let records = records {
154- self . store. publish ( records: records, context: context) . catch { error in
155- preconditionFailure ( String ( describing: error) )
156- }
190+ return
191+ }
192+
193+ firstly {
194+ try response. parseResult ( cacheKeyForObject: self . cacheKeyForObject)
195+ } . andThen { ( result, records) in
196+ if let records = records {
197+ self . store. publish ( records: records, context: context) . catch { error in
198+ preconditionFailure ( String ( describing: error) )
157199 }
158- resultHandler ( . success ( result ) )
159- } . catch { error in
160- resultHandler ( . failure ( error) )
161- }
200+ }
201+ resultHandler ( . success ( result ) )
202+ } . catch { error in
203+ resultHandler ( . failure ( error ) )
162204 }
163205 }
164206 }
0 commit comments