Skip to content

Commit

Permalink
Merge pull request #311 from mattpolzin/bugfix/293/dereference-links
Browse files Browse the repository at this point in the history
Dereference Links
  • Loading branch information
mattpolzin authored Sep 6, 2023
2 parents 5a6989a + a1d782c commit bc9a711
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 0 deletions.
25 changes: 25 additions & 0 deletions Sources/OpenAPIKit/Link.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,29 @@ extension OpenAPI.Link {
}
}

// MARK: - LocallyDereferenceable
extension OpenAPI.Link: LocallyDereferenceable {
/// Links do not contain any references but for convenience
/// they can be "dereferenced" to themselves.
public func _dereferenced(
in components: OpenAPI.Components,
following references: Set<AnyHashable>,
dereferencedFromComponentNamed name: String?
) throws -> OpenAPI.Link {
var vendorExtensions = self.vendorExtensions
if let name = name {
vendorExtensions[OpenAPI.Components.componentNameExtension] = .init(name)
}

return .init(
operation: operation,
parameters: parameters,
requestBody: requestBody,
description: description,
server: server,
vendorExtensions: vendorExtensions
)
}
}

extension OpenAPI.Link: Validatable {}
6 changes: 6 additions & 0 deletions Sources/OpenAPIKit/Response/DereferencedResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public struct DereferencedResponse: Equatable {
public let headers: DereferencedHeader.Map?
/// The map of dereferenced content for this response.
public let content: DereferencedContent.Map
/// The map of dereferenced links for this response.
public let links: OrderedDictionary<String, OpenAPI.Link>

public subscript<T>(dynamicMember path: KeyPath<OpenAPI.Response, T>) -> T {
return underlyingResponse[keyPath: path]
Expand All @@ -44,6 +46,10 @@ public struct DereferencedResponse: Equatable {
try content._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil)
}

self.links = try response.links.mapValues { link in
try link._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil)
}

var response = response
if let name = name {
response.vendorExtensions[OpenAPI.Components.componentNameExtension] = .init(name)
Expand Down
25 changes: 25 additions & 0 deletions Sources/OpenAPIKit30/Link.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,29 @@ extension OpenAPI.Link {
}
}

// MARK: - LocallyDereferenceable
extension OpenAPI.Link: LocallyDereferenceable {
/// Links do not contain any references but for convenience
/// they can be "dereferenced" to themselves.
public func _dereferenced(
in components: OpenAPI.Components,
following references: Set<AnyHashable>,
dereferencedFromComponentNamed name: String?
) throws -> OpenAPI.Link {
var vendorExtensions = self.vendorExtensions
if let name = name {
vendorExtensions[OpenAPI.Components.componentNameExtension] = .init(name)
}

return .init(
operation: operation,
parameters: parameters,
requestBody: requestBody,
description: description,
server: server,
vendorExtensions: vendorExtensions
)
}
}

extension OpenAPI.Link: Validatable {}
6 changes: 6 additions & 0 deletions Sources/OpenAPIKit30/Response/DereferencedResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public struct DereferencedResponse: Equatable {
public let headers: DereferencedHeader.Map?
/// The map of dereferenced content for this response.
public let content: DereferencedContent.Map
/// The map of dereferenced links for this response.
public let links: OrderedDictionary<String, OpenAPI.Link>

public subscript<T>(dynamicMember path: KeyPath<OpenAPI.Response, T>) -> T {
return underlyingResponse[keyPath: path]
Expand All @@ -44,6 +46,10 @@ public struct DereferencedResponse: Equatable {
try content._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil)
}

self.links = try response.links.mapValues { link in
try link._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil)
}

var response = response
if let name = name {
response.vendorExtensions[OpenAPI.Components.componentNameExtension] = .init(name)
Expand Down
19 changes: 19 additions & 0 deletions Tests/OpenAPIKit30Tests/Response/DereferencedResponseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ final class DereferencedResponseTests: XCTestCase {
],
content: [
.json: .init(schema: .string)
],
links: [
"Link": .link(operationId: "link1")
]
).dereferenced(in: .noComponents)
XCTAssertEqual(t1.headers?["Header"]?.underlyingHeader, .init(schema: .string))
XCTAssertEqual(t1.content[.json]?.underlyingContent, .init(schema: .string))
XCTAssertEqual(t1.links["Link"], .init(operationId: "link1"))
}

func test_referencedHeader() throws {
Expand Down Expand Up @@ -85,4 +89,19 @@ final class DereferencedResponseTests: XCTestCase {
).dereferenced(in: .noComponents)
)
}

func test_referencedLink() throws {
let components = OpenAPI.Components(
links: [
"link1": .init(operationId: "linka")
]
)
let t1 = try OpenAPI.Response(
description: "test",
links: [
"link1": .reference(.component(named: "link1"))
]
).dereferenced(in: components)
XCTAssertEqual(t1.links["link1"], .init(operationId: "linka", vendorExtensions: ["x-component-name": "link1"]))
}
}
30 changes: 30 additions & 0 deletions Tests/OpenAPIKitTests/Response/DereferencedResponseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ final class DereferencedResponseTests: XCTestCase {
],
content: [
.json: .init(schema: .string)
],
links: [
"Link": .link(operationId: "link1")
]
).dereferenced(in: .noComponents)
XCTAssertEqual(t1.headers?["Header"]?.underlyingHeader, .init(schema: .string))
XCTAssertEqual(t1.content[.json]?.underlyingContent, .init(schema: .string))
XCTAssertEqual(t1.links["Link"], .init(operationId: "link1"))
}

func test_referencedHeader() throws {
Expand Down Expand Up @@ -85,4 +89,30 @@ final class DereferencedResponseTests: XCTestCase {
).dereferenced(in: .noComponents)
)
}

func test_referencedLink() throws {
let components = OpenAPI.Components(
links: [
"link1": .init(operationId: "linka")
]
)
let t1 = try OpenAPI.Response(
description: "test",
links: [
"link1": .reference(.component(named: "link1"))
]
).dereferenced(in: components)
XCTAssertEqual(t1.links["link1"], .init(operationId: "linka", vendorExtensions: ["x-component-name": "link1"]))
}

func test_referencedLinkMissing() {
XCTAssertThrowsError(
try OpenAPI.Response(
description: "test",
links: [
"link1": .reference(.component(named: "link1"))
]
).dereferenced(in: .noComponents)
)
}
}

0 comments on commit bc9a711

Please sign in to comment.