1use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct OpenApiPath {
11 pub path: String,
13 pub method: String,
15 pub operation: OpenApiOperation,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
21pub struct OpenApiOperation {
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub summary: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub description: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub operation_id: Option<String>,
31 #[serde(default, skip_serializing_if = "Vec::is_empty")]
33 pub tags: Vec<String>,
34 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
36 pub deprecated: bool,
37 #[serde(default, skip_serializing_if = "Vec::is_empty")]
39 pub parameters: Vec<OpenApiParameter>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub request_body: Option<Value>,
43 #[serde(default)]
45 pub responses: serde_json::Map<String, Value>,
46 #[serde(flatten)]
48 pub extra: serde_json::Map<String, Value>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53pub struct OpenApiParameter {
54 pub name: String,
56 #[serde(rename = "in")]
58 pub location: String,
59 #[serde(default)]
61 pub required: bool,
62 #[serde(default)]
64 pub schema: Value,
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub description: Option<String>,
68 #[serde(flatten)]
70 pub extra: serde_json::Map<String, Value>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
75pub struct OpenApiSchema {
76 pub name: String,
78 pub schema: Value,
80}
81
82impl OpenApiPath {
83 pub fn new(path: impl Into<String>, method: impl Into<String>) -> Self {
85 Self {
86 path: path.into(),
87 method: method.into().to_lowercase(),
88 operation: OpenApiOperation::default(),
89 }
90 }
91
92 pub fn with_operation(mut self, operation: OpenApiOperation) -> Self {
94 self.operation = operation;
95 self
96 }
97}
98
99impl Default for OpenApiOperation {
100 fn default() -> Self {
101 Self {
102 summary: None,
103 description: None,
104 operation_id: None,
105 tags: Vec::new(),
106 deprecated: false,
107 parameters: Vec::new(),
108 request_body: None,
109 responses: serde_json::Map::new(),
110 extra: serde_json::Map::new(),
111 }
112 }
113}
114
115impl OpenApiOperation {
116 pub fn new(summary: impl Into<String>) -> Self {
118 Self {
119 summary: Some(summary.into()),
120 ..Default::default()
121 }
122 }
123
124 pub fn with_id(mut self, id: impl Into<String>) -> Self {
126 self.operation_id = Some(id.into());
127 self
128 }
129
130 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
132 self.description = Some(desc.into());
133 self
134 }
135
136 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
138 self.tags.push(tag.into());
139 self
140 }
141
142 pub fn with_tags(mut self, tags: impl IntoIterator<Item = impl Into<String>>) -> Self {
144 self.tags.extend(tags.into_iter().map(|t| t.into()));
145 self
146 }
147
148 pub fn deprecated(mut self) -> Self {
150 self.deprecated = true;
151 self
152 }
153
154 pub fn with_parameter(mut self, param: OpenApiParameter) -> Self {
156 self.parameters.push(param);
157 self
158 }
159
160 pub fn with_response(mut self, status: impl Into<String>, response: Value) -> Self {
162 self.responses.insert(status.into(), response);
163 self
164 }
165}
166
167impl OpenApiParameter {
168 pub fn path(name: impl Into<String>) -> Self {
170 Self {
171 name: name.into(),
172 location: "path".to_string(),
173 required: true, schema: serde_json::json!({"type": "string"}),
175 description: None,
176 extra: serde_json::Map::new(),
177 }
178 }
179
180 pub fn query(name: impl Into<String>, required: bool) -> Self {
182 Self {
183 name: name.into(),
184 location: "query".to_string(),
185 required,
186 schema: serde_json::json!({"type": "string"}),
187 description: None,
188 extra: serde_json::Map::new(),
189 }
190 }
191
192 pub fn header(name: impl Into<String>, required: bool) -> Self {
194 Self {
195 name: name.into(),
196 location: "header".to_string(),
197 required,
198 schema: serde_json::json!({"type": "string"}),
199 description: None,
200 extra: serde_json::Map::new(),
201 }
202 }
203
204 pub fn with_schema(mut self, schema: Value) -> Self {
206 self.schema = schema;
207 self
208 }
209
210 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
212 self.description = Some(desc.into());
213 self
214 }
215}
216
217impl OpenApiSchema {
218 pub fn new(name: impl Into<String>, schema: Value) -> Self {
220 Self {
221 name: name.into(),
222 schema,
223 }
224 }
225}