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}