Skip to content

Commit 0de056a

Browse files
committed
Add new default-on builtin validation that all callbacks references can befound in the components object
1 parent 1b6ab9d commit 0de056a

File tree

4 files changed

+40
-3
lines changed

4 files changed

+40
-3
lines changed

Sources/OpenAPIKit/Validator/Validation+Builtins.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,28 @@ extension Validation {
408408
)
409409
}
410410

411+
/// Validate that all non-external Callbacks references are found in the document's
412+
/// components dictionary.
413+
///
414+
/// - Important: This is included in validation by default.
415+
///
416+
public static var callbacksReferencesAreValid: Validation<OpenAPI.Reference<OpenAPI.Callbacks>> {
417+
.init(
418+
description: "Callbacks reference can be found in components/callbacks",
419+
check: { context in
420+
guard case let .internal(internalReference) = context.subject.jsonReference,
421+
case .component = internalReference else {
422+
// don't make assertions about external references
423+
// TODO: could make a stronger assertion including
424+
// internal references outside of components given
425+
// some way to resolve those references.
426+
return true
427+
}
428+
return context.document.components.contains(internalReference)
429+
}
430+
)
431+
}
432+
411433
/// Validate that all non-external PathItem references are found in the document's
412434
/// components dictionary.
413435
///

Sources/OpenAPIKit/Validator/Validator.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ public final class Validator {
190190
.init(.requestReferencesAreValid),
191191
.init(.headerReferencesAreValid),
192192
.init(.linkReferencesAreValid),
193+
.init(.callbacksReferencesAreValid),
193194
.init(.pathItemReferencesAreValid),
194195
.init(.serverVariableEnumIsValid),
195196
.init(.serverVariableDefaultExistsInEnum)

Tests/OpenAPIKitCompatTests/DocumentConversionTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ final class DocumentConversionTests: XCTestCase {
202202
components: .init(
203203
parameters: [
204204
"test": .init(name: "referencedParam", context: .query, schema: .string)
205+
],
206+
callbacks: [
207+
"other_callback": callbacks
205208
]
206209
)
207210
)

Tests/OpenAPIKitTests/Validator/BuiltinValidationTests.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,9 @@ final class BuiltinValidationTests: XCTestCase {
741741
],
742742
links: ["linky": .reference(.component(named: "link1"))]
743743
)
744+
],
745+
callbacks: [
746+
"callbacks1": .reference(.component(named: "callbacks1"))
744747
]
745748
)
746749
)
@@ -758,7 +761,7 @@ final class BuiltinValidationTests: XCTestCase {
758761
// NOTE these are part of default validation
759762
XCTAssertThrowsError(try document.validate()) { error in
760763
let error = error as? ValidationErrorCollection
761-
XCTAssertEqual(error?.values.count, 8)
764+
XCTAssertEqual(error?.values.count, 9)
762765
XCTAssertEqual(error?.values[0].reason, "Failed to satisfy: Parameter reference can be found in components/parameters")
763766
XCTAssertEqual(error?.values[0].codingPathString, ".paths['/hello'].get.parameters[0]")
764767
XCTAssertEqual(error?.values[1].reason, "Failed to satisfy: Request reference can be found in components/requestBodies")
@@ -773,8 +776,10 @@ final class BuiltinValidationTests: XCTestCase {
773776
XCTAssertEqual(error?.values[5].codingPathString, ".paths['/hello'].get.responses.404.content['application/xml'].schema")
774777
XCTAssertEqual(error?.values[6].reason, "Failed to satisfy: Link reference can be found in components/links")
775778
XCTAssertEqual(error?.values[6].codingPathString, ".paths['/hello'].get.responses.404.links.linky")
776-
XCTAssertEqual(error?.values[7].reason, "Failed to satisfy: PathItem reference can be found in components/pathItems")
777-
XCTAssertEqual(error?.values[7].codingPathString, ".paths['/world']")
779+
XCTAssertEqual(error?.values[7].reason, "Failed to satisfy: Callbacks reference can be found in components/callbacks")
780+
XCTAssertEqual(error?.values[7].codingPathString, ".paths['/hello'].get.callbacks.callbacks1")
781+
XCTAssertEqual(error?.values[8].reason, "Failed to satisfy: PathItem reference can be found in components/pathItems")
782+
XCTAssertEqual(error?.values[8].codingPathString, ".paths['/world']")
778783
}
779784
}
780785

@@ -817,6 +822,9 @@ final class BuiltinValidationTests: XCTestCase {
817822
"linky2": .reference(.external(URL(string: "https://linky.com")!))
818823
]
819824
)
825+
],
826+
callbacks: [
827+
"callbacks1": .reference(.component(named: "callbacks1"))
820828
]
821829
)
822830
)
@@ -851,6 +859,9 @@ final class BuiltinValidationTests: XCTestCase {
851859
links: [
852860
"link1": .init(operationId: "op 1")
853861
],
862+
callbacks: [
863+
"callbacks1": .init()
864+
],
854865
pathItems: [
855866
"path1": .init()
856867
]

0 commit comments

Comments
 (0)