Skip to content

Commit

Permalink
Merge pull request #170 from mattpolzin/feature/131/server-var-valida…
Browse files Browse the repository at this point in the history
…tion

Add validation that all server template variables are defined.
  • Loading branch information
mattpolzin authored Dec 26, 2020
2 parents 4f788f2 + a4e3668 commit 7861ff0
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Sources/OpenAPIKit/Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ extension OpenAPI {
self.variables = variables
self.vendorExtensions = vendorExtensions
}

/// Create an OpenAPI Server Object with a URL containing
/// variables that can change depending on the context in
/// which the API is invoked,
public init(
urlTemplate: URLTemplate,
description: String? = nil,
variables: OrderedDictionary<String, Variable> = [:],
vendorExtensions: [String: AnyCodable] = [:]
) {
self.urlTemplate = urlTemplate
self.description = description
self.variables = variables
self.vendorExtensions = vendorExtensions
}
}
}

Expand Down
23 changes: 23 additions & 0 deletions Sources/OpenAPIKit/Validator/Validation+Builtins.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,29 @@ extension Validation {
)
}

/// Validate that all Server Objects define all of the variables found in their URL Templates.
///
/// For example, a server URL Template of `{scheme}://website.com/{path}` would
/// fail this validation if either "scheme" or "path" were not found in the Server Object's
/// `variables` dictionary.
///
/// - Important: This is not an included validation by default.
public static var serverVariablesAreDefined: Validation<OpenAPI.Server> {
.init(
check: { context in
let missingVariables = context.subject.urlTemplate.variables
.filter { !context.subject.variables.contains(key: $0) }

return missingVariables.map { variableName in
ValidationError(
reason: "Server Object does not define the variable '\(variableName)' that is found in the `urlTemplate` '\(context.subject.urlTemplate.rawValue)'",
at: context.codingPath
)
}
}
)
}

// MARK: - Included with `Validator()` by default

/// Validate the OpenAPI Document's `Operations` all have at least
Expand Down
76 changes: 76 additions & 0 deletions Tests/OpenAPIKitTests/Validator/BuiltinValidationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,82 @@ final class BuiltinValidationTests: XCTestCase {
try document.validate(using: validator)
}

func test_missingServerVariableFails() throws {
let document = OpenAPI.Document(
info: .init(title: "test", version: "1.0"),
servers: [
.init(urlTemplate: URLTemplate(rawValue: "https://website.com/{path}")!)
],
paths: [:],
components: .noComponents
)

let validator = Validator.blank.validating(.serverVariablesAreDefined)
XCTAssertThrowsError(try document.validate(using: validator)) { error in
XCTAssertEqual(
(error as? ValidationErrorCollection)?.values.map(String.init(describing:)),
[
"Server Object does not define the variable 'path' that is found in the `urlTemplate` 'https://website.com/{path}' at path: .servers[0]"
]
)
}
}

func test_partialMissingServerVariablesFails() throws {
let document = OpenAPI.Document(
info: .init(title: "test", version: "1.0"),
servers: [
.init(
urlTemplate: URLTemplate(rawValue: "{scheme}://website.com/{path}")!,
variables: ["scheme": .init(default: "scheme")]
)
],
paths: [:],
components: .noComponents
)

let validator = Validator.blank.validating(.serverVariablesAreDefined)
XCTAssertThrowsError(try document.validate(using: validator)) { error in
XCTAssertEqual(
(error as? ValidationErrorCollection)?.values.map(String.init(describing:)),
[
"Server Object does not define the variable 'path' that is found in the `urlTemplate` '{scheme}://website.com/{path}' at path: .servers[0]"
]
)
}
}

func test_noSevrerVariablesSucceeds() throws {
let document = OpenAPI.Document(
info: .init(title: "test", version: "1.0"),
servers: [
.init(urlTemplate: URLTemplate(rawValue: "https://website.com")!)
],
paths: [:],
components: .noComponents
)

let validator = Validator.blank.validating(.serverVariablesAreDefined)
try document.validate(using: validator)
}

func test_allServerVariablesDefinedSucceeds() throws {
let document = OpenAPI.Document(
info: .init(title: "test", version: "1.0"),
servers: [
.init(
urlTemplate: URLTemplate(rawValue: "https://website.com/{path}")!,
variables: ["path": .init(default: "welcome")]
)
],
paths: [:],
components: .noComponents
)

let validator = Validator.blank.validating(.serverVariablesAreDefined)
try document.validate(using: validator)
}

func test_duplicateTagOnDocumentFails() {
let document = OpenAPI.Document(
info: .init(title: "test", version: "1.0"),
Expand Down

0 comments on commit 7861ff0

Please sign in to comment.