rweb_openapi/v3_0/
schema.rs

1//! Schema specification for [OpenAPI 3.0.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
2
3use crate::{
4    v3_0::components::{Components, ObjectOrReference},
5    Str,
6};
7use indexmap::IndexMap;
8use serde::{Deserialize, Serialize};
9use serde_json;
10use url::Url;
11
12/// top level document
13#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
14pub struct Spec {
15    /// This string MUST be the [semantic version number](https://semver.org/spec/v2.0.0.html)
16    /// of the
17    /// [OpenAPI Specification version](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#versions)
18    /// that the OpenAPI document uses. The `openapi` field SHOULD be used by tooling
19    /// specifications and clients to interpret the OpenAPI document. This is not related to
20    /// the API
21    /// [`info.version`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#infoVersion)
22    /// string.
23    pub openapi: Str,
24    /// Provides metadata about the API. The metadata MAY be used by tooling as required.
25    pub info: Info,
26    /// An array of Server Objects, which provide connectivity information to a target server.
27    /// If the `servers` property is not provided, or is an empty array, the default value would
28    /// be a
29    /// [Server Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#serverObject)
30    /// with a
31    /// [url](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#serverUrl)
32    /// value of `/`.
33    #[serde(skip_serializing_if = "Vec::is_empty")]
34    pub servers: Vec<Server>,
35
36    /// Holds the relative paths to the individual endpoints and their operations. The path is
37    /// appended to the URL from the
38    /// [`Server Object`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#serverObject)
39    /// in order to construct the full URL. The Paths MAY be empty, due to
40    /// [ACL constraints](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#securityFiltering).
41    pub paths: IndexMap<Str, PathItem>,
42
43    /// An element to hold various schemas for the specification.
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub components: Option<Components>,
46
47    /// A declaration of which security mechanisms can be used across the API.
48    /// The list of  values includes alternative security requirement objects that can be used.
49    /// Only one of the security requirement objects need to be satisfied to authorize a request.
50    /// Individual operations can override this definition.
51    #[serde(skip_serializing_if = "Vec::is_empty")]
52    pub security: Vec<SecurityRequirement>,
53
54    /// A list of tags used by the specification with additional metadata.
55    ///The order of the tags can be used to reflect on their order by the parsing tools.
56    /// Not all tags that are used by the
57    /// [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#operationObject)
58    /// must be declared. The tags that are not declared MAY be organized randomly or
59    /// based on the tools' logic. Each tag name in the list MUST be unique.
60    #[serde(skip_serializing_if = "Vec::is_empty")]
61    pub tags: Vec<Tag>,
62
63    /// Additional external documentation.
64    #[serde(skip_serializing_if = "Option::is_none", rename = "externalDocs")]
65    pub external_docs: Option<ExternalDoc>,
66    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
67}
68
69/// General information about the API.
70///
71///
72/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#infoObject>.
73#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
74// #[serde(rename_all = "lowercase")]
75pub struct Info {
76    /// The title of the application.
77    pub title: Str,
78    /// A short description of the application. CommonMark syntax MAY be used for rich text representation.
79    #[serde(skip_serializing_if = "str::is_empty")]
80    pub description: Str,
81    /// A URL to the Terms of Service for the API. MUST be in the format of a URL.
82    #[serde(rename = "termsOfService", skip_serializing_if = "Option::is_none")]
83    pub terms_of_service: Option<Url>,
84    /// The version of the OpenAPI document (which is distinct from the [OpenAPI Specification
85    /// version](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oasVersion)
86    /// or the API implementation version).
87    pub version: Str,
88    /// The contact information for the exposed API.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub contact: Option<Contact>,
91    /// The license information for the exposed API.
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub license: Option<License>,
94}
95
96/// Contact information for the exposed API.
97///
98/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#contactObject>.
99#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
100pub struct Contact {
101    #[serde(skip_serializing_if = "str::is_empty")]
102    pub name: Str,
103
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub url: Option<Url>,
106
107    // TODO: Make sure the email is a valid email
108    #[serde(skip_serializing_if = "str::is_empty")]
109    pub email: Str,
110    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions
111}
112
113/// License information for the exposed API.
114///
115/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#licenseObject>.
116#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
117pub struct License {
118    /// The license name used for the API.
119    pub name: Str,
120    /// A URL to the license used for the API.
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub url: Option<Url>,
123    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
124}
125
126/// An object representing a Server.
127///
128/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#serverObject>.
129#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
130pub struct Server {
131    /// A URL to the target host. This URL supports Server Variables and MAY be relative, to
132    /// indicate that the host location is relative to the location where the OpenAPI document
133    /// is being served. Variable substitutions will be made when a variable is named
134    /// in {brackets}.
135    pub url: Str,
136    /// An optional string describing the host designated by the URL. CommonMark syntax MAY be used for rich text representation.
137    #[serde(skip_serializing_if = "str::is_empty")]
138    pub description: Str,
139    /// A map between a variable name and its value. The value is used for substitution in
140    /// the server's URL template.
141    #[serde(skip_serializing_if = "IndexMap::is_empty")]
142    pub variables: IndexMap<Str, ServerVariable>,
143}
144
145/// An object representing a Server Variable for server URL template substitution.
146///
147/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#serverVariableObject>.
148#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
149pub struct ServerVariable {
150    /// The default value to use for substitution, and to send, if an alternate value is not
151    /// supplied. Unlike the Schema Object's default, this value MUST be provided by the consumer.
152    pub default: Str,
153    /// An enumeration of string values to be used if the substitution options are from a limited
154    /// set.
155    #[serde(rename = "enum", skip_serializing_if = "Vec::is_empty")]
156    pub substitutions_enum: Vec<Str>,
157    /// An optional description for the server variable. [CommonMark] syntax MAY be used for rich
158    /// text representation.
159    ///
160    /// [CommonMark]: https://spec.commonmark.org/
161    #[serde(skip_serializing_if = "str::is_empty")]
162    pub description: Str,
163}
164
165/// Describes the operations available on a single path.
166///
167/// A Path Item MAY be empty, due to [ACL
168/// constraints](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#securityFiltering).
169/// The path itself is still exposed to the documentation viewer but they will not know which
170/// operations and parameters are available.
171#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
172pub struct PathItem {
173    /// Allows for an external definition of this path item. The referenced structure MUST be
174    /// in the format of a
175    /// [Path Item Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#pathItemObject).
176    /// If there are conflicts between the referenced definition and this Path Item's definition,
177    /// the behavior is undefined.
178    #[serde(skip_serializing_if = "str::is_empty", rename = "$ref")]
179    pub reference: Str,
180
181    /// An optional, string summary, intended to apply to all operations in this path.
182    #[serde(skip_serializing_if = "str::is_empty")]
183    pub summary: Str,
184    /// An optional, string description, intended to apply to all operations in this path.
185    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
186    #[serde(skip_serializing_if = "str::is_empty")]
187    pub description: Str,
188
189    /// A definition of a GET operation on this path.
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub get: Option<Operation>,
192    /// A definition of a PUT operation on this path.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub put: Option<Operation>,
195    /// A definition of a POST operation on this path.
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub post: Option<Operation>,
198    /// A definition of a DELETE operation on this path.
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub delete: Option<Operation>,
201    /// A definition of a OPTIONS operation on this path.
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub options: Option<Operation>,
204    /// A definition of a HEAD operation on this path.
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub head: Option<Operation>,
207    /// A definition of a PATCH operation on this path.
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub patch: Option<Operation>,
210    /// A definition of a TRACE operation on this path.
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub trace: Option<Operation>,
213
214    /// An alternative `server` array to service all operations in this path.
215    #[serde(skip_serializing_if = "Vec::is_empty")]
216    pub servers: Vec<Server>,
217
218    /// A list of parameters that are applicable for all the operations described under this
219    /// path. These parameters can be overridden at the operation level, but cannot be removed
220    /// there. The list MUST NOT include duplicated parameters. A unique parameter is defined by
221    /// a combination of a
222    /// [name](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterName)
223    /// and
224    /// [location](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterIn).
225    /// The list can use the
226    /// [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#referenceObject)
227    /// to link to parameters that are defined at the
228    /// [OpenAPI Object's components/parameters](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#componentsParameters).
229    #[serde(skip_serializing_if = "Vec::is_empty")]
230    pub parameters: Vec<ObjectOrReference<Parameter>>,
231    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
232}
233
234/// Describes a single API operation on a path.
235///
236/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#operationObject>.
237#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
238// #[serde(rename_all = "lowercase")]
239pub struct Operation {
240    /// A list of tags for API documentation control. Tags can be used for logical grouping of
241    /// operations by resources or any other qualifier.
242    #[serde(skip_serializing_if = "Vec::is_empty")]
243    pub tags: Vec<Str>,
244    /// A short summary of what the operation does.
245    #[serde(skip_serializing_if = "str::is_empty")]
246    pub summary: Str,
247    /// A verbose explanation of the operation behavior.
248    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
249    #[serde(skip_serializing_if = "str::is_empty")]
250    pub description: Str,
251    /// Additional external documentation for this operation.
252    #[serde(skip_serializing_if = "Option::is_none", rename = "externalDocs")]
253    pub external_docs: Option<ExternalDoc>,
254    /// Unique string used to identify the operation. The id MUST be unique among all operations
255    /// described in the API. Tools and libraries MAY use the operationId to uniquely identify an
256    /// operation, therefore, it is RECOMMENDED to follow common programming naming conventions.
257    #[serde(skip_serializing_if = "str::is_empty", rename = "operationId")]
258    pub operation_id: Str,
259
260    /// A list of parameters that are applicable for this operation. If a parameter is already
261    /// defined at the
262    /// [Path Item](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#pathItemParameters),
263    /// the new definition will override it but can never remove it. The list MUST NOT
264    /// include duplicated parameters. A unique parameter is defined by a combination of a
265    /// [name](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterName)
266    /// and
267    /// [location](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterIn).
268    /// The list can use the
269    /// [Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#referenceObject)
270    /// to link to parameters that are defined at the
271    /// [OpenAPI Object's components/parameters](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#componentsParameters).
272    #[serde(skip_serializing_if = "Vec::is_empty")]
273    pub parameters: Vec<ObjectOrReference<Parameter>>,
274
275    /// The request body applicable for this operation. The requestBody is only supported in HTTP methods where the HTTP 1.1 specification RFC7231 has explicitly defined semantics for request bodies. In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers.
276    #[serde(skip_serializing_if = "Option::is_none", rename = "requestBody")]
277    pub request_body: Option<ObjectOrReference<RequestBody>>,
278
279    /// The list of possible responses as they are returned from executing this operation.
280    ///
281    /// A container for the expected responses of an operation. The container maps a HTTP
282    /// response code to the expected response.
283    ///
284    /// The documentation is not necessarily expected to cover all possible HTTP response codes
285    /// because they may not be known in advance. However, documentation is expected to cover
286    /// a successful operation response and any known errors.
287    ///
288    /// The `default` MAY be used as a default response object for all HTTP codes that are not
289    /// covered individually by the specification.
290    ///
291    /// The `Responses Object` MUST contain at least one response code, and it SHOULD be the
292    /// response for a successful operation call.
293    ///
294    /// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#responsesObject>.
295    pub responses: IndexMap<Str, Response>,
296
297    /// A map of possible out-of band callbacks related to the parent operation. The key is
298    /// a unique identifier for the Callback Object. Each value in the map is a
299    /// [Callback Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#callbackObject)
300    /// that describes a request that may be initiated by the API provider and the
301    /// expected responses. The key value used to identify the callback object is
302    /// an expression, evaluated at runtime, that identifies a URL to use for the
303    /// callback operation.
304    #[serde(skip_serializing_if = "IndexMap::is_empty")]
305    pub callbacks: IndexMap<Str, Callback>,
306
307    /// Declares this operation to be deprecated. Consumers SHOULD refrain from usage
308    /// of the declared operation. Default value is `false`.
309    #[serde(skip_serializing_if = "Option::is_none")]
310    pub deprecated: Option<bool>,
311
312    /// A declaration of which security mechanisms can be used for this operation. The list of
313    /// values includes alternative security requirement objects that can be used. Only one
314    /// of the security requirement objects need to be satisfied to authorize a request.
315    /// This definition overrides any declared top-level
316    /// [`security`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oasSecurity).
317    /// To remove a top-level security declaration, an empty array can be used.
318    #[serde(skip_serializing_if = "Vec::is_empty")]
319    pub security: Vec<SecurityRequirement>,
320
321    /// An alternative `server` array to service this operation. If an alternative `server`
322    /// object is specified at the Path Item Object or Root level, it will be overridden by
323    /// this value.
324    #[serde(skip_serializing_if = "Vec::is_empty")]
325    pub servers: Vec<Server>,
326}
327
328/// Describes a single operation parameter.
329/// A unique parameter is defined by a combination of a
330/// [name](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterName)
331/// and [location](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterIn).
332///
333/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterObject>.
334#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
335#[serde(rename_all = "camelCase")]
336pub struct Parameter {
337    /// The name of the parameter. Parameter names are case sensitive.
338    pub name: Str,
339
340    /// The location of the parameter. Possible values are `"query"`, `"header"`, `"path"` or `"cookie"`.
341    #[serde(rename = "in")]
342    pub location: Location,
343
344    /// A brief description of the parameter. This could contain examples of use. 
345    /// [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.
346    #[serde(skip_serializing_if = "str::is_empty")]
347    pub description: Str,
348
349    /// Determines whether this parameter is mandatory.
350    /// If the [parameter location](#parameterIn) is `"path"`, this property is **REQUIRED** and its value MUST be `true`.
351    /// Otherwise, the property MAY be included and its default value is `false`.
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub required: Option<bool>,
354
355    /// Specifies that a parameter is deprecated and SHOULD be transitioned out of usage.
356    /// Default value is `false`.
357    #[serde(skip_serializing_if = "Option::is_none")]
358    pub deprecated: Option<bool>,
359
360    // /// Sets the ability to pass empty-valued parameters.
361    // /// This is valid only for `query` parameters and allows sending a parameter with an empty value.
362    // /// Default value is `false`.
363    // /// If [`style`](#parameterStyle) is used, and if behavior is `n/a` (cannot be serialized), the value of `allowEmptyValue` SHALL be ignored.
364    // /// Use of this property is NOT RECOMMENDED, as it is likely to be removed in a later revision.
365    // #[serde(skip_serializing_if = "Option::is_none")]
366    // pub allowEmptyValue: Option<bool>,
367
368    /// Describes how the parameter value will be serialized depending on the type of the parameter
369    /// value. Default values (based on value of in): for `query` - `form`; for `path` - `simple`; for
370    /// `header` - `simple`; for cookie - `form`.
371    #[serde(skip_serializing_if = "Option::is_none")]
372    pub style: Option<ParameterStyle>,
373
374    /// When this is true, parameter values of type `array` or `object` generate separate parameters for each value of the array or key-value pair of the map. 
375    /// For other types of parameters this property has no effect. 
376    /// When [`style`] is `form`, the default value is `true`.
377    /// For all other styles, the default value is `false`.
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub explode: Option<bool>,
380
381    /// Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.2) `:/?#[]@!$&'()*+,;=` to be included without percent-encoding.
382    /// This property only applies to parameters with an `in` value of `query`.
383    /// The default value is `false`.
384    #[serde(skip_serializing_if = "Option::is_none")]
385    pub allow_reserved: Option<bool>,
386
387    /// The schema defining the type used for the parameter or a map containing the representations for the parameter.
388    #[serde(flatten, skip_serializing_if = "Option::is_none")]
389    pub representation: Option<ParameterRepresentation>,
390
391    /// Example(s) of the parameter's potential value
392    #[serde(flatten, skip_serializing_if = "Option::is_none")]
393    pub example: Option<ParameterExamples>,
394}
395
396/// The schema defining the type used for the parameter or a map containing the representations for the parameter.
397#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
398#[serde(untagged)]
399pub enum ParameterRepresentation {
400    Simple {
401        /// The schema defining the type used for the parameter.
402        schema: ComponentOrInlineSchema,
403    },
404    Content {
405        /// A map containing the representations for the parameter. The key is the media type and the value describes it. The map MUST only contain one entry.
406        content: IndexMap<Str, MediaType>,
407    }
408}
409
410/// Example(s) of the parameter's potential value
411#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
412#[serde(untagged)]
413pub enum ParameterExamples {
414    One {
415        /// Example of the parameter's potential value.
416        /// The example SHOULD match the specified schema and encoding properties if present.
417        /// The `example` field is mutually exclusive of the `examples` field. Furthermore, if referencing a `schema` that contains an example, the `example` value SHALL _override_ the example provided by the schema.
418        /// To represent examples of media types that cannot naturally be represented in JSON or YAML, a string value can contain the example with escaping where necessary.
419        example: Option<serde_json::Value>,
420    },
421    Multiple {
422        /// Examples of the parameter's potential value.
423        /// Each example SHOULD contain a value in the correct format as specified in the parameter encoding.
424        /// The `examples` field is mutually exclusive of the `example` field.
425        /// Furthermore, if referencing a `schema` that contains an example, the `examples` value SHALL _override_ the example provided by the schema.
426        examples: IndexMap<Str, ObjectOrReference<Example>>,
427    },
428}
429
430#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)]
431pub enum Type {
432    #[serde(rename = "string")]
433    String,
434    #[serde(rename = "number")]
435    Number,
436    #[serde(rename = "integer")]
437    Integer,
438    #[serde(rename = "boolean")]
439    Boolean,
440    #[serde(rename = "array")]
441    Array,
442    #[serde(rename = "object")]
443    Object,
444    #[serde(rename = "file")]
445    File,
446}
447
448#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)]
449pub enum Location {
450    #[serde(rename = "query")]
451    Query,
452    #[serde(rename = "header")]
453    Header,
454    #[serde(rename = "path")]
455    Path,
456    #[serde(rename = "formData")]
457    FormData,
458}
459
460/// Just for convenience.
461impl Default for Location {
462    fn default() -> Self {
463        Location::Query
464    }
465}
466
467#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)]
468#[serde(rename_all = "camelCase")]
469pub enum ParameterStyle {
470    Matrix,
471    Label,
472    Form,
473    Simple,
474    SpaceDelimited,
475    PipeDelimited,
476    DeepObject,
477}
478
479mod component_ser_as_ref {
480    use super::*;
481    use serde::*;
482
483    const PATH_REF_PREFIX: &str = "#/components/schemas/"; 
484
485    pub fn serialize<S: Serializer>(component: &Str, ser: S) -> Result<S::Ok, S::Error> {
486        ser.serialize_str(&(PATH_REF_PREFIX.to_string() + component))
487    }
488
489    pub fn deserialize<'de, D: Deserializer<'de>>(deser: D) -> Result<Str, D::Error> {
490        let s = String::deserialize(deser)?;
491        if let Some(s) = s.strip_prefix(PATH_REF_PREFIX) {
492            Ok(Str::Owned(s.to_string()))
493        } else {
494            Err(de::Error::custom("not a component schema reference path"))
495        }
496    }
497}
498
499/// Either a reference to a component schema
500/// or an \[inline\] schema itself.
501#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
502#[serde(untagged)]
503pub enum ComponentOrInlineSchema {
504    Component {
505        /// Name of the component schema.
506        /// 
507        /// Serialized as [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
508        /// path to the definition within the specification document
509        #[serde(rename = "$ref", serialize_with = "component_ser_as_ref::serialize", deserialize_with = "component_ser_as_ref::deserialize")]
510        name: Str
511    },
512    Inline(Schema),
513    // Add "ExtRef" variant if support for externally referenced schemas (neither inline nor components) is needed
514}
515impl ComponentOrInlineSchema {
516    /// Unwrap inlined
517    pub fn unwrap(&self) -> Option<&Schema> {
518        match self {
519            Self::Inline(s) => Some(s),
520            Self::Component{..} => None,
521        }
522    }
523}
524
525/// The Schema Object allows the definition of input and output data types.
526/// These types can be objects, but also primitives and arrays.
527/// This object is an extended subset of the
528/// [JSON Schema Specification Wright Draft 00](http://json-schema.org/).
529/// For more information about the properties, see
530/// [JSON Schema Core](https://tools.ietf.org/html/draft-wright-json-schema-00) and
531/// [JSON Schema Validation](https://tools.ietf.org/html/draft-wright-json-schema-validation-00).
532/// Unless stated otherwise, the property definitions follow the JSON Schema.
533///
534/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schemaObject>.
535#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
536#[serde(rename_all = "camelCase")]
537pub struct Schema {
538    // This is from 3.0.1; Differs for 3.1
539    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
540    // The following properties are taken directly from the JSON Schema definition and follow the same specifications:
541    // - multipleOf
542    // - maximum
543    // - exclusiveMaximum
544    // - minimum
545    // - exclusiveMinimum
546    // - maxLength
547    // - minLength
548    // - pattern (This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect)
549    // - maxItems
550    // - minItems
551    // - uniqueItems
552    // - maxProperties
553    // - minProperties
554    // - required
555    // - enum
556    //
557    // The following properties are taken from the JSON Schema definition but their definitions were adjusted to the OpenAPI Specification.
558    // - type - Value MUST be a string. Multiple types via an array are not supported.
559    // - allOf - Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard JSON Schema.
560    // - oneOf - Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard JSON Schema.
561    // - anyOf - Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard JSON Schema.
562    // - not - Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard JSON Schema.
563    // - items - Value MUST be an object and not an array. Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard JSON Schema. `items` MUST be present if the `type` is `array`.
564    // - properties - Property definitions MUST be a [Schema Object](#schemaObject) and not a standard JSON Schema (inline or referenced).
565    // - additionalProperties - Value can be boolean or object. Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard JSON Schema.
566    // - description - [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
567    // - format - See [Data Type Formats](#dataTypeFormat) for further details. While relying on JSON Schema's defined formats, the OAS offers a few additional predefined formats.
568    // - default - The default value represents what would be assumed by the consumer of the input as the value of the schema if one is not provided. Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. For example, if `type` is `string`, then `default` can be `"foo"` but cannot be `1`.
569
570    #[serde(skip_serializing_if = "str::is_empty")]
571    pub description: Str,
572
573    #[serde(skip_serializing_if = "str::is_empty")]
574    pub format: Str,
575
576    #[serde(skip_serializing_if = "Option::is_none")]
577    pub items: Option<Box<ComponentOrInlineSchema>>,
578
579    #[serde(skip_serializing_if = "IndexMap::is_empty")]
580    pub properties: IndexMap<Str, ComponentOrInlineSchema>,
581
582    #[serde(skip_serializing_if = "Option::is_none")]
583    pub read_only: Option<bool>,
584
585    #[serde(skip_serializing_if = "Option::is_none")]
586    pub write_only: Option<bool>,
587
588    #[serde(skip_serializing_if = "Option::is_none")]
589    pub nullable: Option<bool>,
590
591    /// Value can be boolean or object. Inline or referenced schema MUST be of a
592    /// [Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schemaObject)
593    /// and not a standard JSON Schema.
594    ///
595    /// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#properties>.
596    #[serde(skip_serializing_if = "Option::is_none")]
597    pub additional_properties: Option<Box<ComponentOrInlineSchema>>,
598
599    /// A free-form property to include an example of an instance for this schema.
600    /// To represent examples that cannot be naturally represented in JSON or YAML,
601    /// a string value can be used to contain the example with escaping where necessary.
602    /// NOTE: According to [spec], _Primitive data types in the OAS are based on the
603    ///       types supported by the JSON Schema Specification Wright Draft 00._
604    ///       This suggest using
605    ///       [`serde_json::Value`](https://docs.serde.rs/serde_json/value/enum.Value.html). [spec][https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types]
606    #[serde(skip_serializing_if = "Option::is_none")]
607    pub example: Option<serde_json::value::Value>,
608
609    #[serde(skip_serializing_if = "str::is_empty")]
610    pub title: Str,
611
612    /// The default value represents what would be assumed by the consumer of the input as the value
613    /// of the schema if one is not provided. Unlike JSON Schema, the value MUST conform to the
614    /// defined type for the Schema Object defined at the same level. For example, if type is
615    /// `string`, then `default` can be `"foo"` but cannot be `1`.
616    #[serde(skip_serializing_if = "Option::is_none")]
617    pub default: Option<serde_json::Value>,
618
619    /// Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard
620    /// JSON Schema.
621    #[serde(skip_serializing_if = "Vec::is_empty")]
622    pub all_of: Vec<ComponentOrInlineSchema>,
623
624    /// Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard
625    /// JSON Schema.
626    #[serde(skip_serializing_if = "Vec::is_empty")]
627    pub one_of: Vec<ComponentOrInlineSchema>,
628
629    /// Inline or referenced schema MUST be of a [Schema Object](#schemaObject) and not a standard
630    /// JSON Schema.
631    #[serde(skip_serializing_if = "Vec::is_empty")]
632    pub any_of: Vec<ComponentOrInlineSchema>,
633
634
635    // JSON Schema Validation
636    // TODO: fetch up descriptions from https://json-schema.org/draft/2020-12/json-schema-validation.html
637
638    // Any
639    
640    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
641    pub schema_type: Option<Type>,
642    #[serde(rename = "enum", skip_serializing_if = "Vec::is_empty")]
643    pub enum_values: Vec<Str>,
644    #[serde(rename = "const", skip_serializing_if = "Option::is_none")]
645    pub const_value: Option<serde_json::Value>,
646
647    // Numbers
648
649    #[serde(skip_serializing_if = "Option::is_none")]
650    pub multiple_of: Option<serde_json::Value>,
651    #[serde(skip_serializing_if = "Option::is_none")]
652    pub minimum: Option<serde_json::Value>,
653    #[serde(skip_serializing_if = "Option::is_none")]
654    pub exclusive_minimum: Option<serde_json::Value>,
655    #[serde(skip_serializing_if = "Option::is_none")]
656    pub maximum: Option<serde_json::Value>,
657    #[serde(skip_serializing_if = "Option::is_none")]
658    pub exclusive_maximum: Option<serde_json::Value>,
659
660    // Strings
661
662    #[serde(skip_serializing_if = "Option::is_none")]
663    pub max_length: Option<usize>,
664    #[serde(skip_serializing_if = "Option::is_none")]
665    pub min_length: Option<usize>,
666    #[serde(skip_serializing_if = "str::is_empty")]
667    pub pattern: Str,
668
669    // Arrays
670
671    #[serde(skip_serializing_if = "Option::is_none")]
672    pub max_items: Option<usize>,
673    #[serde(skip_serializing_if = "Option::is_none")]
674    pub min_items: Option<usize>,
675    #[serde(skip_serializing_if = "Option::is_none")]
676    pub unique_items: Option<bool>,
677
678    // Objects
679
680    #[serde(skip_serializing_if = "Option::is_none")]
681    pub max_properties: Option<usize>,
682    #[serde(skip_serializing_if = "Option::is_none")]
683    pub min_properties: Option<usize>,
684    #[serde(skip_serializing_if = "Vec::is_empty")]
685    pub required: Vec<Str>,
686    #[serde(skip_serializing_if = "IndexMap::is_empty")]
687    pub dependent_required: IndexMap<Str, Vec<Str>>,
688}
689
690/// Describes a single response from an API Operation, including design-time, static `links`
691/// to operations based on the response.
692///
693/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#responseObject>.
694#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
695pub struct Response {
696    /// A short description of the response.
697    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
698    pub description: Str,
699
700    /// Maps a header name to its definition.
701    /// [RFC7230](https://tools.ietf.org/html/rfc7230#page-22) states header names are case
702    /// insensitive. If a response header is defined with the name `"Content-Type"`, it SHALL
703    /// be ignored.
704    #[serde(skip_serializing_if = "IndexMap::is_empty")]
705    pub headers: IndexMap<Str, ObjectOrReference<Header>>,
706
707    /// A map containing descriptions of potential response payloads. The key is a media type
708    /// or [media type range](https://tools.ietf.org/html/rfc7231#appendix-D) and the value
709    /// describes it. For responses that match multiple keys, only the most specific key is
710    /// applicable. e.g. text/plain overrides text/*
711    #[serde(skip_serializing_if = "IndexMap::is_empty")]
712    pub content: IndexMap<Str, MediaType>,
713
714    /// A map of operations links that can be followed from the response. The key of the map
715    /// is a short name for the link, following the naming constraints of the names for
716    /// [Component Objects](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#componentsObject).
717    #[serde(skip_serializing_if = "IndexMap::is_empty")]
718    pub links: IndexMap<Str, ObjectOrReference<Link>>,
719    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
720}
721
722/// The Header Object follows the structure of the
723/// [Parameter Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterObject)
724/// with the following changes:
725/// 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map.
726/// 1. `in` MUST NOT be specified, it is implicitly in `header`.
727/// 1. All traits that are affected by the location MUST be applicable to a location of
728///    `header` (for example, [`style`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterStyle)).
729///
730/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#headerObject>.
731#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
732pub struct Header {
733    #[serde(skip_serializing_if = "Option::is_none")]
734    pub required: Option<bool>,
735    #[serde(skip_serializing_if = "Option::is_none")]
736    pub schema: Option<ComponentOrInlineSchema>,
737    #[serde(skip_serializing_if = "Option::is_none")]
738    #[serde(rename = "uniqueItems")]
739    pub unique_items: Option<bool>,
740    /// string, number, boolean, integer, array, file ( only for formData )
741    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
742    pub param_type: Option<Type>,
743    #[serde(skip_serializing_if = "str::is_empty")]
744    pub format: Str,
745    /// A brief description of the parameter. This could contain examples
746    /// of use.  GitHub Flavored Markdown is allowed.
747    #[serde(skip_serializing_if = "str::is_empty")]
748    pub description: Str,
749    // collectionFormat: ???
750    // default: ???
751    // maximum ?
752    // exclusiveMaximum ??
753    // minimum ??
754    // exclusiveMinimum ??
755    // maxLength ??
756    // minLength ??
757    // pattern ??
758    // maxItems ??
759    // minItems ??
760    // enum ??
761    // multipleOf ??
762    // allowEmptyValue ( for query / body params )
763}
764
765/// Describes a single request body.
766///
767/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#requestBodyObject>.
768#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
769pub struct RequestBody {
770    /// A brief description of the request body. This could contain examples of use.
771    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
772    #[serde(skip_serializing_if = "str::is_empty")]
773    pub description: Str,
774
775    /// The content of the request body. The key is a media type or
776    /// [media type range](https://tools.ietf.org/html/rfc7231#appendix-D) and the
777    /// value describes it. For requests that match multiple keys, only the most specific key
778    /// is applicable. e.g. text/plain overrides text/*
779    pub content: IndexMap<Str, MediaType>,
780
781    #[serde(skip_serializing_if = "Option::is_none")]
782    pub required: Option<bool>,
783}
784
785/// The Link object represents a possible design-time link for a response.
786///
787/// The presence of a link does not guarantee the caller's ability to successfully invoke it,
788/// rather it provides a known relationship and traversal mechanism between responses and
789/// other operations.
790///
791/// Unlike _dynamic_ links (i.e. links provided *in* the response payload), the OAS linking
792/// mechanism does not require link information in the runtime response.
793///
794/// For computing links, and providing instructions to execute them, a
795/// [runtime expression](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#runtimeExpression)
796/// is used for accessing values in an operation and using them as parameters while invoking
797/// the linked operation.
798///
799/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#linkObject>.
800#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
801pub struct Link {
802    #[serde(flatten)]
803    operation: LinkOperation,
804
805    /// A map representing parameters to pass to an operation as specified with `operationId`
806    /// or identified via `operationRef`. The key is the parameter name to be used, whereas
807    /// the value can be a constant or an expression to be evaluated and passed to the
808    /// linked operation. The parameter name can be qualified using the
809    /// [parameter location](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterIn)
810    /// `[{in}.]{name}` for operations that use the same parameter name in different
811    /// locations (e.g. path.id).
812    #[serde(skip_serializing_if = "IndexMap::is_empty")]
813    parameters: IndexMap<Str, RuntimeExpressionOrValue>,
814
815    /// A literal value or
816    /// [{expression}](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#runtimeExpression)
817    /// to use as a request body when calling the target operation.
818    #[serde(rename = "requestBody", skip_serializing_if = "Option::is_none")]
819    request_body: Option<RuntimeExpressionOrValue>,
820
821    /// A description of the link. [CommonMark syntax](http://spec.commonmark.org/) MAY be
822    /// used for rich text representation.
823    #[serde(skip_serializing_if = "str::is_empty")]
824    description: Str,
825
826    /// A server object to be used by the target operation.
827    #[serde(skip_serializing_if = "Option::is_none")]
828    server: Option<Server>,
829    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtension
830}
831
832/// Runtime expression or literal value. Used for Link `parameters` and `request_body`.
833#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
834#[serde(untagged)]
835pub enum RuntimeExpressionOrValue {
836    RuntimeExpression(Str),
837    LiteralValue(serde_json::Value),
838}
839
840/// The name of an _existing_ resolvable OAS operation, or a relative or absolute reference to an OAS operation.
841#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
842#[serde(untagged)]
843pub enum LinkOperation {
844    Id {
845        /// The name of an _existing_, resolvable OAS operation, as defined with a unique
846        /// `operationId`. This field is mutually exclusive of the `operationRef` field.
847        #[serde(rename = "operationId")]
848        operation_id: Str,
849    },
850    Ref {
851        /// A relative or absolute reference to an OAS operation. This field is mutually exclusive
852        /// of the `operationId` field, and MUST point to an
853        /// [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#operationObject).
854        /// Relative `operationRef` values MAY be used to locate an existing
855        /// [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#operationObject)
856        /// in the OpenAPI definition.
857        #[serde(rename = "operationRef")]
858        operation_ref: Str,
859    },
860}
861
862/// Each Media Type Object provides schema and examples for the media type identified by its key.
863///
864/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#media-type-object>.
865#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
866pub struct MediaType {
867    /// The schema defining the type used for the request body.
868    #[serde(skip_serializing_if = "Option::is_none")]
869    pub schema: Option<ComponentOrInlineSchema>,
870
871    /// Example of the media type.
872    #[serde(flatten, skip_serializing_if = "Option::is_none")]
873    pub examples: Option<MediaTypeExample>,
874
875    /// A map between a property name and its encoding information. The key, being the
876    /// property name, MUST exist in the schema as a property. The encoding object SHALL
877    /// only apply to `requestBody` objects when the media type is `multipart`
878    /// or `application/x-www-form-urlencoded`.
879    #[serde(skip_serializing_if = "IndexMap::is_empty")]
880    pub encoding: IndexMap<Str, Encoding>,
881}
882
883#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
884#[serde(untagged)]
885pub enum MediaTypeExample {
886    /// Example of the media type. The example object SHOULD be in the correct format as
887    /// specified by the media type. The `example` field is mutually exclusive of the
888    /// `examples` field. Furthermore, if referencing a `schema` which contains an example,
889    /// the `example` value SHALL override the example provided by the schema.
890    Example { example: serde_json::Value },
891    /// Examples of the media type. Each example object SHOULD match the media type and
892    /// specified schema if present. The `examples` field is mutually exclusive of
893    /// the `example` field. Furthermore, if referencing a `schema` which contains an
894    /// example, the `examples` value SHALL override the example provided by the schema.
895    Examples {
896        examples: IndexMap<Str, ObjectOrReference<Example>>,
897    },
898}
899
900/// A single encoding definition applied to a single schema property.
901#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
902pub struct Encoding {
903    /// The Content-Type for encoding a specific property. Default value depends on the
904    /// property type: for `string` with `format` being `binary` – `application/octet-stream`;
905    /// for other primitive types – `text/plain`; for `object` - `application/json`;
906    /// for `array` – the default is defined based on the inner type. The value can be a
907    /// specific media type (e.g. `application/json`), a wildcard media type
908    /// (e.g. `image/*`), or a comma-separated list of the two types.
909    #[serde(skip_serializing_if = "str::is_empty", rename = "contentType")]
910    pub content_type: Str,
911
912    /// A map allowing additional information to be provided as headers, for example
913    /// `Content-Disposition`.  `Content-Type` is described separately and SHALL be
914    /// ignored in this section. This property SHALL be ignored if the request body
915    /// media type is not a `multipart`.
916    #[serde(skip_serializing_if = "IndexMap::is_empty")]
917    pub headers: IndexMap<Str, ObjectOrReference<Header>>,
918
919    /// Describes how a specific property value will be serialized depending on its type.
920    /// See [Parameter Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterObject)
921    /// for details on the
922    /// [`style`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#parameterStyle)
923    /// property. The behavior follows the same values as `query` parameters, including
924    /// default values. This property SHALL be ignored if the request body media type
925    /// is not `application/x-www-form-urlencoded`.
926    #[serde(skip_serializing_if = "str::is_empty")]
927    pub style: Str,
928
929    /// When this is true, property values of type `array` or `object` generate
930    /// separate parameters for each value of the array, or key-value-pair of the map.
931    /// For other types of properties this property has no effect. When
932    /// [`style`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#encodingStyle)
933    /// is `form`, the default value is `true`. For all other styles, the default value
934    /// is `false`. This property SHALL be ignored if the request body media type is
935    /// not `application/x-www-form-urlencoded`.
936    #[serde(skip_serializing_if = "Option::is_none")]
937    pub explode: Option<bool>,
938
939    /// Determines whether the parameter value SHOULD allow reserved characters, as defined
940    /// by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.2) `:/?#[]@!$&'()*+,;=`
941    /// to be included without percent-encoding. The default value is `false`. This
942    /// property SHALL be ignored if the request body media type is
943    /// not `application/x-www-form-urlencoded`.
944    #[serde(skip_serializing_if = "Option::is_none", rename = "allowReserved")]
945    pub allow_reserved: Option<bool>,
946}
947
948/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#exampleObject>.
949#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
950pub struct Example {
951    /// Short description for the example.
952    #[serde(skip_serializing_if = "str::is_empty")]
953    pub summary: Str,
954
955    /// Long description for the example.
956    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
957    #[serde(skip_serializing_if = "str::is_empty")]
958    pub description: Str,
959    /// Embedded literal example or a URL that points to the literal example.
960    #[serde(skip_serializing_if = "Option::is_none", flatten)]
961    pub value: Option<ExampleValue>,
962
963    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
964}
965
966/// Embedded literal example or a URL that points to the literal example.
967#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
968#[serde(untagged)]
969pub enum ExampleValue {
970    Embedded {
971        /// Embedded literal example. The `value` field and `externalValue` field are mutually
972        /// exclusive. To represent examples of media types that cannot naturally represented
973        /// in JSON or YAML, use a string value to contain the example, escaping where necessary.
974        value: serde_json::Value
975    },
976    External {
977        /// A URL that points to the literal example. This provides the capability to reference
978        /// examples that cannot easily be included in JSON or YAML documents. The `value` field
979        /// and `externalValue` field are mutually exclusive.
980        #[serde(rename = "externalValue")]
981        external_value: Str
982    },
983}
984
985/// Defines a security scheme that can be used by the operations. Supported schemes are
986/// HTTP authentication, an API key (either as a header or as a query parameter),
987///OAuth2's common flows (implicit, password, application and access code) as defined
988/// in [RFC6749](https://tools.ietf.org/html/rfc6749), and
989/// [OpenID Connect Discovery](https://tools.ietf.org/html/draft-ietf-oauth-discovery-06).
990///
991/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#securitySchemeObject>.
992#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
993#[serde(tag = "type")]
994pub enum SecurityScheme {
995    #[serde(rename = "apiKey")]
996    ApiKey {
997        name: Str,
998        #[serde(rename = "in")]
999        location: Str,
1000    },
1001    #[serde(rename = "http")]
1002    Http {
1003        scheme: Str,
1004        #[serde(rename = "bearerFormat")]
1005        bearer_format: Str,
1006    },
1007    #[serde(rename = "oauth2")]
1008    OAuth2 { flows: Flows },
1009    #[serde(rename = "openIdConnect")]
1010    OpenIdConnect {
1011        #[serde(rename = "openIdConnectUrl")]
1012        open_id_connect_url: Str,
1013    },
1014}
1015
1016/// Allows configuration of the supported OAuth Flows.
1017/// See [link]
1018/// [link][https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flows-object]
1019#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
1020#[serde(rename_all = "camelCase")]
1021pub struct Flows {
1022    #[serde(skip_serializing_if = "Option::is_none")]
1023    pub implicit: Option<ImplicitFlow>,
1024    #[serde(skip_serializing_if = "Option::is_none")]
1025    pub password: Option<PasswordFlow>,
1026    #[serde(skip_serializing_if = "Option::is_none")]
1027    pub client_credentials: Option<ClientCredentialsFlow>,
1028    #[serde(skip_serializing_if = "Option::is_none")]
1029    pub authorization_code: Option<AuthorizationCodeFlow>,
1030}
1031
1032/// Configuration details for a implicit OAuth Flow
1033/// See [link]
1034/// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object)
1035#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
1036#[serde(rename_all = "camelCase")]
1037pub struct ImplicitFlow {
1038    pub authorization_url: Url,
1039    #[serde(skip_serializing_if = "Option::is_none")]
1040    pub refresh_url: Option<Url>,
1041    pub scopes: IndexMap<Str, Str>,
1042}
1043
1044/// Configuration details for a password OAuth Flow
1045/// See [link]
1046/// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object
1047#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
1048#[serde(rename_all = "camelCase")]
1049pub struct PasswordFlow {
1050    token_url: Url,
1051    #[serde(skip_serializing_if = "Option::is_none")]
1052    pub refresh_url: Option<Url>,
1053    pub scopes: IndexMap<Str, Str>,
1054}
1055
1056/// Configuration details for a client credentials OAuth Flow
1057/// See [link]
1058/// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object
1059#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
1060#[serde(rename_all = "camelCase")]
1061pub struct ClientCredentialsFlow {
1062    token_url: Url,
1063    #[serde(skip_serializing_if = "Option::is_none")]
1064    pub refresh_url: Option<Url>,
1065    pub scopes: IndexMap<Str, Str>,
1066}
1067
1068/// Configuration details for a authorization code OAuth Flow
1069/// See [link]
1070/// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object
1071#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
1072#[serde(rename_all = "camelCase")]
1073pub struct AuthorizationCodeFlow {
1074    pub authorization_url: Url,
1075    token_url: Url,
1076    #[serde(skip_serializing_if = "Option::is_none")]
1077    pub refresh_url: Option<Url>,
1078    pub scopes: IndexMap<Str, Str>,
1079}
1080
1081// TODO: Implement
1082/// A map of possible out-of band callbacks related to the parent operation. Each value in
1083/// the map is a Path Item Object that describes a set of requests that may be initiated by
1084/// the API provider and the expected responses. The key value used to identify the callback
1085/// object is an expression, evaluated at runtime, that identifies a URL to use for the
1086/// callback operation.
1087///
1088/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#callbackObject>.
1089#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
1090pub struct Callback(
1091    /// A Path Item Object used to define a callback request and expected responses.
1092    serde_json::Value, // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
1093);
1094
1095/// # [Security Requirement Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#securityRequirementObject)
1096/// Lists the required security schemes to execute this operation.
1097/// The name used for each property MUST correspond to a security scheme declared in the [Security Schemes](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsSecuritySchemes) under the [Components Object](#componentsObject).
1098///
1099/// Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a request to be authorized.
1100/// This enables support for scenarios where multiple query parameters or HTTP headers are required to convey security information.
1101///
1102/// When a list of Security Requirement Objects is defined on the [OpenAPI Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#oasObject) or [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#operationObject), only one of the Security Requirement Objects in the list needs to be satisfied to authorize the request.
1103pub type SecurityRequirement = IndexMap<Str, Vec<Str>>;
1104
1105/// Adds metadata to a single tag that is used by the
1106/// [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#operationObject).
1107/// It is not mandatory to have a Tag Object per tag defined in the Operation Object instances.
1108///
1109/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#tagObject>.
1110#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
1111pub struct Tag {
1112    /// The name of the tag.
1113    pub name: Str,
1114
1115    /// A short description for the tag.
1116    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
1117    #[serde(skip_serializing_if = "str::is_empty")]
1118    pub description: Str,
1119    // /// Additional external documentation for this tag.
1120    // #[serde(skip_serializing_if = "Option::is_none")]
1121    // pub external_docs: Option<Vec<ExternalDoc>>,
1122
1123    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
1124}
1125
1126/// Allows referencing an external resource for extended documentation.
1127///
1128/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#externalDocumentationObject>.
1129#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
1130pub struct ExternalDoc {
1131    /// The URL for the target documentation.
1132    pub url: Url,
1133
1134    /// A short description of the target documentation.
1135    /// [CommonMark syntax](http://spec.commonmark.org/) MAY be used for rich text representation.
1136    #[serde(skip_serializing_if = "str::is_empty")]
1137    pub description: Str,
1138    // TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
1139}
1140
1141#[cfg(test)]
1142mod tests {
1143    use super::*;
1144
1145    #[test]
1146    fn test_security_scheme_oauth_deser() {
1147        const IMPLICIT_OAUTH2_SAMPLE: &str = r#"{
1148          "type": "oauth2",
1149          "flows": {
1150            "implicit": {
1151              "authorizationUrl": "https://example.com/api/oauth/dialog",
1152              "scopes": {
1153                "write:pets": "modify pets in your account",
1154                "read:pets": "read your pets"
1155              }
1156            },
1157            "authorizationCode": {
1158              "authorizationUrl": "https://example.com/api/oauth/dialog",
1159              "tokenUrl": "https://example.com/api/oauth/token",
1160              "scopes": {
1161                "write:pets": "modify pets in your account",
1162                "read:pets": "read your pets"
1163              }
1164            }
1165          }
1166        }"#;
1167        let obj: SecurityScheme = serde_json::from_str(&IMPLICIT_OAUTH2_SAMPLE).unwrap();
1168        match obj {
1169            SecurityScheme::OAuth2 { flows } => {
1170                assert!(flows.implicit.is_some());
1171                let implicit = flows.implicit.unwrap();
1172                assert_eq!(
1173                    implicit.authorization_url,
1174                    Url::parse("https://example.com/api/oauth/dialog").unwrap()
1175                );
1176                assert!(implicit.scopes.contains_key("write:pets"));
1177                assert!(implicit.scopes.contains_key("read:pets"));
1178
1179                assert!(flows.authorization_code.is_some());
1180                let auth_code = flows.authorization_code.unwrap();
1181                assert_eq!(
1182                    auth_code.authorization_url,
1183                    Url::parse("https://example.com/api/oauth/dialog").unwrap()
1184                );
1185                assert_eq!(
1186                    auth_code.token_url,
1187                    Url::parse("https://example.com/api/oauth/token").unwrap()
1188                );
1189                assert!(implicit.scopes.contains_key("write:pets"));
1190                assert!(implicit.scopes.contains_key("read:pets"));
1191            }
1192            _ => assert!(false, "wrong security scheme type"),
1193        }
1194    }
1195}