1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct OpenApiInfo {
11 pub title: String,
12 pub version: String,
13 pub description: String,
14}
15
16#[allow(dead_code)]
18#[derive(Debug, Clone)]
19pub struct OpenApiParam {
20 pub name: String,
21 pub r#in: String,
22 pub required: bool,
23 pub schema_type: String,
24}
25
26#[allow(dead_code)]
28#[derive(Debug, Clone)]
29pub struct OpenApiPath {
30 pub path: String,
31 pub method: String,
32 pub summary: String,
33 pub parameters: Vec<OpenApiParam>,
34 pub response_schema: String,
35}
36
37#[allow(dead_code)]
39#[derive(Debug, Clone)]
40pub struct OpenApiDoc {
41 pub info: OpenApiInfo,
42 pub paths: Vec<OpenApiPath>,
43}
44
45#[allow(dead_code)]
47pub fn new_openapi_doc(title: &str, version: &str) -> OpenApiDoc {
48 OpenApiDoc {
49 info: OpenApiInfo {
50 title: title.to_string(),
51 version: version.to_string(),
52 description: String::new(),
53 },
54 paths: Vec::new(),
55 }
56}
57
58#[allow(dead_code)]
60pub fn add_path(doc: &mut OpenApiDoc, path: &str, method: &str, summary: &str) -> usize {
61 doc.paths.push(OpenApiPath {
62 path: path.to_string(),
63 method: method.to_string(),
64 summary: summary.to_string(),
65 parameters: Vec::new(),
66 response_schema: "object".to_string(),
67 });
68 doc.paths.len() - 1
69}
70
71#[allow(dead_code)]
73pub fn add_param(
74 doc: &mut OpenApiDoc,
75 path_idx: usize,
76 name: &str,
77 location: &str,
78 required: bool,
79 schema_type: &str,
80) {
81 if path_idx < doc.paths.len() {
82 doc.paths[path_idx].parameters.push(OpenApiParam {
83 name: name.to_string(),
84 r#in: location.to_string(),
85 required,
86 schema_type: schema_type.to_string(),
87 });
88 }
89}
90
91#[allow(dead_code)]
93pub fn export_openapi_json(doc: &OpenApiDoc) -> String {
94 let mut paths_json = String::new();
95 for (i, p) in doc.paths.iter().enumerate() {
96 let params: Vec<String> = p
97 .parameters
98 .iter()
99 .map(|param| {
100 format!(
101 r#"{{"name":"{}","in":"{}","required":{},"schema":{{"type":"{}"}}}}"#,
102 param.name, param.r#in, param.required, param.schema_type
103 )
104 })
105 .collect();
106 let params_arr = format!("[{}]", params.join(","));
107 let path_entry = format!(
108 r#""{}":{{"{}": {{"summary":"{}","parameters":{},"responses":{{"200":{{"description":"OK"}}}}}}}}"#,
109 p.path, p.method, p.summary, params_arr
110 );
111 if i > 0 {
112 paths_json.push(',');
113 }
114 paths_json.push_str(&path_entry);
115 }
116 format!(
117 r#"{{"openapi":"3.0.0","info":{{"title":"{}","version":"{}"}},"paths":{{{}}}}}"#,
118 doc.info.title, doc.info.version, paths_json
119 )
120}
121
122#[allow(dead_code)]
124pub fn path_count(doc: &OpenApiDoc) -> usize {
125 doc.paths.len()
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn new_doc_title() {
134 let doc = new_openapi_doc("My API", "1.0");
135 assert_eq!(doc.info.title, "My API");
136 }
137
138 #[test]
139 fn add_path_increases_count() {
140 let mut doc = new_openapi_doc("API", "1.0");
141 add_path(&mut doc, "/users", "get", "List users");
142 assert_eq!(path_count(&doc), 1);
143 }
144
145 #[test]
146 fn export_contains_openapi_version() {
147 let doc = new_openapi_doc("API", "1.0");
148 let s = export_openapi_json(&doc);
149 assert!(s.contains("3.0.0"));
150 }
151
152 #[test]
153 fn export_contains_title() {
154 let doc = new_openapi_doc("My API", "1.0");
155 let s = export_openapi_json(&doc);
156 assert!(s.contains("My API"));
157 }
158
159 #[test]
160 fn export_contains_path() {
161 let mut doc = new_openapi_doc("API", "1.0");
162 add_path(&mut doc, "/users", "get", "Get users");
163 let s = export_openapi_json(&doc);
164 assert!(s.contains("/users"));
165 }
166
167 #[test]
168 fn add_param_to_path() {
169 let mut doc = new_openapi_doc("API", "1.0");
170 let idx = add_path(&mut doc, "/user", "get", "Get user");
171 add_param(&mut doc, idx, "id", "query", true, "integer");
172 assert_eq!(doc.paths[0].parameters.len(), 1);
173 }
174
175 #[test]
176 fn param_in_export() {
177 let mut doc = new_openapi_doc("API", "1.0");
178 let idx = add_path(&mut doc, "/user", "get", "Get user");
179 add_param(&mut doc, idx, "id", "query", true, "integer");
180 let s = export_openapi_json(&doc);
181 assert!(s.contains("\"id\""));
182 }
183
184 #[test]
185 fn invalid_path_idx_ignored() {
186 let mut doc = new_openapi_doc("API", "1.0");
187 add_param(&mut doc, 99, "x", "query", false, "string");
188 assert_eq!(path_count(&doc), 0);
189 }
190
191 #[test]
192 fn empty_paths_json() {
193 let doc = new_openapi_doc("API", "1.0");
194 let s = export_openapi_json(&doc);
195 assert!(s.contains("paths"));
196 }
197
198 #[test]
199 fn version_in_export() {
200 let doc = new_openapi_doc("API", "2.5.0");
201 let s = export_openapi_json(&doc);
202 assert!(s.contains("2.5.0"));
203 }
204}