Skip to content

Commit

Permalink
Add support for output CustomCoding values in headers and querys (#417)
Browse files Browse the repository at this point in the history
* Add support for output CustomCoding values in headers and querys

CustomEncoder protocol has new `string(from: CodableValue)` function. If you implement this then the wrapped value will be returned. Otherwise nothing will be output

* Extended testing
  • Loading branch information
adam-fowler authored Dec 28, 2020
1 parent 386d872 commit b6cb204
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ public protocol CustomCoder {

/// Protocol for object that will encode a value
public protocol CustomEncoder: CustomCoder {
/// encode CodableValue with supplied encoder
static func encode(value: CodableValue, to encoder: Encoder) throws
/// return value as a String. Used by query string and header values
static func string(from: CodableValue) -> String?
}

extension CustomEncoder {
public static func string(from: CodableValue) -> String? { return nil }
}

/// Protocol for object that will decode a value
Expand Down
4 changes: 4 additions & 0 deletions Sources/SotoCore/Encoder/CodableProperties/DateCoders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ extension DateFormatCoder {
try container.encode(dateFormatters[0].string(from: value))
}

public static func string(from value: Date) -> String? {
dateFormatters[0].string(from: value)
}

/// create DateFormatter
static func createDateFormatters() -> [DateFormatter] {
var dateFormatters: [DateFormatter] = []
Expand Down
21 changes: 21 additions & 0 deletions Sources/SotoCore/Message/AWSRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ extension AWSRequest {
switch encoding.location {
case .header(let location):
switch value {
case let string as AWSRequestEncodableString:
string.encoded.map { headers.replaceOrAdd(name: location, value: $0) }
case let dictionary as AWSRequestEncodableDictionary:
dictionary.encoded.forEach { headers.replaceOrAdd(name: "\(location)\($0.key)", value: $0.value) }
default:
Expand All @@ -153,6 +155,8 @@ extension AWSRequest {

case .querystring(let location):
switch value {
case let string as AWSRequestEncodableString:
string.encoded.map { queryParams.append((key: location, value: $0)) }
case let array as AWSRequestEncodableArray:
array.encoded.forEach { queryParams.append((key: location, value: $0)) }
case let dictionary as AWSRequestEncodableDictionary:
Expand Down Expand Up @@ -339,3 +343,20 @@ extension Dictionary: AWSRequestEncodableDictionary {
return self.map { (key: "\($0.key)", value: "\($0.value)") }
}
}

private protocol AWSRequestEncodableString {
var encoded: String? { get }
}

extension CustomCoding: AWSRequestEncodableString where Coder: CustomEncoder {
var encoded: String? {
return Coder.string(from: self.wrappedValue)
}
}

extension OptionalCustomCoding: AWSRequestEncodableString where Coder: CustomEncoder {
var encoded: String? {
guard let value = self.wrappedValue else { return nil }
return Coder.string(from: value)
}
}
18 changes: 18 additions & 0 deletions Tests/SotoCoreTests/AWSRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,22 @@ class AWSRequestTests: XCTestCase {
XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config))
XCTAssertEqual(request?.url, URL(string: "https://test.com/?item=apple&item=orange")!)
}

func testCustomEncoderInQuery() {
struct Input: AWSEncodableShape {
static let _encoding: [AWSMemberEncoding] = [
.init(label: "_date", location: .querystring(locationName: "date")),
.init(label: "_values", location: .querystring(locationName: "values")),
]
@OptionalCustomCoding<HTTPHeaderDateCoder>
var date: Date?
@CustomCoding<StandardArrayCoder>
var values: [Int]
}
let input = Input(date: Date(timeIntervalSince1970: 10_000_000), values: [1])
let config = createServiceConfig(endpoint: "https://test.com")
var request: AWSRequest?
XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config))
XCTAssertEqual(request?.url, URL(string: "https://test.com/?date=Sun%2C%2026%20Apr%201970%2017%3A46%3A40%20GMT")!)
}
}

0 comments on commit b6cb204

Please sign in to comment.