Skip to content

Commit eede562

Browse files
committed
adding new components
1 parent 18f2f29 commit eede562

File tree

7 files changed

+226
-31
lines changed

7 files changed

+226
-31
lines changed

README.md

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ This library *is* opinionated about a few defaults when you use the Swift types,
6060
- [x] parameters
6161
- [ ] examples
6262
- [ ] requestBodies
63-
- [ ] headers
63+
- [x] headers
6464
- [ ] securitySchemes
6565
- [ ] links
6666
- [ ] callbacks
@@ -132,23 +132,23 @@ This library *is* opinionated about a few defaults when you use the Swift types,
132132

133133
### Media Type Object (`OpenAPI.Content`)
134134
- [x] schema
135-
- [ ] example
135+
- [x] example
136136
- [ ] examples
137-
- [ ] encoding
137+
- [x] encoding
138138

139-
### Encoding Object
140-
- [ ] contentType
141-
- [ ] headers
139+
### Encoding Object (`OpenAPI.Content.Encoding`)
140+
- [x] contentType
141+
- [x] headers
142142
- [ ] style
143143
- [ ] explode
144-
- [ ] allowReserved
144+
- [x] allowReserved
145145

146146
### Responses Object (`OpenAPI.Response.Map`)
147147
- [x] *dictionary*
148148

149149
### Response Object (`OpenAPI.Response`)
150150
- [x] description
151-
- [ ] headers
151+
- [x] headers
152152
- [x] content
153153
- [ ] links
154154

@@ -170,12 +170,11 @@ This library *is* opinionated about a few defaults when you use the Swift types,
170170
- [ ] server
171171

172172
### Header Object
173-
- [ ] description
174-
- [ ] required
175-
- [ ] deprecated
176-
- [ ] allowEmptyValue
177-
- [ ] content
178-
- [ ] schema
173+
- [x] description
174+
- [x] required
175+
- [x] deprecated
176+
- [x] content
177+
- [x] schema
179178
- [ ] style
180179
- [ ] explode
181180
- [ ] allowReserved

Sources/OpenAPIKit/Components.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,23 @@ extension OpenAPI {
1919
public let parameters: ParametersDict
2020
// public let examples:
2121
// public let requestBodies:
22-
// public let headers:
23-
// public let headers:
22+
public let headers: HeadersDict
2423
// public let securitySchemas:
2524
// public let links:
2625
// public let callbacks:
2726

28-
public init(schemas: [String: SchemasDict.Value], parameters: [String: ParametersDict.Value]) {
27+
public init(schemas: [String: SchemasDict.Value],
28+
parameters: [String: ParametersDict.Value],
29+
headers: [String: HeadersDict.Value]) {
2930
self.schemas = SchemasDict(schemas)
3031
self.parameters = ParametersDict(parameters)
32+
self.headers = HeadersDict(headers)
3133
}
3234

3335
public static var noComponents: Components {
34-
return .init(schemas: [:], parameters: [:])
36+
return .init(schemas: [:],
37+
parameters: [:],
38+
headers: [:])
3539
}
3640

3741
public enum SchemasName: RefName {
@@ -45,5 +49,11 @@ extension OpenAPI {
4549
}
4650

4751
public typealias ParametersDict = RefDict<Components, ParametersName, PathItem.Parameter>
52+
53+
public enum HeadersName: RefName {
54+
public static var refName: String { return "headers" }
55+
}
56+
57+
public typealias HeadersDict = RefDict<Components, HeadersName, Header>
4858
}
4959
}

Sources/OpenAPIKit/Content.swift

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//
2-
// File.swift
3-
//
2+
// Content.swift
3+
// OpenAPIKit
44
//
55
// Created by Mathew Polzin on 7/4/19.
66
//
77

88
import Foundation
99
import Poly
10+
import AnyCodable
1011

1112
extension OpenAPI {
1213
public enum ContentType: String, Codable, Equatable, Hashable {
@@ -17,16 +18,38 @@ extension OpenAPI {
1718

1819
public struct Content: Codable, Equatable {
1920
public let schema: Either<JSONReference<Components, JSONSchema>, JSONSchema>
20-
// public let example:
21+
public let example: AnyCodable?
2122
// public let examples:
22-
// public let encoding:
23+
public let encoding: [String: Encoding]?
2324

24-
public init(schema: Either<JSONReference<Components, JSONSchema>, JSONSchema>) {
25+
public init(schema: Either<JSONReference<Components, JSONSchema>, JSONSchema>,
26+
example: AnyCodable? = nil,
27+
encoding: [String: Encoding]? = nil) {
2528
self.schema = schema
29+
self.example = example
30+
self.encoding = encoding
2631
}
2732
}
2833
}
2934

3035
extension OpenAPI.Content {
3136
public typealias Map = [OpenAPI.ContentType: OpenAPI.Content]
3237
}
38+
39+
extension OpenAPI.Content {
40+
public struct Encoding: Codable, Equatable {
41+
public let contentType: String?
42+
public let headers: OpenAPI.Header.Map?
43+
// public let style: String?
44+
// public let explode: Bool (defaults for this need to be tied to style making style a good candidate for abstraction)
45+
public let allowReserved: Bool
46+
47+
public init(contentType: String? = nil,
48+
headers: OpenAPI.Header.Map? = nil,
49+
allowReserved: Bool = false) {
50+
self.contentType = contentType
51+
self.headers = headers
52+
self.allowReserved = allowReserved
53+
}
54+
}
55+
}

Sources/OpenAPIKit/Header.swift

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// Header.swift
3+
// OpenAPIKit
4+
//
5+
// Created by Mathew Polzin on 8/25/19.
6+
//
7+
8+
import Foundation
9+
import Poly
10+
11+
extension OpenAPI {
12+
public struct Header: Equatable {
13+
public let description: String?
14+
public let required: Bool
15+
public let deprecated: Bool // default is false
16+
public let schemaOrContent: Either<SchemaProperty, OpenAPI.Content.Map>
17+
18+
public typealias Map = [String: Either<Header, JSONReference<OpenAPI.Components, Header>>]
19+
20+
public typealias SchemaProperty = Either<JSONReference<OpenAPI.Components, JSONSchema>, JSONSchema>
21+
22+
public init(schemaOrContent: Either<SchemaProperty, OpenAPI.Content.Map>,
23+
description: String? = nil,
24+
required: Bool = false,
25+
deprecated: Bool = false) {
26+
self.schemaOrContent = schemaOrContent
27+
self.description = description
28+
self.required = required
29+
self.deprecated = deprecated
30+
}
31+
}
32+
}
33+
34+
// MARK: - Codable
35+
36+
extension OpenAPI.Header {
37+
private enum CodingKeys: String, CodingKey {
38+
case description
39+
case required
40+
case deprecated
41+
42+
// the following are alternatives
43+
case content
44+
case schema
45+
}
46+
}
47+
48+
extension OpenAPI.Header: Encodable {
49+
public func encode(to encoder: Encoder) throws {
50+
var container = encoder.container(keyedBy: CodingKeys.self)
51+
52+
if required {
53+
try container.encode(required, forKey: .required)
54+
}
55+
56+
switch schemaOrContent {
57+
case .a(let schema):
58+
try container.encode(schema, forKey: .schema)
59+
case .b(let contentMap):
60+
// Hack to work around Dictionary encoding
61+
// itself as an array in this case:
62+
let stringKeyedDict = Dictionary(
63+
contentMap.map { ($0.key.rawValue, $0.value) },
64+
uniquingKeysWith: { $1 }
65+
)
66+
try container.encode(stringKeyedDict, forKey: .content)
67+
}
68+
69+
if description != nil {
70+
try container.encode(description, forKey: .description)
71+
}
72+
73+
if deprecated {
74+
try container.encode(deprecated, forKey: .deprecated)
75+
}
76+
}
77+
}
78+
79+
extension OpenAPI.Header: Decodable {
80+
public init(from decoder: Decoder) throws {
81+
let container = try decoder.container(keyedBy: CodingKeys.self)
82+
83+
required = try container.decodeIfPresent(Bool.self, forKey: .required) ?? false
84+
85+
// hacky workaround for Dictionary decoding bug
86+
let maybeContentDict = try container.decodeIfPresent([String: OpenAPI.Content].self, forKey: .content)
87+
let maybeContent = maybeContentDict.map { contentDict in
88+
Dictionary(contentDict.compactMap { contentTypeString, content in
89+
OpenAPI.ContentType(rawValue: contentTypeString).map { ($0, content) } },
90+
uniquingKeysWith: { $1 })
91+
}
92+
93+
let maybeSchema = try container.decodeIfPresent(SchemaProperty.self, forKey: .schema)
94+
95+
switch (maybeContent, maybeSchema) {
96+
case (let content?, _):
97+
schemaOrContent = .init(content)
98+
case (_, let schema?):
99+
schemaOrContent = .init(schema)
100+
default:
101+
throw OpenAPI.DecodingError.unsatisfied(requirement: "A single path parameter must specify one but not both 'content' and 'schema'.", codingPath: decoder.codingPath)
102+
}
103+
104+
description = try container.decodeIfPresent(String.self, forKey: .description)
105+
106+
deprecated = try container.decodeIfPresent(Bool.self, forKey: .deprecated) ?? false
107+
}
108+
}

Sources/OpenAPIKit/Node Conformances/SwiftPrimitiveTypes+OpenAPI.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//
2-
// PrimitiveTypes.swift
3-
// OpenAPI
2+
// SwiftPrimitiveTypes+OpenAPI.swift
3+
// OpenAPIKit
44
//
55
// Created by Mathew Polzin on 01/13/19.
66
//

Sources/OpenAPIKit/Response.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import Poly
1111
extension OpenAPI {
1212
public struct Response: Equatable {
1313
public let description: String
14-
// public let headers:
14+
public let headers: Header.Map?
1515
public let content: Content.Map
1616
// public let links:
1717

1818
public init(description: String,
19+
headers: Header.Map? = nil,
1920
content: Content.Map) {
2021
self.description = description
22+
self.headers = headers
2123
self.content = content
2224
}
2325
}
@@ -71,7 +73,7 @@ extension OpenAPI.Response.StatusCode: ExpressibleByIntegerLiteral {
7173
extension OpenAPI.Response {
7274
private enum CodingKeys: String, CodingKey {
7375
case description
74-
// case headers
76+
case headers
7577
case content
7678
// case links
7779
}
@@ -83,6 +85,10 @@ extension OpenAPI.Response: Encodable {
8385

8486
try container.encode(description, forKey: .description)
8587

88+
if headers != nil {
89+
try container.encode(headers, forKey: .headers)
90+
}
91+
8692
if content.count > 0 {
8793
// Hack to work around Dictionary encoding
8894
// itself as an array in this case:
@@ -101,6 +107,8 @@ extension OpenAPI.Response: Decodable {
101107

102108
description = try container.decode(String.self, forKey: .description)
103109

110+
headers = try container.decodeIfPresent(OpenAPI.Header.Map.self, forKey: .headers)
111+
104112
// hacky workaround for Dictionary decoding bug
105113
let maybeContentDict = try container.decodeIfPresent([String: OpenAPI.Content].self, forKey: .content)
106114
content = maybeContentDict.map { contentDict in

0 commit comments

Comments
 (0)