restify_openapi/models/
mod.rs

1//! [OAS 3.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md) models over [schemars](https://github.com/GREsau/schemars)'s [`Schema`](https://docs.rs/schemars/latest/schemars/schema/enum.Schema.html).
2//!
3//! These models are not linked to any web framework.
4
5// schemars::Schema does not implement Eq
6#![allow(clippy::derive_partial_eq_without_eq)]
7
8use crate::models::components::Components;
9use crate::models::info::Info;
10use crate::models::paths::{ExternalDocumentation, Paths};
11use crate::models::security::SecurityRequirement;
12use crate::models::server::Server;
13use crate::models::tag::Tag;
14use indexmap::IndexMap;
15use serde::Serialize;
16use serde_json::Value;
17
18pub mod components;
19pub mod info;
20pub mod paths;
21pub mod reference_or;
22pub mod security;
23pub mod server;
24pub mod tag;
25
26pub use schemars::schema::*;
27
28#[derive(Serialize, Clone, Debug)]
29#[cfg_attr(
30  any(test, feature = "deserialize"),
31  derive(serde::Deserialize, PartialEq)
32)]
33pub enum OpenApiVersion {
34  #[serde(rename = "3.0.3")]
35  OAS3_0,
36}
37
38impl Default for OpenApiVersion {
39  fn default() -> Self {
40    Self::OAS3_0
41  }
42}
43
44/// This is the root document object of the [OpenAPI document](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#openapi-document).
45#[derive(Serialize, Clone, Debug, Default)]
46#[cfg_attr(
47  any(test, feature = "deserialize"),
48  derive(serde::Deserialize, PartialEq)
49)]
50#[serde(rename_all = "camelCase")]
51pub struct OpenApi {
52  /// This string MUST be the [semantic version number](https://semver.org/spec/v2.0.0.html) of the [OpenAPI Specification version](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#versions) that the OpenAPI document uses. The `openapi` field SHOULD be used by tooling specifications and clients to interpret the OpenAPI document. This is not related to the API [**`info.version`**](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#infoVersion) string.
53  pub openapi: OpenApiVersion,
54  /// Provides metadata about the API. The metadata MAY be used by tooling as required.
55  pub info: Info,
56  /// An array of Server Objects, which provide connectivity information to a target server. If the `servers` property is not provided, or is an empty array, the default value would be a [Server Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-object) with a [url](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#serverUrl) value of `/`.
57  pub servers: Vec<Server>,
58  /// The available paths and operations for the API.
59  pub paths: Paths,
60  /// An element to hold various schemas for the specification.
61  #[serde(skip_serializing_if = "Option::is_none")]
62  pub components: Option<Components>,
63  /// A declaration of which security mechanisms can be used across the API. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. Individual operations can override this definition. To make security optional, an empty security requirement (`{}`) can be included in the array.
64  #[serde(skip_serializing_if = "Vec::is_empty", default)]
65  pub security: Vec<SecurityRequirement>,
66  /// A list of tags used by the specification with additional metadata. The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used by the [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object) must be declared. The tags that are not declared MAY be organized randomly or based on the tools' logic. Each tag name in the list MUST be unique.
67  #[serde(skip_serializing_if = "Vec::is_empty", default)]
68  pub tags: Vec<Tag>,
69  /// Additional external documentation.
70  #[serde(skip_serializing_if = "Option::is_none")]
71  pub external_docs: Option<ExternalDocumentation>,
72  /// This object MAY be extended with [Specification Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions).
73  #[serde(
74    flatten,
75    skip_serializing_if = "IndexMap::is_empty",
76    skip_deserializing
77  )]
78  pub extensions: IndexMap<String, Value>,
79}
80
81#[cfg(test)]
82mod test {
83  #![allow(clippy::expect_used)]
84
85  use crate::models::info::Info;
86  use crate::models::paths::{Operation, OperationType, PathItem, Paths, Response, Responses};
87  use crate::models::reference_or::ReferenceOr;
88  use crate::models::server::Server;
89  use crate::models::tag::Tag;
90  use crate::models::{OpenApi, OpenApiVersion};
91  use indexmap::IndexMap;
92  use std::collections::BTreeMap;
93
94  #[test]
95  fn empty_openapi_properly_generated() {
96    let oas = OpenApi {
97      openapi: OpenApiVersion::OAS3_0,
98      info: Info {
99        title: "Test".to_string(),
100        description: Some("Description".to_string()),
101        version: "1.0.0".to_string(),
102        ..Default::default()
103      },
104      paths: Paths::default(),
105      ..Default::default()
106    };
107
108    let oas_json = serde_json::to_string_pretty(&oas).expect("Error generating json for oas");
109    assert_eq!(
110      oas_json,
111      include_str!("../../test-assets/empty-openapi.json")
112    );
113  }
114
115  #[test]
116  fn openapi_properly_generated() {
117    let oas = OpenApi {
118      openapi: OpenApiVersion::OAS3_0,
119      info: Info {
120        title: "Test".to_string(),
121        description: Some("Description".to_string()),
122        version: "1.0.0".to_string(),
123        ..Default::default()
124      },
125      servers: vec![Server {
126        url: "https://google.com".to_string(),
127        description: Some("A big search server".to_string()),
128        ..Default::default()
129      }],
130      paths: Paths {
131        paths: IndexMap::from_iter(vec![(
132          "/search".to_string(),
133          PathItem {
134            operations: IndexMap::from_iter(vec![(
135              OperationType::Get,
136              Operation {
137                tags: vec!["Search".to_string()],
138                summary: Some("I don't know what this do".to_string()),
139                operation_id: Some("get_search".to_string()),
140                responses: Responses {
141                  responses: BTreeMap::from_iter(vec![(
142                    "200".to_string(),
143                    ReferenceOr::Object(Response {
144                      description: "A search thingy".to_string(),
145                      ..Default::default()
146                    }),
147                  )]),
148                  ..Default::default()
149                },
150                ..Default::default()
151              },
152            )]),
153            ..Default::default()
154          },
155        )]),
156        ..Default::default()
157      },
158      tags: vec![Tag {
159        name: "Search".to_string(),
160        ..Default::default()
161      }],
162      ..Default::default()
163    };
164
165    let oas_json = serde_json::to_string_pretty(&oas).expect("Error generating json for oas");
166    assert_eq!(oas_json, include_str!("../../test-assets/openapi.json"));
167  }
168}