amplify-swift/AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLOperation.swift

135 lines
5.1 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Amplify
import AWSPluginsCore
import Foundation
final public class AWSGraphQLOperation<R: Decodable>: GraphQLOperation<R> {
let session: URLSessionBehavior
let mapper: OperationTaskMapper
let pluginConfig: AWSAPICategoryPluginConfiguration
let graphQLResponseDecoder: GraphQLResponseDecoder<R>
init(request: GraphQLOperationRequest<R>,
session: URLSessionBehavior,
mapper: OperationTaskMapper,
pluginConfig: AWSAPICategoryPluginConfiguration,
resultListener: AWSGraphQLOperation.ResultListener?) {
self.session = session
self.mapper = mapper
self.pluginConfig = pluginConfig
self.graphQLResponseDecoder = GraphQLResponseDecoder(request: request)
super.init(categoryType: .api,
eventName: request.operationType.hubEventName,
request: request,
resultListener: resultListener)
}
override public func main() {
Amplify.API.log.debug("Starting \(request.operationType) \(id)")
if isCancelled {
finish()
return
}
// Validate the request
do {
try request.validate()
} catch let error as APIError {
dispatch(result: .failure(error))
finish()
return
} catch {
dispatch(result: .failure(APIError.unknown("Could not validate request", "", nil)))
finish()
return
}
// Retrieve endpoint configuration
let endpointConfig: AWSAPICategoryPluginConfiguration.EndpointConfig
let requestInterceptors: [URLRequestInterceptor]
do {
endpointConfig = try pluginConfig.endpoints.getConfig(for: request.apiName, endpointType: .graphQL)
if let pluginOptions = request.options.pluginOptions as? AWSPluginOptions,
let authType = pluginOptions.authType {
requestInterceptors = try pluginConfig.interceptorsForEndpoint(withConfig: endpointConfig,
authType: authType)
} else {
requestInterceptors = try pluginConfig.interceptorsForEndpoint(withConfig: endpointConfig)
}
} catch let error as APIError {
dispatch(result: .failure(error))
finish()
return
} catch {
dispatch(result: .failure(APIError.unknown("Could not get endpoint configuration", "", nil)))
finish()
return
}
// Prepare request payload
let queryDocument = GraphQLOperationRequestUtils.getQueryDocument(document: request.document,
variables: request.variables)
if Amplify.API.log.logLevel == .verbose,
let serializedJSON = try? JSONSerialization.data(withJSONObject: queryDocument,
options: .prettyPrinted),
let prettyPrintedQueryDocument = String(data: serializedJSON, encoding: .utf8) {
Amplify.API.log.verbose("\(prettyPrintedQueryDocument)")
}
let requestPayload: Data
do {
requestPayload = try JSONSerialization.data(withJSONObject: queryDocument)
} catch {
dispatch(result: .failure(APIError.operationError("Failed to serialize query document",
"fix the document or variables",
error)))
finish()
return
}
// Create request
let urlRequest = GraphQLOperationRequestUtils.constructRequest(with: endpointConfig.baseURL,
requestPayload: requestPayload)
Task {
// Intercept request
var finalRequest = urlRequest
for interceptor in requestInterceptors {
do {
finalRequest = try await interceptor.intercept(finalRequest)
} catch let error as APIError {
dispatch(result: .failure(error))
cancel()
} catch {
dispatch(result: .failure(APIError.operationError("Failed to intercept request fully.",
"Something wrong with the interceptor",
error)))
cancel()
}
}
if isCancelled {
finish()
return
}
// Begin network task
Amplify.API.log.debug("Starting network task for \(request.operationType) \(id)")
let task = session.dataTaskBehavior(with: finalRequest)
mapper.addPair(operation: self, task: task)
task.resume()
}
}
}