sw4rm_rs/
spec.rs

1use std::collections::HashMap;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use semver::{Version, VersionReq};
5
6use crate::{
7    RefOr,
8    shared::{
9        ExternalDocumentation,
10        Info,
11        Parameter,
12        PathItem,
13        Response,
14        Schema,
15        SecurityScheme,
16        Tag,
17    },
18    openapi_v2::Scheme,
19    openapi_v3_0::{
20        Server,
21        Components,
22    }
23};
24
25#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)]
26#[serde(default, rename_all = "camelCase")]
27pub struct Spec {
28    // MARK: Common Fields
29
30    #[serde(alias = "swagger", alias = "openapi")]
31    pub spec_version: String,
32    pub info: Info,
33    #[serde(skip_serializing_if = "Vec::is_empty")]
34    pub servers: Vec<Server>,
35    #[serde(skip_serializing_if = "HashMap::is_empty")]
36    pub paths: HashMap<String, RefOr<PathItem>>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub components: Option<Components>,
39    #[serde(skip_serializing_if = "Vec::is_empty")]
40    pub security: Vec<HashMap<String, Vec<String>>>,
41    #[serde(skip_serializing_if = "Vec::is_empty")]
42    pub tags: Vec<Tag>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub external_docs: Option<ExternalDocumentation>,
45
46    /// Allows extensions to the Swagger Schema. The field name MUST begin with x-, for example,
47    /// x-internal-id. The value can be null, a primitive, an array or an object. See Vendor
48    /// Extensions for further details.
49    #[serde(flatten, skip_serializing_if = "HashMap::is_empty")]
50    pub x_fields: HashMap<String, Value>,
51
52    // MARK: OpenAPI v2 Fields
53
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub host: Option<String>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub base_path: Option<String>,
58    #[serde(skip_serializing_if = "Vec::is_empty")]
59    pub schemes: Vec<Scheme>,
60    #[serde(skip_serializing_if = "Vec::is_empty")]
61    pub consumes: Vec<String>,
62    #[serde(skip_serializing_if = "Vec::is_empty")]
63    pub produces: Vec<String>,
64    #[serde(skip_serializing_if = "HashMap::is_empty")]
65    pub definitions: HashMap<String, RefOr<Schema>>,
66    #[serde(skip_serializing_if = "HashMap::is_empty")]
67    pub parameters: HashMap<String, RefOr<Parameter>>,
68    #[serde(skip_serializing_if = "HashMap::is_empty")]
69    pub responses: HashMap<String, RefOr<Response>>,
70    #[serde(skip_serializing_if = "HashMap::is_empty")]
71    pub security_definitions: HashMap<String, RefOr<SecurityScheme>>,
72
73    // MARK: OpenAPI v3.1 Fields
74
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub json_schema_dialect: Option<String>,
77    #[serde(skip_serializing_if = "HashMap::is_empty")]
78    pub webhooks: HashMap<String, RefOr<PathItem>>,
79}
80
81impl Spec {
82    pub(crate) fn semver_check(&self, version: &str) -> bool {
83        let spec_version = Version::parse(self.spec_version.replace("2.0", "2.0.0").as_str()).unwrap();
84        let version = VersionReq::parse(version).unwrap();
85        version.matches(&spec_version)
86    }
87
88    pub fn schemas(&self) -> HashMap<String, RefOr<Schema>> {
89        self.components
90            .as_ref()
91            .map(|c| c.schemas.clone())
92            .unwrap_or(self.definitions.clone())
93            .clone()
94    }
95}