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 #[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 #[serde(flatten, skip_serializing_if = "HashMap::is_empty")]
50 pub x_fields: HashMap<String, Value>,
51
52 #[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 #[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}