1 /**
2  * Authors: Szabo Bogdan <szabobogdan@yahoo.com>
3  * Date: 13 3, 2018
4  * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
5  * Copyright: Public Domain
6  */
7 module openapi.definitions;
8 
9 import std.traits;
10 import std.array;
11 import std.algorithm;
12 import std.conv;
13 import std.typecons;
14 import std.stdio;
15 import std.math;
16 
17 import vibe.data.json;
18 import vibe.data.serialization : SerializedName = name;
19 
20 private string memberToKey(alias member)() pure {
21   static if(member[$-1..$] == "_") {
22     return member[0..$-1];
23   } else {
24     return member;
25   }
26 }
27 
28 /// 
29 Type toEnumValue(Type)(string value) {
30   foreach(member; EnumMembers!Type) {{
31     if((cast(OriginalType!Type) member).to!string == value) {
32       return member;
33     }
34   }}
35 
36   throw new Exception("`" ~ value ~ "` is not a member in `" ~ Type.stringof ~ "`");
37 }
38 
39 OriginalType!Type toOriginalEnumValue(Type)(Type value) {
40   return cast(OriginalType!Type) value;
41 }
42 
43 mixin template Serialization(T) {
44 
45   @trusted:
46     Json[string] extensions;
47 
48     ///
49     Json toJson() const {
50       auto dest = Json.emptyObject;
51 
52       static if(__traits(hasMember, T, "_ref")) {
53         if(_ref != "") {
54           dest["$ref"] = _ref;
55           return dest;
56         }
57       }
58 
59       static foreach (member; __traits(allMembers, T)) 
60         static if(member != "extensions" && !isCallable!(__traits(getMember, T, member))) {{
61           alias Type = typeof(__traits(getMember, this, member));
62 
63 
64           auto tmp = __traits(getMember, this, member);
65 
66           static if(is(Type == class)) {
67             Json value;
68 
69             if(tmp is null) {
70               value = Json.undefined;
71             } else {
72               value = tmp.serializeToJson;
73             }
74           } else static if(!isSomeString!Type && (isArray!Type || isAssociativeArray!Type)) {
75             auto value = tmp.serializeToJson;
76           } else static if(is(Unqual!Type == bool)) {
77             auto value = tmp ? Json(true) : Json.undefined;
78           } else static if(isSomeString!Type || isBuiltinType!Type) {
79             auto value = Json(tmp);
80           } else {
81             auto value = tmp.serializeToJson;
82           }
83 
84           alias key = memberToKey!member;
85 
86           if(value.type == Json.Type.array && value.length == 0) {
87             value = Json.undefined;
88           }
89 
90           if(value.type == Json.Type.object && value.length == 0) {
91             value = Json.undefined;
92           }
93 
94           if(value.type == Json.Type..string && value == "") {
95             value = Json.undefined;
96           }
97 
98           if(value.type != Json.Type.undefined) {
99             dest[key] = value;
100           }
101         }}
102 
103       foreach(string key, Json value; extensions) {
104         dest[key] = value;
105       }
106 
107       return dest;
108     }
109 
110     ///
111     static T fromJson(Json src) {
112       T value;
113 
114       static if(__traits(hasMember, T, "_ref")) {
115         if("$ref" in src) {
116           value._ref = src["$ref"].to!string;
117           return value;
118         }
119       }
120 
121       static foreach (member; __traits(allMembers, T)) 
122         static if(member != "extensions" && !isCallable!(__traits(getMember, T, member))) {{
123           alias Type = typeof(__traits(getMember, value, member));
124           alias key = memberToKey!member;
125           Type tmp;
126 
127           if(key in src) {
128             static if(is(Type == enum)) {
129               tmp = src[key].to!string.toEnumValue!Type;
130             } else static if(isSomeString!Type) {
131               tmp = src[key].to!Type;
132             } else static if (isArray!Type) {
133               tmp = src[key].deserializeJson!Type;
134             } else static if(isAssociativeArray!Type) {
135               tmp = src[key].deserializeJson!Type;
136             } else static if(!isSomeString!Type && (isAggregateType!Type || isArray!Type || isAssociativeArray!Type)) {
137               tmp = src[key].deserializeJson!Type;
138             } else {
139               tmp = src[key].to!Type;
140             }
141 
142             __traits(getMember, value, member) = tmp;
143           }
144         }}
145 
146       value.extensions = src.byKeyValue.filter!(a => a.key.startsWith("x-")).assocArray;
147 
148       return value;
149     }
150 }
151 
152 ///
153 enum Schemes: string {
154   http = "http",
155   https = "https",
156   ws = "ws",
157   wss = "wss"
158 }
159 
160 ///
161 struct OpenApi {
162   /// This string MUST be the semantic version number of the OpenApi Specification 
163   /// version that the OpenApi document uses. The openapi field SHOULD be used by
164   /// tooling specifications and clients to interpret the OpenApi document. This
165   /// is not related to the API info.version string
166   string openapi = "3.0.1";
167 
168   /// Provides metadata about the API. The metadata MAY be used by tooling as required
169   Info info;
170 
171   /// The available paths and operations for the API
172   Path[string] paths;
173 
174   @optional {
175     /// An array of Server Objects, which provide connectivity information to a
176     /// target server. If the servers property is not provided, or is an empty
177     /// array, the default value would be a Server Object with a url value of /
178     Server[] servers;
179 
180     /// An element to hold various schemas for the specification
181     Components components;
182 
183     /// A declaration of which security mechanisms can be used across the API.
184     /// The list of values includes alternative security requirement objects
185     /// that can be used. Only one of the security requirement objects need
186     /// to be satisfied to authorize a request. Individual operations can
187     /// override this definition
188     SecurityRequirement security;
189     
190     /// A list of tags used by the specification with additional metadata.
191     /// The order of the tags can be used to reflect on their order by
192     /// the parsing tools. Not all tags that are used by the Operation
193     /// Object must be declared. The tags that are not declared MAY be organized
194     /// randomly or based on the tools' logic. Each tag name in the list MUST be unique.
195     Tag[] tags;
196 
197     /// Additional external documentation.
198     ExternalDocumentation externalDocs;
199   }
200 
201   mixin Serialization!OpenApi;
202 }
203 
204 /// The object provides metadata about the API. The metadata MAY
205 /// be used by the clients if needed, and MAY be presented in editing
206 /// or documentation generation tools for convenience.
207 struct Info {
208   /// The title of the application.
209   string title;
210 
211   /// The version of the OpenApi document (which is distinct from the
212   /// OpenApi Specification version or the API implementation version).
213   @SerializedName("version") string version_;
214 
215   @optional {
216     /// A short description of the application. CommonMark syntax MAY be used
217     /// for rich text representation.
218     string description;
219 
220     /// A URL to the Terms of Service for the API. MUST be in the format of a URL.
221     string termsOfService;
222 
223     /// The contact information for the exposed API.
224     Contact contact;
225 
226     /// The license information for the exposed API.
227     License license;
228   }
229 
230   mixin Serialization!Info;
231 }
232 
233 /// Contact information for the exposed API.
234 struct Contact {
235   @optional {
236     /// The identifying name of the contact person/organization.
237     string name;
238 
239     /// The URL pointing to the contact information. MUST be in the format of a URL.
240     string url;
241 
242     /// The email address of the contact person/organization. MUST be in the format of an email address.
243     string email;
244   }
245 
246   mixin Serialization!Contact;
247 }
248 
249 /// License information for the exposed API.
250 struct License {
251   /// The license name used for the API.
252   string name;
253 
254   /// A URL to the license used for the API. MUST be in the format of a URL.
255   @optional string url;
256 
257   mixin Serialization!License;
258 }
259 
260 // An object representing a Server.
261 struct Server {
262 
263   /// A URL to the target host. This URL supports Server Variables and MAY
264   /// be relative, to indicate that the host location is relative to the location
265   /// where the OpenApi document is being served. Variable substitutions will be
266   /// made when a variable is named in {brackets}.
267   string url;
268 
269   @optional {
270     /// An optional string describing the host designated by the URL. CommonMark syntax
271     /// MAY be used for rich text representation.
272     string description;
273 
274     /// A map between a variable name and its value. The value is used for substitution
275     /// in the server's URL template.
276     ServerVariable[string] variables;
277   }
278 
279   @safe:
280     ///
281     Json toJson() const {
282       auto dest = Json.emptyObject;
283 
284       if(url != "") {
285         dest["url"] = url;
286       }
287 
288       if(description != "") {
289         dest["description"] = description;
290       }
291 
292       if(variables.length > 0) {
293         dest["variables"] = variables.serializeToJson;
294       }
295 
296       return dest;
297     }
298 
299     ///
300     static Server fromJson(Json src) {
301       Server server;
302 
303       server.url = src["url"].to!string;
304 
305       if("description" in src) {
306         server.description = src["description"].to!string;
307       }
308 
309       if("variables" in src && src["variables"].length > 0) {
310         server.variables = src["variables"].deserializeJson!(ServerVariable[string]);
311       }
312 
313       return server;
314     }
315 }
316 
317 /// An object representing a Server Variable for server URL template substitution.
318 struct ServerVariable {
319 
320   /// The default value to use for substitution, and to send, if an alternate value is not
321   /// supplied. Unlike the Schema Object's default, this value MUST be provided by the consumer.
322   @SerializedName("default") string default_;
323 
324   @optional {
325     /// An enumeration of string values to be used if the substitution options are from a limited set.
326     @SerializedName("enum") string[] enum_;
327     
328     /// An optional description for the server variable. CommonMark syntax MAY be used for
329     /// rich text representation.
330     string description;
331   }
332 }
333 
334 /// Holds a set of reusable objects for different aspects of the OAS. All objects defined within
335 /// the components object will have no effect on the API unless they are explicitly referenced from
336 /// properties outside the components object.
337 struct Components {
338 
339   @optional {
340     ///An object to hold reusable Schema Objects.
341     Schema[string] schemas;
342     
343     ///An object to hold reusable Response Objects.
344     Response[string] responses;
345 
346     ///An object to hold reusable Parameter Objects.
347     Parameter[string] parameters;
348 
349     ///An object to hold reusable Example Objects.
350     Example[string] examples;
351 
352     ///An object to hold reusable Request Body Objects.
353     RequestBody[string] requestBodies;
354 
355     ///An object to hold reusable Header Objects.
356     Header[string] headers;
357 
358     ///An object to hold reusable Security Scheme Objects.
359     SecurityScheme[string] securitySchemes;
360 
361     ///An object to hold reusable Link Objects.
362     Link[string] links;
363 
364     ///An object to hold reusable Callback Objects.
365     Callback[string] callbacks;
366   }
367 
368   mixin Serialization!Components;
369 }
370 
371 alias Callback = Path[string];
372 
373 enum OperationsType : string {
374   get = "get",
375   put = "put",
376   post = "post",
377   delete_ = "delete",
378   options = "options",
379   head = "head",
380   patch = "patch",
381   trace = "trace" 
382 }
383 
384 /// Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path
385 /// itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.
386 struct Path {
387   alias operations this;
388 
389   @optional {
390     /// Allows for an external definition of this path item. The referenced structure MUST be in the format of
391     /// a Path Item Object. If there are conflicts between the referenced definition and this Path Item's
392     /// definition, the behavior is undefined.
393     @SerializedName("$ref") string _ref;
394 
395     /// An optional, string summary, intended to apply to all operations in this path.
396     string summary; 
397 
398     /// An optional, string description, intended to apply to all operations in this path. 
399     /// CommonMark syntax MAY be used for rich text representation.
400     string description; 
401 
402     /// Defined operations
403     Operation[OperationsType] operations; 
404 
405     /// An alternative server array to service all operations in this path.
406     Server[] servers; 
407 
408     /// A list of parameters that are applicable for all the operations described under this path.
409     /// These parameters can be overridden at the operation level, but cannot be removed there.
410     /// The list MUST NOT include duplicated parameters. A unique parameter is defined by
411     /// a combination of a name and location. The list can use the Reference Object to link
412     /// to parameters that are defined at the OpenApi Object's components/parameters.
413     Parameter[] parameters;
414   }
415 
416  @trusted:
417     ///
418     Json toJson() const {
419       auto dest = Json.emptyObject;
420 
421       if(_ref != "") {
422         dest["$ref"] = _ref;
423         return dest;
424       }
425 
426       if(summary != "") {
427         dest["summary"] = summary;
428       }
429 
430       if(description != "") {
431         dest["description"] = description;
432       }
433 
434       if(servers.length > 0) {
435         dest["servers"] = servers.serializeToJson;
436       }
437 
438       if(parameters.length > 0) {
439         dest["parameters"] = parameters.serializeToJson;
440       }
441 
442       foreach(string key, operation; operations) {
443         dest[key] = operation.serializeToJson;
444       }
445 
446       return dest;
447     }
448 
449     ///
450     static Path fromJson(Json src) {
451       Path path;
452 
453       if("$ref" in src) {
454         path._ref = "";
455         return path;
456       }
457 
458       if("summary" in src) {
459         path.summary = src["summary"].to!string;
460       }
461 
462       if("description" in src) {
463         path.description = src["description"].to!string;
464       }
465 
466       if("servers" in src) {
467         path.servers = src["servers"].deserializeJson!(Server[]);
468       }
469 
470       if("parameters" in src) {
471         path.parameters = src["parameters"].deserializeJson!(Parameter[]);
472       }
473 
474       static foreach(value; EnumMembers!OperationsType) {
475         if(value in src) {
476           path.operations[value] = src[value].deserializeJson!Operation;
477         }
478       }
479 
480       return path;
481     }
482 }
483 
484 /// Describes a single API operation on a path.
485 struct Operation {
486 
487   /// The list of possible responses as they are returned from executing this operation.
488   Response[string] responses;
489 
490   @optional {
491     /// A list of tags for API documentation control. Tags can be used for logical
492     /// grouping of operations by resources or any other qualifier.
493     string[] tags;
494 
495     /// A short summary of what the operation does.
496     string summary;
497 
498     /// A verbose explanation of the operation behavior. CommonMark syntax MAY be used for rich text representation.
499     string description;
500 
501     /// Additional external documentation for this operation.
502     ExternalDocumentation externalDocs;
503 
504     /// Unique string used to identify the operation. The id MUST be unique among all operations described
505     /// in the API. Tools and libraries MAY use the operationId to uniquely identify an operation, therefore,
506     /// it is RECOMMENDED to follow common programming naming conventions.
507     string operationId;
508 
509     /// A list of parameters that are applicable for this operation. If a parameter is already defined at the
510     /// Path Item, the new definition will override it but can never remove it. The list MUST NOT include
511     /// duplicated parameters. A unique parameter is defined by a combination of a name and location.
512     /// The list can use the Reference Object to link to parameters that are defined at the OpenApi
513     /// Object's components/parameters.
514     Parameter[] parameters;
515 
516     /// The request body applicable for this operation. The requestBody is only supported in HTTP methods
517     /// where the HTTP 1.1 specification RFC7231 has explicitly defined semantics for request bodies. In
518     /// other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers.
519     RequestBody requestBody;
520 
521     /// A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier
522     /// for the Callback Object. Each value in the map is a Callback Object that describes a request that may
523     /// be initiated by the API provider and the expected responses. The key value used to identify the callback
524     /// object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation.
525     Callback[string] callbacks;
526     
527     /// Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation.
528     /// Default value is false.
529     @SerializedName("deprecated") bool deprecated_;
530 
531     /// A declaration of which security mechanisms can be used for this operation. The list of values
532     /// includes alternative security requirement objects that can be used. Only one of the security
533     /// requirement objects need to be satisfied to authorize a request. This definition overrides any
534     /// declared top-level security. To remove a top-level security declaration, an empty array can be used.
535     SecurityRequirement[] security;
536 
537     /// An alternative server array to service this operation. If an alternative server object is specified
538     /// at the Path Item Object or Root level, it will be overridden by this value.
539     Server[] servers;
540   }
541 
542   @trusted:
543     ///
544     Json toJson() const {
545       Json data = Json.emptyObject;
546       data["responses"] = responses.serializeToJson;
547 
548       if(tags.length > 0) {
549         data["tags"] = tags.serializeToJson;
550       }
551 
552       if(summary != "") {
553         data["summary"] = summary;
554       }
555 
556       if(description != "") {
557         data["description"] = description;
558       }
559 
560       if(operationId != "") {
561         data["operationId"] = operationId;
562       } 
563 
564       if(parameters.length > 0) {
565         data["parameters"] = parameters.serializeToJson;
566       }
567 
568       if(deprecated_) {
569         data["deprecated"] = deprecated_;
570       }
571 
572       if(security.length > 0) {
573         data["security"] = security.serializeToJson;
574       }
575 
576       if(servers.length > 0) {
577         data["servers"] = servers.serializeToJson;
578       }
579 
580       auto externalDocsJson = externalDocs.serializeToJson;
581       if(externalDocsJson.length > 0) {
582         data["externalDocs"] = externalDocs.serializeToJson;
583       }
584 
585       auto requestBodyJson = requestBody.serializeToJson;
586       if(requestBodyJson.length > 0) {
587         data["requestBody"] = requestBodyJson;
588       }
589 
590       auto callbacksJson = callbacks.serializeToJson;
591       if(callbacksJson.length > 0) {
592         data["callbacks"] = callbacks.serializeToJson;
593       }
594 
595       return data;
596     }
597 
598     ///
599     static Operation fromJson(Json src) {
600       auto operation = Operation();
601 
602       if("responses" in src) {
603         operation.responses = src["responses"].deserializeJson!(Response[string]);
604       }
605 
606       if("tags" in src) {
607         operation.tags = src["tags"].deserializeJson!(string[]);
608       }
609 
610       if("summary" in src) {
611         operation.summary = src["summary"].to!string;
612       }
613 
614       if("description" in src) {
615         operation.description = src["description"].to!string;
616       }
617 
618       if("operationId" in src) {
619         operation.operationId = src["operationId"].to!string;
620       }
621 
622       if("externalDocs" in src) {
623         operation.externalDocs = src["externalDocs"].deserializeJson!ExternalDocumentation;
624       }
625 
626       if("parameters" in src) {
627         operation.parameters = src["parameters"].deserializeJson!(Parameter[]);
628       }
629 
630       if("requestBody" in src) {
631         operation.requestBody = src["requestBody"].deserializeJson!RequestBody;
632       }
633 
634       if("deprecated" in src) {
635         operation.deprecated_ = src["deprecated"].to!bool;
636       }
637 
638       if("security" in src) {
639         operation.security = src["security"].deserializeJson!(SecurityRequirement[]);
640       }
641 
642       if("servers" in src) {
643         operation.servers = src["servers"].deserializeJson!(Server[]);
644       }
645 
646       if("callbacks" in src) {
647         operation.callbacks = src["callbacks"].deserializeJson  !(Callback[string]);
648       }
649 
650       return operation;
651     }
652 }
653 
654 /// Allows referencing an external resource for extended documentation.
655 struct ExternalDocumentation {
656 
657   /// The URL for the target documentation. Value MUST be in the format of a URL.
658   string url;
659 
660   /// A short description of the target documentation. CommonMark syntax MAY be used for rich text representation.
661   @optional string description;
662 
663   mixin Serialization!ExternalDocumentation;
664 }
665 
666 ///
667 enum ParameterIn : string {
668   ///
669   query = "query",
670 
671   ///
672   header = "header",
673 
674   ///
675   path = "path",
676 
677   ///
678   cookie = "cookie",
679 
680   ///
681   body_ = "body"
682 }
683 
684 mixin template ParameterOptions() {
685 
686   @optional:
687     /// Determines whether this parameter is mandatory. If the parameter location is "path", this property is REQUIRED
688     /// and its value MUST be true. Otherwise, the property MAY be included and its default value is false.
689     bool required;
690 
691     /// A brief description of the parameter. This could contain examples of use. CommonMark syntax MAY be used
692     /// for rich text representation.
693     string description;
694 
695     /// Specifies that a parameter is deprecated and SHOULD be transitioned out of usage.
696     @SerializedName("deprecated") bool deprecated_;
697 
698     /// Sets the ability to pass empty-valued parameters. This is valid only for query parameters and allows
699     /// sending a parameter with an empty value. Default value is false. If style is used, and if behavior
700     /// is n/a (cannot be serialized), the value of allowEmptyValue SHALL be ignored.
701     bool allowEmptyValue;
702 
703     /// Describes how the parameter value will be serialized depending on the type of the parameter value.
704     /// Default values (based on value of in): for query - form; for path - simple;
705     /// for header - simple; for cookie - form.
706     Style style;
707     
708     /// When this is true, parameter values of type array or object generate separate parameters for each
709     /// value of the array or key-value pair of the map. For other types of parameters this property has no effect.
710     /// When style is form, the default value is true. For all other styles, the default value is false.
711     bool explode;
712     
713     /// Determines whether the parameter value SHOULD allow reserved characters, as defined by
714     /// RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding. This property only applies to 
715     /// parameters with an in value of query. The default value is false.
716     bool allowReserved;
717     
718     /// The schema defining the type used for the parameter.
719     Schema schema;
720 
721     /// Example of the media type. The example SHOULD match the specified schema andencoding properties
722     /// if present. The example field is mutually exclusive of the examples field. Furthermore, if
723     /// referencing a schema which contains an example, the example value SHALL override the example provided
724     /// by the schema. To represent examples of media types that cannot naturally be represented in JSON or
725     /// YAML, a string value can contain the example with escaping where necessary.
726     string example;
727     
728     /// Examples of the media type. Each example SHOULD contain a value in the correct format as specified in
729     /// the parameter encoding. The examples field is mutually exclusive of the example field. Furthermore,
730     /// if referencing a schema which contains an example, the examples value SHALL override the example
731     /// provided by the schema.
732     Example[string] examples;
733 
734     /// A map containing the representations for the parameter. The key is the media type and the value 
735     /// describes it. The map MUST only contain one entry.
736     MediaType[string] content;
737 }
738 
739 /// Describes a single operation parameter. A unique parameter is defined by a
740 /// combination of a name and location.
741 struct Parameter {
742   /***
743     The name of the parameter. Parameter names are case sensitive. 
744 
745       - If in is "path", the name field MUST correspond to the associated path segment from the path field
746         in the Paths Object. See Path Templating for further information.
747       
748       - If in is "header" and the name field is "Accept", "Content-Type" or "Authorization",
749         the parameter definition SHALL be ignored.
750       
751       - For all other cases, the name corresponds to the parameter name used by the in property.
752   */
753   string name;
754 
755   /// The location of the parameter.
756   @SerializedName("in") ParameterIn in_;
757 
758   mixin ParameterOptions;
759 
760   mixin Serialization!Parameter;
761 }
762 
763 /// The Header Object follows the structure of the Parameter Object
764 struct Header {
765   mixin ParameterOptions;
766 
767   mixin Serialization!Header;
768 }
769 
770 /// In order to support common ways of serializing simple parameters, a set of style values are defined.
771 enum Style : string {
772   ///
773   undefined = "",
774 
775   /// Path-style parameters defined by RFC6570
776   matrix = "matrix",
777 
778   /// Label style parameters defined by RFC6570
779   label = "label",
780 
781   /// Form style parameters defined by RFC6570. This option replaces collectionFormat with a csv (when explode is false) or multi
782   /// (when explode is true) value from OpenApi 2.0.
783   form = "form",
784 
785   /// Simple style parameters defined by RFC6570. This option replaces collectionFormat with a csv value from OpenApi 2.0.
786   simple = "simple",
787 
788   /// Space separated array values. This option replaces collectionFormat equal to ssv from OpenApi 2.0.
789   spaceDelimited = "spaceDelimited",
790 
791   /// Pipe separated array values. This option replaces collectionFormat equal to pipes from OpenApi 2.0.
792   pipeDelimited = "pipeDelimited",
793 
794   /// Provides a simple way of rendering nested objects using form parameters.
795   deepObject = "deepObject",
796 }
797 
798 /// Describes a single request body.
799 struct RequestBody {
800   /// The content of the request body. The key is a media type or media type range and the value
801   /// describes it. For requests that match multiple keys, only the most specific key is applicable.
802   /// e.g. text/plain overrides text/*
803   MediaType[string] content;
804 
805   @optional {
806     /// A brief description of the request body. This could contain examples of use. 
807     /// CommonMark syntax MAY be used for rich text representation.
808     string description;
809 
810     /// Determines if the request body is required in the request. Defaults to false.
811     bool required;
812   }
813 
814   mixin Serialization!RequestBody;
815 }
816 
817 /// Each Media Type Object provides schema and examples for the media type identified by its key.
818 struct MediaType {
819   @optional {
820     /// The schema defining the type used for the request body.
821     Schema schema;
822 
823     /// The example object SHOULD be in the correct format as specified by the media type. The example
824     /// field is mutually exclusive of the examples field. Furthermore, if referencing a schema which contains an
825     /// example, the example value SHALL override the example provided by the schema.
826     string example;
827     
828     /// True if the example is a Json object or array. This flag is used for serialization.
829     bool parseJsonExample;
830 
831     /// Examples of the media type. Each example object SHOULD match the media type and specified schema if present.
832     /// The examples field is mutually exclusive of the example field. Furthermore, if referencing a schema which
833     /// contains an example, the examples value SHALL override the example provided by the schema.
834     Example[string] examples;
835 
836     /// A map between a property name and its encoding information. The key, being the property name, MUST exist in
837     /// the schema as a property. The encoding object SHALL only apply to requestBody objects when the media type is
838     /// multipart or application/x-www-form-urlencoded.
839     Encoding[string] encoding;
840   }
841 
842   @trusted:
843     Json toJson() const {
844       Json value = Json.emptyObject;
845 
846       if(schema !is null) {
847         value["schema"] = schema.toJson;
848       }
849 
850       if(example != "") {
851         if(parseJsonExample) {
852           value["example"] = example.parseJsonString;
853         } else {
854           value["example"] = example;
855         }
856       }
857 
858       if(examples.length > 0) {
859         value["examples"] = examples.serializeToJson;
860       }
861 
862       if(encoding.length > 0) {
863         value["encoding"] = encoding.serializeToJson;
864       }
865 
866       return value;
867     }
868 
869     static MediaType fromJson(Json src) {
870       MediaType value;
871 
872       if("schema" in src) {
873         value.schema = Schema.fromJson(src["schema"]);
874       }
875 
876       if("example" in src) {
877         value.parseJsonExample = src["example"].type == Json.Type.array || src["example"].type == Json.Type.object;
878         value.example = src["example"].to!string;
879       }
880 
881       if("examples" in src) {
882         value.examples = src["examples"].deserializeJson!(Example[string]);
883       }
884 
885       if("encoding" in src) {
886         value.encoding = src["encoding"].deserializeJson!(Encoding[string]);
887       }
888 
889       return value;
890     }
891 }
892 
893 /// A single encoding definition applied to a single schema property.
894 struct Encoding {
895   @optional:
896     /// The Content-Type for encoding a specific property. Default value depends on the property type: for string with
897     /// format being binary – application/octet-stream; for other primitive types – text/plain; for object - application/json; 
898     /// for array – the default is defined based on the inner type. The value can be a specific media type (e.g. application/json), 
899     /// a wildcard media type (e.g. image/*), or a comma-separated list of the two types.
900     string contentType;
901 
902     /// A map allowing additional information to be provided as headers, for example Content-Disposition. Content-Type is
903     /// described separately and SHALL be ignored in this section. This property SHALL be ignored if the request body media 
904     /// type is not a multipart.
905     Header[string] headers;
906 
907     /// Describes how a specific property value will be serialized depending on its type. See Parameter Object for details on the style
908     /// property. The behavior follows the same values as query parameters, including default values. This property SHALL be ignored 
909     /// if the request body media type is not application/x-www-form-urlencoded.
910     Style style;
911     
912     /// When this is true, property values of type array or object generate separate parameters for each value of the array, or
913     /// key-value-pair of the map. For other types of properties this property has no effect. When style is form, the default value is
914     /// true. For all other styles, the default value is false. This property SHALL be ignored if the request body media type is not
915     /// application/x-www-form-urlencoded.
916     bool explode;
917     
918     /// Determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986 :/?#[]@!$&'()*+,;= to be included
919     /// without percent-encoding. The default value is false. This property SHALL be ignored if the request body media type is not
920     /// application/x-www-form-urlencoded.
921     bool allowReserved;
922 }
923 
924 /// Describes a single response from an API Operation, including design-time, static links to operations based on the response.
925 struct Response {
926   /// A short description of the response. CommonMark syntax MAY be used for rich text representation.
927   string description;
928 
929   @optional {
930     /// Maps a header name to its definition. RFC7230 states header names are case insensitive. If a response header is
931     /// defined with the name "Content-Type", it SHALL be ignored.
932     Header[string] headers;
933 
934     /// A map containing descriptions of potential response payloads. The key is a media type or media type range and the value
935     /// describes it. For responses that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/*
936     MediaType[string] content;
937 
938     /// A map of operations links that can be followed from the response. The key of the map is a short name for the link,
939     /// following the naming constraints of the names for Component Objects.
940     Link[string] links;
941   }
942 
943   mixin Serialization!Response;
944 }
945 
946 /***
947   The Link object represents a possible design-time link for a response. The presence of a link does not guarantee the caller's ability
948   to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations.
949 
950   Unlike dynamic links (i.e. links provided in the response payload), the OAS linking mechanism does not require link information in
951   the runtime response.
952 
953   For computing links, and providing instructions to execute them, a runtime expression is used for accessing values in an operation
954   and using them as parameters while invoking the linked operation.
955 */
956 struct Link {
957   @optional:
958     /// A relative or absolute reference to an OAS operation. This field is mutually exclusive of the operationId field, and MUST point to an
959     /// Operation Object. Relative operationRef values MAY be used to locate an existing Operation Object in the OpenApi definition.
960     string operationRef; 	
961     
962     /// The name of an existing, resolvable OAS operation, as defined with a unique operationId. This field is mutually exclusive of the operationRef field.
963     string operationId;
964   
965     /// A map representing parameters to pass to an operation as specified with operationId or identified via operationRef. The key is the parameter
966     /// name to be used, whereas the value can be a constant or an expression to be evaluated and passed to the linked operation. The parameter
967     /// name can be qualified using the parameter location [{in}.]{name} for operations that use the same parameter name in different locations (e.g. path.id).
968     string[string] parameters;
969     
970     /// A literal value or {expression} to use as a request body when calling the target operation.
971     string requestBody;
972 
973     /// A description of the link. CommonMark syntax MAY be used for rich text representation.
974     string description;
975 
976     /// A server object to be used by the target operation.
977     Server server;
978 
979     /// The reference string.
980     @SerializedName("$ref") string _ref;
981 
982   mixin Serialization!Link;
983 }
984 
985 enum SchemaType : string {
986   null_ = "null",
987   boolean = "boolean",
988   object = "object",
989   array = "array",
990   number = "number",
991   integer = "integer",
992   string = "string"
993 }
994 
995 enum SchemaFormat : string {
996   ///
997   undefined = "undefined",
998 
999   ///
1000   string = "string",
1001 
1002   /// signed 32 bits
1003   int32 = "int32",
1004 
1005   /// signed 64 bits
1006   int64 = "int64",
1007 
1008   ///
1009   float_ = "float",
1010   
1011   /// base64 encoded characters
1012   byte_ = "byte",
1013 
1014   /// any sequence of octets
1015   binary = "binary",
1016 
1017   /// As defined by full-date - RFC3339
1018   date = "date",
1019 
1020   /// As defined by date-time - RFC3339
1021   dateTime = "date-time",
1022 
1023   /// A hint to UIs to obscure input.
1024   password = "password",
1025 
1026   ///
1027   uri = "uri",
1028 
1029   ///
1030   uriref = "uriref"
1031 }
1032 
1033 /***
1034   The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays.
1035   This object is an extended subset of the JSON Schema Specification Wright Draft 00.
1036 
1037   For more information about the properties, see JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions
1038   follow the JSON Schema.
1039 */
1040 class Schema {
1041   @optional {
1042     /++ The following properties are taken directly from the JSON Schema definition and follow the same specifications: +/
1043 
1044     /// A title will preferrably be short
1045     string title;
1046 
1047     /// A numeric instance is only valid if division by this keyword's value results in an integer.
1048     ulong multipleOf;
1049 
1050     /// An upper limit for a numeric instance.
1051     /// If the instance is a number, then this keyword validates if "exclusiveMaximum" is true and instance is less than the provided
1052     /// value, or else if the instance is less than or exactly equal to the
1053     /// provided value.
1054     double maximum;
1055 
1056     /// ditto
1057     bool exclusiveMaximum;
1058     
1059     /// A lower limit for a numeric instance.
1060     /// If the instance is a number, then this keyword validates if "exclusiveMinimum" is true and instance is greater than the provided
1061     /// value, or else if the instance is greater than or exactly equal to the provided value.
1062     double minimum;
1063 
1064     /// ditto
1065     bool exclusiveMinimum;
1066 
1067     /// A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
1068     ulong maxLength;
1069 
1070     /// A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
1071     ulong minLength;
1072 
1073     /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect.
1074     string pattern;
1075 
1076     /// An array instance is valid against "maxItems" if its size is less than, or equal to.
1077     ulong maxItems;
1078 
1079     /// An array instance is valid against "minItems" if its size is greater than, or equal to.
1080     ulong minItems;
1081 
1082     /// If this keyword has boolean value false, the instance validates successfully.  If it has boolean value true, the instance validates
1083     /// successfully if all of its elements are unique.
1084     bool uniqueItems;
1085 
1086     /// An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
1087     ulong maxProperties;
1088 
1089     /// An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword.
1090     ulong minProperties;
1091 
1092     /// An object instance is valid against this keyword if its property set contains all elements in this keyword's array value.
1093     string[] required;
1094 
1095     /// 
1096     @SerializedName("enum") string[] enum_;
1097   }
1098 
1099   /++ 
1100     The following properties are taken from the JSON Schema definition but their definitions were adjusted to the OpenApi Specification. 
1101   +/
1102   @optional {
1103     /// An instance validates successfully against this keyword if its value is equal to one of the elements in this keyword's array value.
1104     SchemaType type;
1105     
1106     /// An instance validates successfully against this keyword if it validates successfully against all schemas defined by this keyword's
1107     /// value.
1108     Schema[] allOf;
1109     
1110     /// An instance validates successfully against this keyword if it validates successfully against exactly one schema defined by this
1111     /// keyword's value.
1112     Schema[] oneOf;
1113 
1114     /// An instance validates successfully against this keyword if it validates successfully against at least one schema defined by this
1115     /// keyword's value.
1116     Schema[] anyOf;
1117 
1118     /// An instance is valid against this keyword if it fails to validate successfully against the schema defined by this keyword.
1119     Schema[] not;
1120 
1121     /***
1122       MUST be present if the type is array.
1123 
1124       Successful validation of an array instance with regards to these two keywords is determined as follows:
1125 
1126       If either keyword is absent, it may be considered present with an empty schema.
1127     */
1128     Schema items;
1129 
1130     /// Using properties, we can define a known set of properties, however if we
1131     /// wish to use any other hash/map where we can't specify how many keys
1132     /// there are nor what they are in advance, we should use additionalProperties.
1133     Schema[string] properties;
1134 
1135 
1136     /// It will match any property name (that will act as the dict's key, and the $ref or
1137     /// type will be the schema of the dict's value, and since there should not be more than
1138     /// one properties with the same name for every given object, we will get the enforcement 
1139     /// of unique keys.
1140     Schema additionalProperties;
1141 
1142     /// CommonMark syntax MAY be used for rich text representation.
1143     string description;
1144 
1145     /// 
1146     SchemaFormat format;
1147 
1148     /// The default value
1149     @SerializedName("default") string default_;
1150 
1151     /+ Other than the JSON Schema subset fields, the following fields MAY be used for further schema documentation: +/
1152 
1153     /// Allows sending a null value for the defined schema.
1154     bool nullable;
1155 
1156     /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate between
1157     /// other schemas which may satisfy the payload description. See Composition and Inheritance for more details.
1158     Discriminator discriminator;
1159 
1160     /// Relevant only for Schema "properties" definitions. Declares the property as "read only". This means that it MAY be sent as part of a response but
1161     /// SHOULD NOT be sent as part of the request. If the property is marked as readOnly being true and is in the required list, the required will take
1162     /// effect on the response only. A property MUST NOT be marked as both readOnly and writeOnly being true. Default value is false.
1163     bool readOnly;
1164 
1165     /// Relevant only for Schema "properties" definitions. Declares the property as "write only". Therefore, it MAY be sent as part of a
1166     /// request but SHOULD NOT be sent as part of the response. If the property is marked as writeOnly being true and is in the required
1167     ///  list, the required will take effect on the request only. A property MUST NOT be marked as both readOnly and writeOnly being 
1168     /// true. Default value is false.
1169     bool writeOnly;
1170 
1171     /// This MAY be used only on properties schemas. It has no effect on root schemas. Adds additional metadata to describe
1172     /// the XML representation of this property.
1173     XML xml;
1174 
1175     /// Additional external documentation for this schema.
1176     ExternalDocumentation externalDocs;
1177 
1178     /// A free-form property to include an example of an instance for this schema. To represent examples that cannot
1179     /// be naturally represented in JSON or YAML, a string value can be used to contain the example with escaping where necessary.
1180     string example;
1181 
1182     /// Specifies that a schema is deprecated and SHOULD be transitioned out of usage. Default value is false.
1183     @SerializedName("deprecated") bool deprecated_;
1184 
1185     /// The reference string.
1186     @SerializedName("$ref") string _ref;
1187   }
1188 
1189   @trusted:
1190 
1191   enum toFields = [
1192     "title", "multipleOf", "maximum", "exclusiveMaximum",
1193     "minimum", "exclusiveMinimum", "maxLength", "minLength",
1194     "pattern", "maxItems", "minItems", "uniqueItems",
1195     "maxProperties", "minProperties", "description",
1196     "nullable", "readOnly", "writeOnly"];
1197 
1198   enum enumField = [
1199     "type", "format"
1200   ];
1201 
1202   enum aFields = [
1203     "allOf", "oneOf", "anyOf", "not"
1204   ];
1205 
1206   enum aaFields = [
1207     "properties"
1208   ];
1209 
1210   enum deserializableFields = [
1211     "discriminator", "xml", "externalDocs", "required"
1212   ];
1213 
1214   Json toJson() const {
1215     Json value = Json.emptyObject;
1216     Schema defaultSchema = new Schema;
1217 
1218     if(_ref != "") {
1219       value["$ref"] = _ref;
1220 
1221       return value;
1222     }
1223 
1224     if(default_ != "") {
1225       try {
1226         value["default"] = default_.parseJsonString;
1227       } catch(JSONException) {
1228         value["default"] = default_;
1229       }
1230     }
1231 
1232     if(deprecated_) {
1233       value["deprecated"] = true;
1234     }
1235 
1236     if(enum_.length > 0) {
1237       value["enum"] = enum_.serializeToJson;
1238     }
1239 
1240     if(example != "") {
1241       value["example"] = example.parseJsonString;
1242     }
1243 
1244     /// to fields
1245     static foreach(field; toFields) {{
1246       alias Type = typeof(__traits(getMember, Schema, field));
1247 
1248       auto tmp = __traits(getMember, this, field);
1249       auto defaultValue = __traits(getMember, defaultSchema, field);
1250 
1251       static if(is(Type == double)) {
1252         if(!isNaN(tmp)) {
1253           value[field] = tmp;
1254         }
1255       } else if(tmp != defaultValue) {
1256         value[field] = tmp;
1257       }
1258     }}
1259 
1260     /// enum fields
1261     static foreach(field; enumField) {{
1262       auto tmp = __traits(getMember, this, field);
1263       auto defaultValue = __traits(getMember, defaultSchema, field);
1264 
1265       if(tmp != defaultValue) {
1266         value[field] = tmp.toOriginalEnumValue;
1267       }
1268     }}
1269 
1270     /// array fields
1271     static foreach(field; aFields) {{
1272       auto tmp = __traits(getMember, this, field);
1273 
1274       if(tmp.length > 0) {
1275         value[field] = tmp.serializeToJson;
1276       }
1277     }}
1278 
1279     /// assoc array fields
1280     static foreach(field; aaFields) {{
1281       auto tmp = __traits(getMember, this, field);
1282 
1283       if(tmp.length > 0) {
1284         value[field] = tmp.serializeToJson;
1285       }
1286     }}
1287 
1288     if(items !is null) {
1289       value["items"] = items.toJson;
1290     }
1291 
1292     /// deserializable fields
1293     static foreach(field; deserializableFields) {{
1294       alias Type = typeof(__traits(getMember, Schema, field));
1295 
1296       Json tmp = __traits(getMember, this, field).serializeToJson;
1297 
1298       if(tmp.length > 0) {
1299         value[field] = tmp;
1300       }
1301     }}
1302 
1303     if(additionalProperties !is null) {
1304       value["additionalProperties"] = additionalProperties.toJson;
1305     }
1306 
1307     return value;
1308   }
1309 
1310   ///
1311   static Schema fromJson(Json src) {
1312     Schema schema = new Schema;
1313 
1314     if("$ref" in src) {
1315       schema._ref = src["$ref"].to!string;
1316       return schema;
1317     }
1318 
1319     if("default" in src) {
1320       schema.default_ = src["default"].to!string;
1321     }
1322 
1323     if("deprecated" in src) {
1324       schema.deprecated_ = src["deprecated"].to!bool;
1325     }
1326 
1327     if("enum" in src) {
1328       schema.enum_ = src["enum"].deserializeJson!(string[]);
1329     }
1330 
1331     if("items" in src) {
1332       schema.items = src["items"].deserializeJson!Schema;
1333     }
1334 
1335     if("example" in src) {
1336       schema.example = src["example"].toString;
1337     }
1338 
1339     /// to fields
1340     static foreach(field; toFields) {{
1341       alias Type = typeof(__traits(getMember, Schema, field));
1342 
1343       if(field in src) {
1344         auto value = src[field].to!Type;
1345         if(__traits(getMember, schema, field) != value) {
1346           __traits(getMember, schema, field) = value;
1347         }
1348       }
1349     }}
1350 
1351     /// enum fields
1352     static foreach(field; enumField) {{
1353       alias Type = typeof(__traits(getMember, Schema, field));
1354 
1355       if(field in src) {
1356         Type value;
1357         
1358         try {
1359           value = src[field].to!string.toEnumValue!Type;
1360 
1361           if(__traits(getMember, schema, field) != value) {
1362             __traits(getMember, schema, field) = value;
1363           }
1364         } catch(Exception e) {
1365           writeln(e.msg);
1366         }
1367       }
1368     }}
1369 
1370     /// array fields
1371     static foreach(field; aFields) {{
1372       if(field in src && src[field].length > 0) {
1373         auto value = src[field].byValue.map!(a => Schema.fromJson(a)).array;
1374         __traits(getMember, schema, field) = value;
1375       }
1376     }}
1377 
1378     /// assoc array fields
1379     static foreach(field; aaFields) {{
1380       if(field in src && src[field].length > 0) {
1381         try {
1382           auto value = src[field].byKeyValue.map!(a => tuple(a.key, Schema.fromJson(a.value))).assocArray;
1383           __traits(getMember, schema, field) = value;
1384         } catch(Exception e) {
1385           writeln("Error: ", e.msg);
1386         }
1387       }
1388     }}
1389 
1390     /// deserializable fields
1391     static foreach(field; deserializableFields) {{
1392       alias Type = typeof(__traits(getMember, Schema, field));
1393 
1394       if(field in src && src[field].length > 0) {
1395         try {
1396           auto value = src[field].deserializeJson!Type;
1397           __traits(getMember, schema, field) = value;
1398         } catch(Exception e) {
1399           writeln("`", field, "` error: ", e.msg);
1400         }
1401       }
1402     }}
1403 
1404     if("additionalProperties" in src && src["additionalProperties"].type == Json.Type.object) {
1405       schema.additionalProperties = Schema.fromJson(src["additionalProperties"]);
1406     }
1407 
1408     return schema;
1409   }
1410 }
1411 
1412 /***
1413 When request bodies or response payloads may be one of a number of different schemas, a discriminator object can be used
1414 to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used
1415 to inform the consumer of the specification of an alternative schema based on the value associated with it.
1416 
1417 When using the discriminator, inline schemas will not be considered.
1418 */
1419 struct Discriminator {
1420   /// The name of the property in the payload that will hold the discriminator value.
1421   string propertyName;
1422 
1423   /// An object to hold mappings between payload values and schema names or references.
1424   @optional string[string][string] mapping;
1425 
1426   mixin Serialization!Discriminator;
1427 }
1428 
1429 /***
1430 A metadata object that allows for more fine-tuned XML model definitions.
1431 
1432 When using arrays, XML element names are not inferred (for singular/plural forms) and the name property SHOULD 
1433 be used to add that information. See examples for expected behavior.
1434 */
1435 struct XML {
1436   @optional {
1437     /// Replaces the name of the element/attribute used for the described schema property. When defined within items, it
1438     /// will affect the name of the individual XML elements within the list. When defined alongside type being array
1439     /// (outside the items), it will affect the wrapping element and only if wrapped is true. If wrapped is false, it will be ignored.
1440     string name;
1441 
1442     /// The URI of the namespace definition. Value MUST be in the form of an absolute URI.
1443     string namespace;
1444 
1445     /// The prefix to be used for the name.
1446     string prefix;
1447 
1448     /// Declares whether the property definition translates to an attribute instead of an element. Default value is false.
1449     bool attribute;
1450 
1451     /// MAY be used only for an array definition. Signifies whether the array is wrapped
1452     /// (for example, <books><book/><book/></books>) or unwrapped (<book/><book/>).
1453     /// Default value is false. The definition takes effect only when defined alongside type being array (outside the items).
1454     bool wrapped;
1455   }
1456 
1457   mixin Serialization!XML;
1458 }
1459 
1460 ///
1461 struct Example {
1462   @optional {
1463     /// Short description for the example.
1464     string summary;
1465 
1466     /// Long description for the example. CommonMark syntax MAY be used for rich text representation.
1467     string description;
1468 
1469     /// Embedded literal example. The value field and externalValue field are mutually exclusive. To represent examples
1470     /// of media types that cannot naturally represented in JSON or YAML, use a string value to contain the example, escaping where necessary.
1471     string value;
1472 
1473     /// A URL that points to the literal example. This provides the capability to reference examples that
1474     /// cannot easily be included in JSON or YAML documents. The value field and externalValue field are mutually exclusive.
1475     string externalValue;
1476 
1477     /// True if the value should be treated as a json object or array
1478     bool parseJsonValue;
1479   }
1480 
1481   Json toJson() const @safe {
1482     Json jsonValue = Json.emptyObject;
1483 
1484     if(summary != "") {
1485       jsonValue["summary"] = summary;
1486     }
1487 
1488     if(description != "") {
1489       jsonValue["description"] = description;
1490     }
1491 
1492     if(externalValue != "") {
1493       jsonValue["externalValue"] = externalValue;
1494     }
1495 
1496     if(value != "") {
1497       if(parseJsonValue) {
1498         jsonValue["value"] = value.parseJsonString;
1499       } else {
1500         jsonValue["value"] = value;
1501       }
1502     }
1503 
1504     return jsonValue;
1505   }
1506 
1507   ///
1508   static Example fromJson(Json src) @safe {
1509     Example example;
1510 
1511     if("summary" in src) {
1512       example.summary = src["summary"].to!string;
1513     }
1514 
1515     if("description" in src) {
1516       example.description = src["description"].to!string;
1517     }
1518 
1519     if("externalValue" in src) {
1520       example.externalValue = src["externalValue"].to!string;
1521     }
1522 
1523     if("value" in src) {
1524       example.parseJsonValue = src["value"].type == Json.Type.array || src["value"].type == Json.Type.object;
1525       example.value = src["value"].to!string;
1526     }
1527 
1528     return example;
1529   }
1530 }
1531 
1532 /// Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a
1533 /// Tag Object per tag defined in the Operation Object instances.
1534 struct Tag {
1535   /// The name of the tag
1536   string name;
1537 
1538   @optional {
1539     /// A short description for the tag. CommonMark syntax MAY be used for rich text representation.
1540     string description;
1541 
1542     /// Additional external documentation for this tag.
1543     ExternalDocumentation externalDocs;
1544   }
1545 
1546   mixin Serialization!Tag;
1547 }
1548 
1549 /// 
1550 enum SecurityType : string {
1551   apiKey = "apiKey",
1552   http = "http",
1553   oauth2 = "oauth2",
1554   openIdConnect = "openIdConnect"
1555 }
1556 
1557 /**
1558   Defines a security scheme that can be used by the operations. Supported schemes are HTTP authentication, an API key (either
1559   as a header or as a query parameter), OAuth2's common flows (implicit, password, application and access code) as defined
1560   in RFC6749, and OpenID Connect Discovery.
1561 */
1562 struct SecurityScheme {
1563   /// 
1564   SecurityType type;
1565 
1566   @optional {
1567     /// A hint to the client to identify how the bearer token is formatted. Bearer tokens are usually generated by an
1568     /// authorization server, so this information is primarily for documentation purposes.
1569     string bearerFormat;
1570 
1571     /// A short description for security scheme. CommonMark syntax MAY be used for rich text representation.
1572     string description;
1573 
1574     /// The name of the header, query or cookie parameter to be used.
1575     string name;
1576 
1577     /// The location of the API key
1578     @SerializedName("in") ParameterIn in_;
1579 
1580     /// The name of the HTTP Authorization scheme to be used in the Authorization header as defined in RFC7235.
1581     string scheme;
1582 
1583     /// An object containing configuration information for the flow types supported.
1584     OAuthFlows flows;
1585 
1586     /// OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of a URL.
1587     string openIdConnectUrl;
1588   }
1589 
1590   mixin Serialization!SecurityScheme;
1591 }
1592 
1593 /// Allows configuration of the supported OAuth Flows.
1594 struct OAuthFlows {
1595   @optional {
1596     /// Configuration for the OAuth Implicit flow
1597     OAuthFlow implicit;
1598 
1599     /// Configuration for the OAuth Resource Owner Password flow
1600     OAuthFlow password;
1601 
1602     /// Configuration for the OAuth Client Credentials flow. Previously called application in OpenApi 2.0.
1603     OAuthFlow clientCredentials;
1604 
1605     /// Configuration for the OAuth Authorization Code flow. Previously called accessCode in OpenApi 2.0.
1606     OAuthFlow authorizationCode;
1607   }
1608 
1609   mixin Serialization!OAuthFlows;
1610 }
1611 
1612 /// Configuration details for a supported OAuth Flow
1613 struct OAuthFlow {
1614 
1615   /// The authorization URL to be used for this flow. This MUST be in the form of a URL.
1616   string authorizationUrl;
1617 
1618   /// The token URL to be used for this flow. This MUST be in the form of a URL.
1619   string tokenUrl;
1620 
1621   /// The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it.
1622   string[string] scopes;
1623 
1624   /// The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL.
1625   @optional string oauth2;
1626 
1627 
1628   mixin Serialization!OAuthFlow;
1629 }
1630 
1631 /// 
1632 alias SecurityRequirement = string[][string];