From ad05d3908a0a405dfb7bc027205525367bb9b1e8 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 25 Jan 2019 12:49:59 -0800 Subject: [PATCH] Add a simple test OpenAPISchema and start to tweak things to get it workable. --- .../OpenAPI/OpenAPITypes+Codable.swift | 11 ++- .../JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift | 93 ++++++++++++++----- .../OpenAPI/OpenAPITests.swift | 52 +++++++++++ 3 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift diff --git a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift b/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift index d6357c7..53d2261 100644 --- a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift +++ b/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift @@ -203,7 +203,16 @@ extension JSONReference: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - try container.encode("#/\(Root.refName)/\(refName)/\(selector)") + let referenceString: String = { + switch self { + case .file(let reference): + return reference + case .node(let reference): + return "#/\(Root.refName)/\(reference.refName)/\(reference.selector)" + } + }() + + try container.encode(referenceString) } } diff --git a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift b/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift index c966a30..cf2327b 100644 --- a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift +++ b/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift @@ -645,28 +645,36 @@ public struct RefDict: Equatable { - public let path: PartialKeyPath - public let selector: String +public enum JSONReference: Equatable { - public var refName: String { - // we require RD be a RefName in the initializer - // so it is safe to force cast here. - return (type(of: path).valueType as! RefName.Type).refName - } + case node(InternalReference) + case file(FileReference) - public init(type: KeyPath, - selector: String) where RD.Value == RefType { - self.path = type - self.selector = selector + public typealias FileReference = String + + public struct InternalReference: Equatable { + public let path: PartialKeyPath + public let selector: String + + public var refName: String { + // we require RD be a RefName in the initializer + // so it is safe to force cast here. + return (type(of: path).valueType as! RefName.Type).refName + } + + public init(type: KeyPath, + selector: String) where RD.Value == RefType { + self.path = type + self.selector = selector + } } } /// An OpenAPI Path Item /// This type describes the endpoints a server has /// bound to a particular path. -public enum JSONPathItem: Equatable { - case reference(JSONReference) +public enum OpenAPIPathItem: Equatable { + case reference(JSONReference) case operations(PathProperties) public struct PathProperties: Equatable { @@ -752,13 +760,29 @@ public enum JSONPathItem: Equatable { public let operationId: String public let parameters: ParameterArray // public let requestBody: - public let responses: ResponseArray + public let responses: ResponseMap // public let callbacks: public let deprecated: Bool // default is false // public let security: // public let servers: - public typealias ResponseArray = [OpenAPIResponse.Code: Either>] + public init(tags: [String]? = nil, + summary: String? = nil, + description: String? = nil, + operationId: String, + parameters: ParameterArray, + responses: ResponseMap, + deprecated: Bool = false) { + self.tags = tags + self.summary = summary + self.description = description + self.operationId = operationId + self.parameters = parameters + self.responses = responses + self.deprecated = deprecated + } + + public typealias ResponseMap = [OpenAPIResponse.Code: Either>] } } } @@ -769,18 +793,32 @@ public struct OpenAPIResponse: Equatable { public let content: ContentMap // public let links: - public typealias ContentMap = [String: Content] + public init(description: String, + content: ContentMap) { + self.description = description + self.content = content + } + + public typealias ContentMap = [ContentType: Content] public enum Code: Equatable, Hashable { case `default` case status(code: Int) } + public enum ContentType: String, Equatable, Hashable { + case json = "application/json" + } + public struct Content: Equatable { public let schema: Either> // public let example: // public let examples: // public let encoding: + + public init(schema: Either>) { + self.schema = schema + } } } @@ -816,7 +854,7 @@ public struct OpenAPIComponents: Equatable, Encodable, ReferenceRoot { public static var refName: String { return "parameters" } } - public typealias ParametersDict = RefDict + public typealias ParametersDict = RefDict } /// The root of an OpenAPI 3.0 document. @@ -824,13 +862,14 @@ public struct OpenAPISchema: Encodable { private enum CodingKeys: String, CodingKey { case openAPIVersion = "openapi" case info + case paths case components } public let openAPIVersion: Version public let info: Info // public let servers: - public let paths: [PathComponents: JSONPathItem] + public let paths: [PathComponents: OpenAPIPathItem] public let components: OpenAPIComponents // public let security: // public let tags: @@ -838,7 +877,7 @@ public struct OpenAPISchema: Encodable { public init(openAPIVersion: Version = .v3_0_0, info: Info, - paths: [PathComponents: JSONPathItem], + paths: [PathComponents: OpenAPIPathItem], components: OpenAPIComponents) { self.openAPIVersion = openAPIVersion self.info = info @@ -869,5 +908,17 @@ public struct OpenAPISchema: Encodable { } } - public typealias PathComponents = [String] + public struct PathComponents: Encodable, Equatable, Hashable { + public let components: [String] + + public init(_ components: [String]) { + self.components = components + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + try container.encode(components.joined(separator: "/")) + } + } } diff --git a/Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift b/Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift new file mode 100644 index 0000000..7410aa1 --- /dev/null +++ b/Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift @@ -0,0 +1,52 @@ +// +// OpenAPITests.swift +// JSONAPIOpenAPITests +// +// Created by Mathew Polzin on 1/25/19. +// + +import XCTest +import JSONAPI +import JSONAPIOpenAPI + +class OpenAPITests: XCTestCase { + + func test_placeholder() { + + let schemaInfo = OpenAPISchema.Info(title: "Cool API", version: "0.1.0") + + let personResponse = OpenAPIResponse(description: "Successfully created a Person", + content: [ + .json: .init(schema: .init(JSONReference.node(.init(type: \.schemas, selector: "person")))) + ]) + + let schemaPaths: [OpenAPISchema.PathComponents: OpenAPIPathItem] = [ + .init(["api","people"]): + .operations( + .init(parameters: [], + post: OpenAPIPathItem.PathProperties.Operation( + summary: "", + operationId: "createPerson", + parameters: [], + responses: [ + .status(code: 200): .init(personResponse) + ] + ) + ) + ) + ] + + let schemaComponents = OpenAPIComponents(schemas: ["person": .reference(.file("filename"))], + parameters: [:]) + + let openAPISchema = OpenAPISchema(info: schemaInfo, + paths: schemaPaths, + components: schemaComponents) + + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + + print(String(data: try! encoder.encode(openAPISchema), encoding: .utf8)!) + } + +}