Skip to content

Commit

Permalink
feat!: Closure-based reader-writer serde for JSON, FormURL (#1439)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbelkins committed May 10, 2024
1 parent 72fe4c0 commit 61031ff
Show file tree
Hide file tree
Showing 109 changed files with 1,571 additions and 3,747 deletions.
29 changes: 16 additions & 13 deletions AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/Package.Base.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,13 @@ func addProtocolTests() {
let name: String
let sourcePath: String
let testPath: String?
let buildOnly: Bool

init(name: String, sourcePath: String, testPath: String? = nil) {
init(name: String, sourcePath: String, testPath: String? = nil, buildOnly: Bool = false) {
self.name = name
self.sourcePath = sourcePath
self.testPath = testPath
self.buildOnly = buildOnly
}
}

Expand All @@ -217,21 +219,22 @@ func addProtocolTests() {
.init(name: "S3TestSDK", sourcePath: "\(baseDir)/s3"),
.init(name: "rest_json_extras", sourcePath: "\(baseDirLocal)/rest_json_extras"),
.init(name: "AwsQueryExtras", sourcePath: "\(baseDirLocal)/AwsQueryExtras"),
.init(name: "EventStream", sourcePath: "\(baseDirLocal)/EventStream", buildOnly: true),
.init(name: "RPCEventStream", sourcePath: "\(baseDirLocal)/RPCEventStream", buildOnly: true),
.init(name: "Waiters", sourcePath: "\(baseDirLocal)/Waiters", testPath: "codegen/protocol-test-codegen-local/Tests"),
]
for protocolTest in protocolTests {
package.targets += [
.target(
name: protocolTest.name,
dependencies: [.clientRuntime, .awsClientRuntime],
path: "\(protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)"
),
.testTarget(
name: "\(protocolTest.name)Tests",
dependencies: [.smithyTestUtils, .byNameItem(name: protocolTest.name, condition: nil)],
path: "\(protocolTest.testPath ?? protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)Tests"
)
]
let target = Target.target(
name: protocolTest.name,
dependencies: [.clientRuntime, .awsClientRuntime],
path: "\(protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)"
)
let testTarget = protocolTest.buildOnly ? nil : Target.testTarget(
name: "\(protocolTest.name)Tests",
dependencies: [.smithyTestUtils, .byNameItem(name: protocolTest.name, condition: nil)],
path: "\(protocolTest.testPath ?? protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)Tests"
)
package.targets += [target, testTarget].compactMap { $0 }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class S3EmptyBody404Tests: S3XCTestCase {
_ = try await client.headObject(input: input)

// If an error was not thrown by the HeadObject call, fail the test.
XCTFail("Request should have thrown a service error with code NotFound, instead the request succeeded")
} catch let error as AWSServiceError & ClientRuntime.HTTPError where error.errorCode == "NotFound" {
XCTFail("Request should have thrown a NotFound modeled service error, instead the request succeeded")
} catch let error as AWSS3.NotFound {

// The expected error has now been caught. Verify that the body is empty and the status code is 404.
XCTAssertTrue(error.httpResponse.body.isEmpty)
Expand Down
29 changes: 16 additions & 13 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,13 @@ func addProtocolTests() {
let name: String
let sourcePath: String
let testPath: String?
let buildOnly: Bool

init(name: String, sourcePath: String, testPath: String? = nil) {
init(name: String, sourcePath: String, testPath: String? = nil, buildOnly: Bool = false) {
self.name = name
self.sourcePath = sourcePath
self.testPath = testPath
self.buildOnly = buildOnly
}
}

Expand All @@ -217,21 +219,22 @@ func addProtocolTests() {
.init(name: "S3TestSDK", sourcePath: "\(baseDir)/s3"),
.init(name: "rest_json_extras", sourcePath: "\(baseDirLocal)/rest_json_extras"),
.init(name: "AwsQueryExtras", sourcePath: "\(baseDirLocal)/AwsQueryExtras"),
.init(name: "EventStream", sourcePath: "\(baseDirLocal)/EventStream", buildOnly: true),
.init(name: "RPCEventStream", sourcePath: "\(baseDirLocal)/RPCEventStream", buildOnly: true),
.init(name: "Waiters", sourcePath: "\(baseDirLocal)/Waiters", testPath: "codegen/protocol-test-codegen-local/Tests"),
]
for protocolTest in protocolTests {
package.targets += [
.target(
name: protocolTest.name,
dependencies: [.clientRuntime, .awsClientRuntime],
path: "\(protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)"
),
.testTarget(
name: "\(protocolTest.name)Tests",
dependencies: [.smithyTestUtils, .byNameItem(name: protocolTest.name, condition: nil)],
path: "\(protocolTest.testPath ?? protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)Tests"
)
]
let target = Target.target(
name: protocolTest.name,
dependencies: [.clientRuntime, .awsClientRuntime],
path: "\(protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)"
)
let testTarget = protocolTest.buildOnly ? nil : Target.testTarget(
name: "\(protocolTest.name)Tests",
dependencies: [.smithyTestUtils, .byNameItem(name: protocolTest.name, condition: nil)],
path: "\(protocolTest.testPath ?? protocolTest.sourcePath)/swift-codegen/\(protocolTest.name)Tests"
)
package.targets += [target, testTarget].compactMap { $0 }
}
}

Expand Down
28 changes: 0 additions & 28 deletions Sources/Core/AWSClientRuntime/Errors/RestXMLError+AWS.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,31 @@ extension UnknownAWSHTTPServiceError {
/// - requestID2: The request ID2 associated with this error (ID2 used on S3 only.) Defaults to `nil`.
/// - typeName: The non-namespaced name of the error type for this error, or `nil`.
/// - Returns: An error that represents the response.
public static func makeError(
httpResponse: HttpResponse,
message: String?,
requestID: String?,
requestID2: String? = nil,
typeName: String?
) async throws -> Error {
public static func makeError<Base: BaseError>(
baseError: Base
) throws -> Error {
let candidates: [UnknownAWSHTTPErrorCandidate.Type] = [
InvalidAccessKeyId.self
]
if let Candidate = candidates.first(where: { $0.errorCode == typeName }) {
if let Candidate = candidates.first(where: { $0.errorCode == baseError.code }) {
return Candidate.init(
httpResponse: httpResponse,
message: message,
requestID: requestID,
requestID2: requestID2
httpResponse: baseError.httpResponse,
message: baseError.message,
requestID: baseError.requestID,
requestID2: baseError.requestID2
)
}
return UnknownAWSHTTPServiceError(
httpResponse: httpResponse,
message: message,
requestID: requestID,
requestID2: requestID2,
typeName: typeName
httpResponse: baseError.httpResponse,
message: baseError.message,
requestID: baseError.requestID,
requestID2: baseError.requestID2,
typeName: baseError.code
)
}
}

extension ClientRuntime.BaseError {

var requestID2: String? { nil }
}
4 changes: 0 additions & 4 deletions Sources/Core/AWSClientRuntime/HTTP/HttpResponse+AWS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
import ClientRuntime

public extension HttpResponse {
/// Returns true if the status code is `HttpStatusCode.notFound` and the body is empty.
var statusCodeIsNotFoundAndBodyIsEmpty: Bool {
return statusCode == .notFound && body.isEmpty
}

/// The value of the x-amz-request-id header.
var requestId: String? {
Expand Down
35 changes: 35 additions & 0 deletions Sources/Core/AWSClientRuntime/Protocols/AWSJSON/AWSJSONError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import protocol ClientRuntime.BaseError
import enum ClientRuntime.BaseErrorDecodeError
import class ClientRuntime.HttpResponse
import class SmithyJSON.Reader

public struct AWSJSONError: BaseError {
public let code: String
public let message: String?
public let requestID: String?
public var errorBodyReader: Reader { responseReader }

public let httpResponse: HttpResponse
private let responseReader: Reader

public init(httpResponse: HttpResponse, responseReader: Reader, noErrorWrapping: Bool) throws {
let code: String? = try httpResponse.headers.value(for: "X-Amzn-Errortype")
?? responseReader["code"].readIfPresent()
?? responseReader["__type"].readIfPresent()
let message: String? = try responseReader["Message"].readIfPresent()
let requestID: String? = try responseReader["RequestId"].readIfPresent()
guard let code else { throw BaseErrorDecodeError.missingRequiredData }
self.code = sanitizeErrorType(code)
self.message = message
self.requestID = requestID
self.httpResponse = httpResponse
self.responseReader = responseReader
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import protocol ClientRuntime.BaseError
import enum ClientRuntime.BaseErrorDecodeError
import class ClientRuntime.HttpResponse
import class SmithyXML.Reader

public struct AWSQueryError: BaseError {
public let code: String
public let message: String?
public let requestID: String?
public let httpResponse: HttpResponse
public let responseReader: Reader
public let errorBodyReader: Reader

public init(httpResponse: HttpResponse, responseReader: Reader, noErrorWrapping: Bool) throws {
self.errorBodyReader = noErrorWrapping ? responseReader : responseReader["Error"]
let code: String? = try errorBodyReader["Code"].readIfPresent()
let message: String? = try errorBodyReader["Message"].readIfPresent()
let requestID: String? = try responseReader["RequestId"].readIfPresent()
guard let code else { throw BaseErrorDecodeError.missingRequiredData }
self.code = code
self.message = message
self.requestID = requestID
self.httpResponse = httpResponse
self.responseReader = responseReader
}
}

public enum AWSQueryDecodeError: Error {
case missingRequiredData
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import protocol ClientRuntime.BaseError
import enum ClientRuntime.BaseErrorDecodeError
import class ClientRuntime.HttpResponse
import class SmithyXML.Reader

public struct EC2QueryError: BaseError {
public let code: String
public let message: String?
public let requestID: String?
public let errorBodyReader: Reader

public let httpResponse: HttpResponse
public let responseReader: Reader

public init(httpResponse: HttpResponse, responseReader: Reader, noErrorWrapping: Bool) throws {
self.httpResponse = httpResponse
self.responseReader = responseReader
self.errorBodyReader = responseReader["Errors"]["Error"]
let code: String? = try errorBodyReader["Code"].readIfPresent()
guard let code else { throw BaseErrorDecodeError.missingRequiredData }
let message: String? = try errorBodyReader["Message"].readIfPresent()
let requestID: String? = try responseReader["RequestId"].readIfPresent()
?? responseReader["RequestID"].readIfPresent()
self.code = code
self.message = message
self.requestID = requestID
}
}
23 changes: 0 additions & 23 deletions Sources/Core/AWSClientRuntime/Protocols/Ec2Query/Ec2Error.swift

This file was deleted.

21 changes: 0 additions & 21 deletions Sources/Core/AWSClientRuntime/Protocols/Ec2Query/Ec2Errors.swift

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 61031ff

Please sign in to comment.