@@ -15,17 +15,47 @@ extension OpenAPI {
1515 ///
1616 /// This is a place to put reusable components to
1717 /// be referenced from other parts of the spec.
18+ ///
19+ /// Most of the components dictionaries can contain either the component
20+ /// directly or a $ref to the component. This distinction can be seen in
21+ /// the types as either `ComponentDictionary<T>` (direct) or
22+ /// `ComponentReferenceDictionary<T>` (direct or by-reference).
23+ ///
24+ /// If you are building a Components Object in Swift you may choose to make
25+ /// all of your components direct in which case the
26+ /// `OpenAPI.Components.direct()` convenience constructor will save you
27+ /// some typing and verbosity.
28+ ///
29+ /// **Example**
30+ /// OpenAPI.Components(
31+ /// parameters: [ "my_param": .parameter(.cookie(name: "my_param", schema: .string)) ]
32+ /// )
33+ ///
34+ /// // The above value is the same as the below value
35+ ///
36+ /// OpenAPI.Components.direct(
37+ /// parameters: [ "my_param": .cookie(name: "my_param", schema: .string) ]
38+ /// )
39+ ///
40+ /// // However, the `init()` initializer does allow you to use references where desired
41+ ///
42+ /// OpenAPI.Components(
43+ /// parameters: [
44+ /// "my_direct_param": .parameter(.cookie(name: "my_param", schema: .string)),
45+ /// "my_param": .reference(.component(named: "my_direct_param"))
46+ /// ]
47+ /// )
1848 public struct Components : Equatable , CodableVendorExtendable , Sendable {
1949
2050 public var schemas : ComponentDictionary < JSONSchema >
21- public var responses : ComponentDictionary < Response >
22- public var parameters : ComponentDictionary < Parameter >
23- public var examples : ComponentDictionary < Example >
24- public var requestBodies : ComponentDictionary < Request >
25- public var headers : ComponentDictionary < Header >
26- public var securitySchemes : ComponentDictionary < SecurityScheme >
27- public var links : ComponentDictionary < Link >
28- public var callbacks : ComponentDictionary < Callbacks >
51+ public var responses : ComponentReferenceDictionary < Response >
52+ public var parameters : ComponentReferenceDictionary < Parameter >
53+ public var examples : ComponentReferenceDictionary < Example >
54+ public var requestBodies : ComponentReferenceDictionary < Request >
55+ public var headers : ComponentReferenceDictionary < Header >
56+ public var securitySchemes : ComponentReferenceDictionary < SecurityScheme >
57+ public var links : ComponentReferenceDictionary < Link >
58+ public var callbacks : ComponentReferenceDictionary < Callbacks >
2959
3060 public var pathItems : ComponentDictionary < PathItem >
3161
@@ -38,14 +68,14 @@ extension OpenAPI {
3868
3969 public init (
4070 schemas: ComponentDictionary < JSONSchema > = [ : ] ,
41- responses: ComponentDictionary < Response > = [ : ] ,
42- parameters: ComponentDictionary < Parameter > = [ : ] ,
43- examples: ComponentDictionary < Example > = [ : ] ,
44- requestBodies: ComponentDictionary < Request > = [ : ] ,
45- headers: ComponentDictionary < Header > = [ : ] ,
46- securitySchemes: ComponentDictionary < SecurityScheme > = [ : ] ,
47- links: ComponentDictionary < Link > = [ : ] ,
48- callbacks: ComponentDictionary < Callbacks > = [ : ] ,
71+ responses: ComponentReferenceDictionary < Response > = [ : ] ,
72+ parameters: ComponentReferenceDictionary < Parameter > = [ : ] ,
73+ examples: ComponentReferenceDictionary < Example > = [ : ] ,
74+ requestBodies: ComponentReferenceDictionary < Request > = [ : ] ,
75+ headers: ComponentReferenceDictionary < Header > = [ : ] ,
76+ securitySchemes: ComponentReferenceDictionary < SecurityScheme > = [ : ] ,
77+ links: ComponentReferenceDictionary < Link > = [ : ] ,
78+ callbacks: ComponentReferenceDictionary < Callbacks > = [ : ] ,
4979 pathItems: ComponentDictionary < PathItem > = [ : ] ,
5080 vendorExtensions: [ String : AnyCodable ] = [ : ]
5181 ) {
@@ -62,6 +92,37 @@ extension OpenAPI {
6292 self . vendorExtensions = vendorExtensions
6393 }
6494
95+ /// Construct components as "direct" entries (no references). When
96+ /// building a document in Swift code, this is often sufficient and it
97+ /// means you don't need to wrap every entry in an `Either`.
98+ public static func direct(
99+ schemas: ComponentDictionary < JSONSchema > = [ : ] ,
100+ responses: ComponentDictionary < Response > = [ : ] ,
101+ parameters: ComponentDictionary < Parameter > = [ : ] ,
102+ examples: ComponentDictionary < Example > = [ : ] ,
103+ requestBodies: ComponentDictionary < Request > = [ : ] ,
104+ headers: ComponentDictionary < Header > = [ : ] ,
105+ securitySchemes: ComponentDictionary < SecurityScheme > = [ : ] ,
106+ links: ComponentDictionary < Link > = [ : ] ,
107+ callbacks: ComponentDictionary < Callbacks > = [ : ] ,
108+ pathItems: ComponentDictionary < PathItem > = [ : ] ,
109+ vendorExtensions: [ String : AnyCodable ] = [ : ]
110+ ) -> Self {
111+ . init(
112+ schemas: schemas,
113+ responses: responses. mapValues { . b( $0) } ,
114+ parameters: parameters. mapValues { . b( $0) } ,
115+ examples: examples. mapValues { . b( $0) } ,
116+ requestBodies: requestBodies. mapValues { . b( $0) } ,
117+ headers: headers. mapValues { . b( $0) } ,
118+ securitySchemes: securitySchemes. mapValues { . b( $0) } ,
119+ links: links. mapValues { . b( $0) } ,
120+ callbacks: callbacks. mapValues { . b( $0) } ,
121+ pathItems: pathItems,
122+ vendorExtensions: vendorExtensions
123+ )
124+ }
125+
65126 /// An empty OpenAPI Components Object.
66127 public static let noComponents : Components = . init( )
67128
@@ -71,6 +132,12 @@ extension OpenAPI {
71132 }
72133}
73134
135+ extension OpenAPI {
136+
137+ public typealias ComponentDictionary < T> = OrderedDictionary < ComponentKey , T >
138+ public typealias ComponentReferenceDictionary < T: ComponentDictionaryLocatable > = OrderedDictionary < ComponentKey , Either < OpenAPI . Reference < T > , T > >
139+ }
140+
74141extension OpenAPI . Components {
75142 public struct ComponentCollision : Swift . Error {
76143 public let componentType : String
@@ -130,11 +197,6 @@ extension OpenAPI.Components {
130197 public static let componentNameExtension : String = " x-component-name "
131198}
132199
133- extension OpenAPI {
134-
135- public typealias ComponentDictionary < T> = OrderedDictionary < ComponentKey , T >
136- }
137-
138200// MARK: - Codable
139201extension OpenAPI . Components : Encodable {
140202 public func encode( to encoder: Encoder ) throws {
@@ -194,30 +256,36 @@ extension OpenAPI.Components: Decodable {
194256 schemas = try container. decodeIfPresent ( OpenAPI . ComponentDictionary< JSONSchema> . self , forKey: . schemas)
195257 ?? [ : ]
196258
197- responses = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Response> . self , forKey: . responses)
259+ responses = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Response> . self , forKey: . responses)
198260 ?? [ : ]
199261
200- parameters = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Parameter> . self , forKey: . parameters)
262+ parameters = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Parameter> . self , forKey: . parameters)
201263 ?? [ : ]
202264
203- examples = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Example> . self , forKey: . examples)
265+ examples = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Example> . self , forKey: . examples)
204266 ?? [ : ]
205267
206- requestBodies = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Request> . self , forKey: . requestBodies)
268+ requestBodies = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Request> . self , forKey: . requestBodies)
207269 ?? [ : ]
208270
209- headers = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Header> . self , forKey: . headers)
271+ headers = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Header> . self , forKey: . headers)
210272 ?? [ : ]
211273
212- securitySchemes = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . SecurityScheme> . self , forKey: . securitySchemes) ?? [ : ]
274+ securitySchemes = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . SecurityScheme> . self , forKey: . securitySchemes) ?? [ : ]
213275
214- links = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Link> . self , forKey: . links) ?? [ : ]
276+ links = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Link> . self , forKey: . links) ?? [ : ]
215277
216- callbacks = try container. decodeIfPresent ( OpenAPI . ComponentDictionary < OpenAPI . Callbacks> . self , forKey: . callbacks) ?? [ : ]
278+ callbacks = try container. decodeIfPresent ( OpenAPI . ComponentReferenceDictionary < OpenAPI . Callbacks> . self , forKey: . callbacks) ?? [ : ]
217279
218280 pathItems = try container. decodeIfPresent ( OpenAPI . ComponentDictionary< OpenAPI . PathItem> . self , forKey: . pathItems) ?? [ : ]
219281
220282 vendorExtensions = try Self . extensions ( from: decoder)
283+ } catch let error as EitherDecodeNoTypesMatchedError {
284+ if let underlyingError = OpenAPI . Error. Decoding. Document. eitherBranchToDigInto ( error) {
285+ throw ( underlyingError. underlyingError ?? underlyingError)
286+ }
287+
288+ throw error
221289 } catch let error as DecodingError {
222290 if let underlyingError = error. underlyingError as? KeyDecodingError {
223291 throw GenericError (
0 commit comments