diff --git a/Sources/ExternalDocumentation.swift b/Sources/ExternalDocumentation.swift index 841375e..885e21a 100644 --- a/Sources/ExternalDocumentation.swift +++ b/Sources/ExternalDocumentation.swift @@ -1,9 +1,30 @@ -// -// ExternalDocumentation.swift -// SwaggerParser -// -// Created by Logan Shire on 7/12/17. -// -// - import Foundation +import ObjectMapper + +/// Allows referencing an external resource for extended documentation. +public struct ExternalDocumentation { + + /// The URL for the target documentation. + let url: URL + + /// A short description of the target documentation. + /// GFM syntax can be used for rich text representation. + let description: String? +} + +struct ExternalDocumentationBuilder: Builder { + + typealias Building = ExternalDocumentation + + let url: URL + let description: String? + + init(map: Map) throws { + url = try map.value("url", using: URLTransform()) + description = try? map.value("description") + } + + func build(_ swagger: SwaggerBuilder) throws -> ExternalDocumentation { + return ExternalDocumentation(url: self.url, description: self.description) + } +} diff --git a/Sources/Operation.swift b/Sources/Operation.swift index 0dd3589..064b543 100644 --- a/Sources/Operation.swift +++ b/Sources/Operation.swift @@ -2,6 +2,10 @@ import ObjectMapper public struct Operation { + /// A list of tags for API documentation control. + /// Tags can be used for logical grouping of operations by resources or any other qualifier. + public let tags: [String] + /// A short summary of what the operation does. This field SHOULD be less than 120 characters. public let summary: String? @@ -32,9 +36,6 @@ public struct Operation { /// A unique string used to identify the operation public let identifier: String? - /// A list of tags used to group operations together - public let tags: [String] - /// A list of which security schemes are applied to this operation. /// The list of values describes alternative security schemes that can be used /// (that is, there is a logical OR between the security requirements). @@ -59,12 +60,12 @@ struct OperationBuilder: Builder { let security: [SecurityRequirement]? init(map: Map) throws { + tags = (try? map.value("tags")) ?? [] summary = try? map.value("summary") description = try? map.value("description") externalDocumentationBuilder = try? map.value("externalDocs") parameters = (try? map.value("parameters")) ?? [] identifier = try? map.value("operationId") - tags = (try? map.value("tags")) ?? [] let allResponses: [String : Reference] = try map.value("responses") var mappedResponses = [Int : Reference]() @@ -91,6 +92,7 @@ struct OperationBuilder: Builder { .map { try ResponseBuilder.resolve(swagger, reference: $0) } return Operation( + tags: self.tags, summary: self.summary, description: self.description, externalDocumentation: externalDocumentation, @@ -99,7 +101,6 @@ struct OperationBuilder: Builder { defaultResponse: defaultResponse, deprecated: self.deprecated, identifier: self.identifier, - tags: self.tags, security: self.security) } } diff --git a/Sources/Swagger.swift b/Sources/Swagger.swift index 9af9379..e0ceebd 100644 --- a/Sources/Swagger.swift +++ b/Sources/Swagger.swift @@ -59,6 +59,13 @@ public struct Swagger { /// Individual operations can override this definition. public let security: [SecurityRequirement] + /// A list of tags used by the specification with additional metadata. + /// The order of the tags can be used to reflect on their order by the parsing tools. + /// Not all tags that are used by the Operation must be declared. + /// The tags that are not declared may be organized randomly or based on the tools' logic. + /// Each tag name in the list MUST be unique. + public let tags: [Tag] + /// Additional external documentation. public let externalDocumentation: ExternalDocumentation? } @@ -93,6 +100,7 @@ struct SwaggerBuilder: Builder { let responses: [String : ResponseBuilder] let securityDefinitions: [String : SecuritySchemaBuilder] let security: [SecurityRequirement] + let tagBuilders: [TagBuilder] let externalDocumentationBuilder: ExternalDocumentationBuilder? init(map: Map) throws { @@ -128,6 +136,7 @@ struct SwaggerBuilder: Builder { responses = (try? map.value("responses")) ?? [:] securityDefinitions = (try? map.value("securityDefinitions")) ?? [:] security = (try? map.value("security")) ?? [] + tagBuilders = (try? map.value("tags")) ?? [] externalDocumentationBuilder = try? map.value("externalDocs") } @@ -153,12 +162,14 @@ struct SwaggerBuilder: Builder { ParameterBuilder.resolver.teardown() ResponseBuilder.resolver.teardown() + let tags = try self.tagBuilders.map { try $0.build(swagger) } + let externalDocumentation = try self.externalDocumentationBuilder?.build(swagger) return Swagger(version: self.version, information: try self.information.build(swagger), host: self.host, basePath: self.basePath, schemes: self.schemes, consumes: self.consumes, produces: self.produces, paths: paths, definitions: definitions, parameters: parameters, responses: responses, securityDefinitions: securityDefinitions, security: self.security, - externalDocumentation: try self.externalDocumentationBuilder?.build(swagger)) + tags: tags, externalDocumentation: externalDocumentation) } } diff --git a/Sources/Tag.swift b/Sources/Tag.swift new file mode 100644 index 0000000..ced0b41 --- /dev/null +++ b/Sources/Tag.swift @@ -0,0 +1,36 @@ +import ObjectMapper + +/// Allows adding meta data to a single tag that is used by the Operation. +/// It is not mandatory to have a Tag per tag used there. +public struct Tag { + + /// The name of the tag. + let name: String + + /// A short description for the tag. + /// GFM syntax can be used for rich text representation. + let description: String? + + /// Additional external documentation for this tag. + let externalDocumentation: ExternalDocumentation? +} + +struct TagBuilder: Builder { + + typealias Building = Tag + + let name: String + let description: String? + let externalDocumentationBuilder: ExternalDocumentationBuilder? + + init(map: Map) throws { + name = try map.value("name") + description = try? map.value("description") + externalDocumentationBuilder = try? map.value("externalDocs") + } + + func build(_ swagger: SwaggerBuilder) throws -> Tag { + return Tag(name: self.name, description: self.description, + externalDocumentation: try self.externalDocumentationBuilder?.build(swagger)) + } +}