casting_cli/
api.rs

1/// API specification fetching and formatting
2
3/// Fetch and parse OpenAPI spec from URL
4pub 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
30/// Convert OpenAPI spec to help text format
31pub fn format_api_spec_as_help(spec: &openapiv3::OpenAPI) -> String {
32    let mut help = String::new();
33
34    // API Info
35    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    // Endpoints
42    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                    // Parameters
63                    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) = &parameter_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}