Skip to content

Commit

Permalink
refactor code style for rest operations
Browse files Browse the repository at this point in the history
  • Loading branch information
Di Wu committed Sep 6, 2023
1 parent e9d0d5d commit b5407e5
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public struct AWSAPICategoryPluginConfiguration {
self.authService = authService
}

/// Registers an interceptor for the provided API endpoint
/// Registers an customer interceptor for the provided API endpoint
/// - Parameter interceptor: operation interceptor used to decorate API requests
/// - Parameter toEndpoint: API endpoint name
mutating func addInterceptor(_ interceptor: URLRequestInterceptor,
Expand All @@ -84,18 +84,17 @@ public struct AWSAPICategoryPluginConfiguration {
interceptors[apiName]?.addInterceptor(interceptor)
}

/// Returns all the customer defined interceptors registered for `apiName` API endpoint
/// Returns all the interceptors registered for `apiName` API endpoint
/// - Parameter apiName: API endpoint name
/// - Returns: request interceptors
/// - Returns: Optional AWSAPIEndpointInterceptors for the apiName
internal func interceptorsForEndpoint(named apiName: APIEndpointName) -> AWSAPIEndpointInterceptors? {
return interceptors[apiName]
}

/// Returns customer defined interceptors for the provided endpointConfig
/// Returns the interceptors for the provided endpointConfig
/// - Parameters:
/// - endpointConfig: endpoint configuration
/// - Throws: PluginConfigurationError in case of failure building an instance of AWSAuthorizationConfiguration
/// - Returns: An array of URLRequestInterceptor
/// - Returns: Optional AWSAPIEndpointInterceptors for the endpointConfig
internal func interceptorsForEndpoint(withConfig endpointConfig: EndpointConfig) -> AWSAPIEndpointInterceptors? {
return interceptorsForEndpoint(named: endpointConfig.name)
}
Expand All @@ -105,7 +104,7 @@ public struct AWSAPICategoryPluginConfiguration {
/// - endpointConfig: endpoint configuration
/// - authType: overrides the registered auth interceptor
/// - Throws: PluginConfigurationError in case of failure building an instance of AWSAuthorizationConfiguration
/// - Returns: An array of URLRequestInterceptor
/// - Returns: Optional AWSAPIEndpointInterceptors for the endpointConfig and authType
internal func interceptorsForEndpoint(
withConfig endpointConfig: EndpointConfig,
authType: AWSAuthorizationType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ final public class AWSGraphQLOperation<R: Decodable>: GraphQLOperation<R> {
task.resume()
case .failure(let error):
dispatch(result: .failure(error))
cancel()
finish()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,99 +45,48 @@ final public class AWSRESTOperation: AmplifyOperation<
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 amplifyInterceptors: [URLRequestInterceptor]
let customerInterceptors: [URLRequestInterceptor]
let checksumInterceptors: [URLRequestInterceptor]
do {
endpointConfig = try pluginConfig.endpoints.getConfig(for: request.apiName, endpointType: .rest)
let interceptorConfig = pluginConfig.interceptorsForEndpoint(withConfig: endpointConfig)
amplifyInterceptors = interceptorConfig?.amplifyInterceptors ?? []
customerInterceptors = interceptorConfig?.interceptors ?? []
checksumInterceptors = interceptorConfig?.checksumInterceptors ?? []
} 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,
withPath: request.path,
withParams: 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,
requestPayload: request.body
)

Task {
var finalResult: Result<URLRequest, APIError> = .success(urlRequest)
// apply amplify interceptors
for interceptor in amplifyInterceptors {
finalResult = await finalResult.flatMapAsync { request in
await applyInterceptor(interceptor, request: request)
let urlRequest = validateRequest(request).flatMap(buildURLRequest(from:))
let finalRequest = await getEndpointConfig(from: request).flatMapAsync { endpointConfig in
let interceptorConfig = pluginConfig.interceptorsForEndpoint(withConfig: endpointConfig)
let amplifyInterceptors = interceptorConfig?.amplifyInterceptors ?? []
let customerInterceptors = interceptorConfig?.interceptors ?? []
let checksumInterceptors = interceptorConfig?.checksumInterceptors ?? []

var finalResult = urlRequest
// apply amplify interceptors
for interceptor in amplifyInterceptors {
finalResult = await finalResult.flatMapAsync { request in
await applyInterceptor(interceptor, request: request)
}
}
}

// apply customer headers
finalResult = finalResult.map { urlRequest in
var mutableRequest = urlRequest
for (key, value) in request.headers ?? [:] {
mutableRequest.setValue(value, forHTTPHeaderField: key)
// apply customer headers
finalResult = finalResult.map { urlRequest in
var mutableRequest = urlRequest
for (key, value) in request.headers ?? [:] {
mutableRequest.setValue(value, forHTTPHeaderField: key)
}
return mutableRequest
}
return mutableRequest
}

// apply customer interceptors
for interceptor in customerInterceptors {
finalResult = await finalResult.flatMapAsync { request in
await applyInterceptor(interceptor, request: request)
// apply customer interceptors
for interceptor in customerInterceptors {
finalResult = await finalResult.flatMapAsync { request in
await applyInterceptor(interceptor, request: request)
}
}
}

// apply checksum interceptor
for interceptor in checksumInterceptors {
finalResult = await finalResult.flatMapAsync { request in
await applyInterceptor(interceptor, request: request)
// apply checksum interceptor
for interceptor in checksumInterceptors {
finalResult = await finalResult.flatMapAsync { request in
await applyInterceptor(interceptor, request: request)
}
}
return finalResult
}

switch finalResult {
switch finalRequest {
case .success(let finalRequest):
if isCancelled {
finish()
Expand All @@ -150,8 +99,53 @@ final public class AWSRESTOperation: AmplifyOperation<
mapper.addPair(operation: self, task: task)
task.resume()
case .failure(let error):
Amplify.API.log.debug("Dispatching error \(error)")
dispatch(result: .failure(error))
cancel()
finish()
}
}
}

private func validateRequest(_ request: RESTOperationRequest) -> Result<RESTOperationRequest, APIError> {
do {
try request.validate()
return .success(request)
} catch let error as APIError {
return .failure(error)
} catch {
return .failure(APIError.unknown("Could not validate request", "", nil))
}
}

private func getEndpointConfig(
from request: RESTOperationRequest
) -> Result<AWSAPICategoryPluginConfiguration.EndpointConfig, APIError> {
do {
return .success(try pluginConfig.endpoints.getConfig(for: request.apiName, endpointType: .rest))
} catch let error as APIError {
return .failure(error)
} catch {
return .failure(APIError.unknown("Could not get endpoint configuration", "", nil))
}
}

private func buildURLRequest(from request: RESTOperationRequest) -> Result<URLRequest, APIError> {
getEndpointConfig(from: request).flatMap { endpointConfig in
do {
let url = try RESTOperationRequestUtils.constructURL(
for: endpointConfig.baseURL,
withPath: request.path,
withParams: request.queryParameters
)
return .success(RESTOperationRequestUtils.constructURLRequest(
with: url,
operationType: request.operationType,
requestPayload: request.body
))
} catch let error as APIError {
return .failure(error)
} catch {
return .failure(APIError.operationError("Failed to construct URL", "", error))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ResultAsyncTests: XCTestCase {
XCTFail("Should fail")
case .failure(let error):
XCTAssertTrue(error is TestError)
XCTAssertEqual(ObjectIdentifier(expectedError), ObjectIdentifier(error as! TestError))
}
}
}
Expand Down

0 comments on commit b5407e5

Please sign in to comment.