Skip to content

Commit 6ea5825

Browse files
committed
Supports base64-encoded data
Motivation OpenAPI supports base64-encoded data but to this point OpenAPI Generator has not (apple/swift-openapi-generator#11). Modifications Introduce the `Base64EncodedData` codable type to allow users in the generator to describe byte types which must be en/de-coded. Result Users will be able to describe base64-encoded data as `OpenAPIRuntime.Base64EncodedData` e.g. ``` public typealias MyData = OpenAPIRuntime.Base64EncodedData ``` Test Plan Added a round-trip encode/decode test `testEncodingDecodingRoundTrip_base64_success`
1 parent d873514 commit 6ea5825

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftOpenAPIGenerator open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
17+
public struct Base64EncodedData: Sendable, Codable, Hashable {
18+
var data: Foundation.Data // or [UInt8] or ArraySlice<UInt8>
19+
20+
public init(data: Foundation.Data) {
21+
self.data = data
22+
}
23+
24+
public init(from decoder: any Decoder) throws {
25+
let container = try decoder.singleValueContainer()
26+
let base64EncodedString = try container.decode(String.self)
27+
guard let data = Data(base64Encoded: base64EncodedString) else {
28+
throw RuntimeError.invalidBase64String(base64EncodedString)
29+
}
30+
self.init(data: data)
31+
}
32+
33+
public func encode(to encoder: any Encoder) throws {
34+
var container = encoder.singleValueContainer()
35+
let base64String = data.base64EncodedString()
36+
try container.encode(base64String)
37+
}
38+
}

Sources/OpenAPIRuntime/Errors/RuntimeError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, Pret
2121
case invalidServerURL(String)
2222
case invalidExpectedContentType(String)
2323
case invalidHeaderFieldName(String)
24+
case invalidBase64String(String)
2425

2526
// Data conversion
2627
case failedToDecodeStringConvertibleValue(type: String)
@@ -73,6 +74,8 @@ internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, Pret
7374
return "Invalid expected content type: '\(string)'"
7475
case .invalidHeaderFieldName(let name):
7576
return "Invalid header field name: '\(name)'"
77+
case .invalidBase64String(let string):
78+
return "Invalid base64-encoded string: '\(string)'"
7679
case .failedToDecodeStringConvertibleValue(let string):
7780
return "Failed to decode a value of type '\(string)'."
7881
case .unsupportedParameterStyle(name: let name, location: let location, style: let style, explode: let explode):

Tests/OpenAPIRuntimeTests/Base/Test_OpenAPIValue.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414
import XCTest
15-
@_spi(Generated) import OpenAPIRuntime
15+
@_spi(Generated) @testable import OpenAPIRuntime
1616

1717
final class Test_OpenAPIValue: Test_Runtime {
1818

@@ -266,4 +266,13 @@ final class Test_OpenAPIValue: Test_Runtime {
266266
let nestedValue = try XCTUnwrap(nestedDict["nested"] as? Int)
267267
XCTAssertEqual(nestedValue, 2)
268268
}
269+
270+
func testEncodingDecodingRoundTrip_base64_success() throws {
271+
print(String(data: testStructData.base64EncodedData(), encoding: .utf8)!.utf8)
272+
let encodedData = Base64EncodedData(data: testStructData)
273+
XCTAssertEqual(
274+
try JSONDecoder().decode(Base64EncodedData.self, from: JSONEncoder().encode(encodedData)),
275+
encodedData
276+
)
277+
}
269278
}

0 commit comments

Comments
 (0)