Skip to content

Commit

Permalink
use Encoder and Decoder userInfo to configure VendorExtension support…
Browse files Browse the repository at this point in the history
… for OpenAPIKit moudle
  • Loading branch information
mattpolzin committed Nov 1, 2024
1 parent 97d026e commit 6641ac3
Show file tree
Hide file tree
Showing 21 changed files with 88 additions and 36 deletions.
20 changes: 15 additions & 5 deletions Sources/OpenAPIKit/CodableVendorExtendable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,21 @@ public protocol VendorExtendable {
var vendorExtensions: VendorExtensions { get set }
}

/// OpenAPIKit supports some additional Encoder/Decoder configuration above and beyond
/// what the Encoder or Decoder support out of box.
///
/// To _disable_ encoding or decoding of Vendor Extensions (by default these are _enabled),
/// set `userInfo[VendorExtensionsConfiguration.enabledKey] = false` for your encoder or decoder.
public enum VendorExtensionsConfiguration {
public static var isEnabled = true
public static let enabledKey: CodingUserInfoKey = .init(rawValue: "vendor-extensions-enabled")!

static func isEnabled(for decoder: Decoder) -> Bool {
decoder.userInfo[enabledKey] as? Bool ?? true
}

static func isEnabled(for encoder: Encoder) -> Bool {
encoder.userInfo[enabledKey] as? Bool ?? true
}
}

internal protocol ExtendableCodingKey: CodingKey, Equatable {
Expand Down Expand Up @@ -75,7 +88,7 @@ internal enum VendorExtensionDecodingError: Swift.Error, CustomStringConvertible
extension CodableVendorExtendable {

internal static func extensions(from decoder: Decoder) throws -> VendorExtensions {
guard VendorExtensionsConfiguration.isEnabled else {
guard VendorExtensionsConfiguration.isEnabled(for: decoder) else {
return [:]
}

Expand Down Expand Up @@ -109,9 +122,6 @@ extension CodableVendorExtendable {
}

internal func encodeExtensions<T: KeyedEncodingContainerProtocol>(to container: inout T) throws where T.Key == Self.CodingKeys {
guard VendorExtensionsConfiguration.isEnabled else {
return
}
for (key, value) in vendorExtensions {
let xKey = key.starts(with: "x-") ? key : "x-\(key)"
try container.encode(value, forKey: .extendedKey(for: xKey))
Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Components Object/Components.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ extension OpenAPI.Components: Encodable {
try container.encode(pathItems, forKey: .pathItems)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Content/Content.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ extension OpenAPI.Content: Encodable {

try container.encodeIfPresent(encoding, forKey: .encoding)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Document/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,9 @@ extension OpenAPI.Document: Encodable {
try container.encode(paths, forKey: .paths)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}

if !components.isEmpty {
try container.encode(components, forKey: .components)
Expand Down
12 changes: 9 additions & 3 deletions Sources/OpenAPIKit/Document/DocumentInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ extension OpenAPI.Document.Info.License: Encodable {
}
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down Expand Up @@ -269,7 +271,9 @@ extension OpenAPI.Document.Info.Contact: Encodable {
try container.encodeIfPresent(url?.absoluteString, forKey: .url)
try container.encodeIfPresent(email, forKey: .email)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down Expand Up @@ -345,7 +349,9 @@ extension OpenAPI.Document.Info: Encodable {
try container.encodeIfPresent(license, forKey: .license)
try container.encode(version, forKey: .version)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Example.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ extension OpenAPI.Example: Encodable {
break
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/ExternalDocumentation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ extension OpenAPI.ExternalDocumentation: Encodable {
try container.encodeIfPresent(description, forKey: .description)
try container.encode(url.absoluteString, forKey: .url)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Header/Header.swift
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,9 @@ extension OpenAPI.Header: Encodable {
try container.encode(deprecated, forKey: .deprecated)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Link.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ extension OpenAPI.Link: Encodable {
try container.encodeIfPresent(description, forKey: .description)
try container.encodeIfPresent(server, forKey: .server)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Operation/Operation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,9 @@ extension OpenAPI.Operation: Encodable {

try container.encodeIfPresent(servers, forKey: .servers)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Parameter/Parameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ extension OpenAPI.Parameter: Encodable {
try container.encode(deprecated, forKey: .deprecated)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Path Item/PathItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ extension OpenAPI.PathItem: Encodable {
try container.encodeIfPresent(patch, forKey: .patch)
try container.encodeIfPresent(trace, forKey: .trace)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Request/Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ extension OpenAPI.Request: Encodable {
try container.encode(required, forKey: .required)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Response/Response.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ extension OpenAPI.Response: Encodable {
try container.encode(links, forKey: .links)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/OpenAPIKit/Schema Object/JSONSchema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1930,7 +1930,7 @@ extension JSONSchema: Encodable {

// Ad-hoc vendor extension encoding because keys are done differently for
// JSONSchema
guard VendorExtensionsConfiguration.isEnabled else {
guard VendorExtensionsConfiguration.isEnabled(for: encoder) else {
return
}
var container = encoder.container(keyedBy: VendorExtensionKeys.self)
Expand Down Expand Up @@ -2140,7 +2140,7 @@ extension JSONSchema: Decodable {
// Ad-hoc vendor extension support since JSONSchema does coding keys differently.
let extensions: [String: AnyCodable]

guard VendorExtensionsConfiguration.isEnabled else {
guard VendorExtensionsConfiguration.isEnabled(for: decoder) else {
self.value = value
return
}
Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Security/SecurityScheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ extension OpenAPI.SecurityScheme: Encodable {
try container.encode(SecurityType.Name.mutualTLS, forKey: .type)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions Sources/OpenAPIKit/Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ extension OpenAPI.Server: Encodable {
try container.encode(variables, forKey: .variables)
}

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down Expand Up @@ -194,7 +196,9 @@ extension OpenAPI.Server.Variable: Encodable {

try container.encodeIfPresent(description, forKey: .description)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/OpenAPIKit/Tag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ extension OpenAPI.Tag: Encodable {

try container.encodeIfPresent(externalDocs, forKey: .externalDocs)

try encodeExtensions(to: &container)
if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

Expand Down
8 changes: 3 additions & 5 deletions Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1741,14 +1741,12 @@ extension SchemaObjectTests {
}
""".data(using: .utf8)!

VendorExtensionsConfiguration.isEnabled = false
let config = [VendorExtensionsConfiguration.enabledKey: false]

let vendorExtended = try orderUnstableDecode(JSONSchema.self, from: vendorExtendedData)
let nonVendorExtended = try orderUnstableDecode(JSONSchema.self, from: nonVendorExtendedData)
let vendorExtended = try orderUnstableDecode(JSONSchema.self, from: vendorExtendedData, userInfo: config)
let nonVendorExtended = try orderUnstableDecode(JSONSchema.self, from: nonVendorExtendedData, userInfo: config)

XCTAssertEqual(vendorExtended, nonVendorExtended)

VendorExtensionsConfiguration.isEnabled = true
}

func test_decodingWarnsForTypeAndPropertyConflict() throws {
Expand Down
11 changes: 7 additions & 4 deletions Tests/OpenAPIKitTests/TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ func orderStableYAMLEncode<T: Encodable>(_ value: T) throws -> String {
return try yamsTestEncoder.encode(value)
}

fileprivate let foundationTestDecoder = { () -> JSONDecoder in
fileprivate func buildFoundationTestDecoder(_ userInfo: [CodingUserInfoKey: Any] = [:]) -> JSONDecoder {
let decoder = JSONDecoder()
decoder.userInfo = userInfo
if #available(macOS 10.12, *) {
decoder.dateDecodingStrategy = .iso8601
decoder.keyDecodingStrategy = .useDefaultKeys
Expand All @@ -51,10 +52,12 @@ fileprivate let foundationTestDecoder = { () -> JSONDecoder in
decoder.keyDecodingStrategy = .useDefaultKeys
#endif
return decoder
}()
}

fileprivate let foundationTestDecoder = { () -> JSONDecoder in buildFoundationTestDecoder() }()

func orderUnstableDecode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
return try foundationTestDecoder.decode(T.self, from: data)
func orderUnstableDecode<T: Decodable>(_ type: T.Type, from data: Data, userInfo : [CodingUserInfoKey: Any] = [:]) throws -> T {
return try buildFoundationTestDecoder(userInfo).decode(T.self, from: data)
}

fileprivate let yamsTestDecoder = { () -> YAMLDecoder in
Expand Down
5 changes: 4 additions & 1 deletion Tests/OpenAPIKitTests/VendorExtendableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ private struct TestStruct: Codable, CodableVendorExtendable {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode("world", forKey: .one)
try container.encode("!", forKey: .two)
try encodeExtensions(to: &container)

if VendorExtensionsConfiguration.isEnabled(for: encoder) {
try encodeExtensions(to: &container)
}
}
}

0 comments on commit 6641ac3

Please sign in to comment.