1pub fn fetch_api_spec(spec_url: &str) -> anyhow::Result<openapiv3::OpenAPI> {
5 println!("🌐 Fetching API spec from: {}", spec_url);
6
7 let response = reqwest::blocking::get(spec_url)?;
8 if !response.status().is_success() {
9 anyhow::bail!("Failed to fetch spec: HTTP {}", response.status());
10 }
11
12 let spec_text = response.text()?;
13 let spec: openapiv3::OpenAPI = serde_json::from_str(&spec_text).or_else(|e1| {
14 serde_yaml::from_str(&spec_text).map_err(|e2| {
15 anyhow::anyhow!(
16 "Failed to parse API spec. This tool supports OpenAPI v3 only.\n\
17 JSON parse error: {}\n\
18 YAML parse error: {}\n\
19 Note: Swagger v2 is not supported. Please use OpenAPI v3 spec.",
20 e1,
21 e2
22 )
23 })
24 })?;
25
26 println!("✅ Successfully parsed OpenAPI v{} spec", spec.openapi);
27 Ok(spec)
28}
29
30pub fn format_api_spec_as_help(spec: &openapiv3::OpenAPI) -> String {
32 let mut help = String::new();
33
34 help.push_str(&format!("API: {}\n", spec.info.title));
36 if let Some(desc) = &spec.info.description {
37 help.push_str(&format!("Description: {}\n", desc));
38 }
39 help.push_str(&format!("Version: {}\n\n", spec.info.version));
40
41 help.push_str("Available Endpoints:\n\n");
43
44 for (path, path_item) in &spec.paths.paths {
45 if let openapiv3::ReferenceOr::Item(item) = path_item {
46 for (method, operation) in [
47 ("GET", &item.get),
48 ("POST", &item.post),
49 ("PUT", &item.put),
50 ("DELETE", &item.delete),
51 ("PATCH", &item.patch),
52 ] {
53 if let Some(op) = operation {
54 help.push_str(&format!("{} {}\n", method, path));
55 if let Some(summary) = &op.summary {
56 help.push_str(&format!(" Summary: {}\n", summary));
57 }
58 if let Some(desc) = &op.description {
59 help.push_str(&format!(" Description: {}\n", desc));
60 }
61
62 if !op.parameters.is_empty() {
64 help.push_str(" Parameters:\n");
65 for param_ref in &op.parameters {
66 if let openapiv3::ReferenceOr::Item(param) = param_ref {
67 match param {
68 openapiv3::Parameter::Query { parameter_data, .. }
69 | openapiv3::Parameter::Path { parameter_data, .. }
70 | openapiv3::Parameter::Header { parameter_data, .. } => {
71 let required = if parameter_data.required {
72 " (required)"
73 } else {
74 ""
75 };
76 help.push_str(&format!(
77 " - {}{}\n",
78 parameter_data.name, required
79 ));
80 if let Some(desc) = ¶meter_data.description {
81 help.push_str(&format!(" {}\n", desc));
82 }
83 }
84 _ => {}
85 }
86 }
87 }
88 }
89
90 help.push('\n');
91 }
92 }
93 }
94 }
95
96 help
97}