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

130 lines
4.4 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Amplify
import Foundation
final public class AWSRESTOperation: AmplifyOperation<
RESTOperationRequest,
Data,
APIError
>, RESTOperation {
// Data received by the operation
var data = Data()
let session: URLSessionBehavior
var mapper: OperationTaskMapper
let pluginConfig: AWSAPICategoryPluginConfiguration
init(request: RESTOperationRequest,
session: URLSessionBehavior,
mapper: OperationTaskMapper,
pluginConfig: AWSAPICategoryPluginConfiguration,
resultListener: AWSRESTOperation.ResultListener?) {
self.session = session
self.mapper = mapper
self.pluginConfig = pluginConfig
super.init(categoryType: .api,
eventName: request.operationType.hubEventName,
request: request,
resultListener: resultListener)
}
/// The work to execute for this operation
override public func main() {
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: .rest)
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
}
// Construct URL with path
let url: URL
do {
url = try RESTOperationRequestUtils.constructURL(for: endpointConfig.baseURL,
with: request.path,
with: request.queryParameters)
} catch let error as APIError {
dispatch(result: .failure(error))
finish()
return
} catch {
let apiError = APIError.operationError("Failed to construct URL", "", error)
dispatch(result: .failure(apiError))
finish()
return
}
// Construct URL Request with url and request body
let urlRequest = RESTOperationRequestUtils.constructURLRequest(with: url,
operationType: request.operationType,
headers: request.headers,
requestPayload: request.body)
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()
}
}
}