pub fn generate(output: Option<&str>, format: &str) -> anyhow::Result<()> {
let path = output.unwrap_or("openapi.json");
let output_path = if path.ends_with(".yaml") || path.ends_with(".yml") {
path.to_string()
} else {
format!("{}.{}", path.trim_end_matches(".json"), format)
};
println!(
"{} Generating OpenAPI spec → {output_path}",
console::style("openapi:generate").green().bold()
);
println!(
" {} This command requires your application to call the OpenAPI generator.\n",
console::style("info:").yellow()
);
println!(" Add the following in your main.rs:\n");
println!(" use rok_openapi::OpenApiBuilder;\n");
println!(" let spec = OpenApiBuilder::new(\"My API\", \"1.0.0\")\n");
println!(" .server(\"http://localhost:3000\", \"Development\")\n");
println!(" .build();\n");
println!(" let json = spec.to_json().unwrap();\n");
println!(" std::fs::write(\"{output_path}\", json).unwrap();");
Ok(())
}
pub fn serve(port: Option<u16>) -> anyhow::Result<()> {
let listen_port = port.unwrap_or(3001);
println!(
"{} Starting OpenAPI preview server on http://localhost:{listen_port}",
console::style("openapi:serve").green().bold()
);
println!(
" {} This command is a placeholder.\n",
console::style("note:").yellow()
);
println!(" Run your app with rok dev and visit /docs for Swagger UI.");
Ok(())
}
pub fn validate(file: Option<&str>) -> anyhow::Result<()> {
let target = file.unwrap_or("openapi.json");
let content = match std::fs::read_to_string(target) {
Ok(c) => c,
Err(e) => {
anyhow::bail!("Cannot read {target}: {e}");
}
};
match serde_json::from_str::<serde_json::Value>(&content) {
Ok(val) => {
let openapi_version = val
.get("openapi")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let title = val
.get("info")
.and_then(|i| i.get("title"))
.and_then(|t| t.as_str())
.unwrap_or("Untitled");
let paths = val
.get("paths")
.map(|p| p.as_object().map(|o| o.len()).unwrap_or(0))
.unwrap_or(0);
println!(
"{} {target} is valid JSON (OpenAPI {openapi_version}, \"{title}\", {paths} path(s))",
console::style("✓").green().bold()
);
}
Err(e) => {
anyhow::bail!("Invalid JSON: {e}");
}
}
if let Ok(yaml) = serde_yaml::from_str::<serde_json::Value>(&content) {
if yaml.get("openapi").is_some() {
println!(
" {} Also valid as YAML.",
console::style("i").cyan().bold()
);
}
}
Ok(())
}