1use anyhow::{anyhow, Result};
2use clap::{Args, Subcommand};
3
4use crate::cli_presentation::CliPresentation;
5use crate::commands::OutputFormat;
6use romm_api::client::RommClient;
7
8#[derive(Args, Debug)]
10#[command(after_help = "Examples:\n \
11 romm-cli api call GET /api/platforms\n \
12 romm-cli --json api call GET /api/roms --query limit=10")]
13pub struct ApiCommand {
14 #[command(subcommand)]
15 pub action: Option<ApiAction>,
16
17 pub method: Option<String>,
19
20 pub path: Option<String>,
22
23 #[arg(long = "query", global = true)]
25 pub query: Vec<String>,
26
27 #[arg(long, global = true)]
29 pub data: Option<String>,
30}
31
32#[derive(Subcommand, Debug)]
33pub enum ApiAction {
34 Call {
36 method: String,
38 path: String,
40 },
41 Get {
43 path: String,
45 },
46 Post {
48 path: String,
50 },
51}
52
53pub async fn handle(
54 cmd: ApiCommand,
55 client: &RommClient,
56 presentation: CliPresentation,
57) -> Result<()> {
58 let format = presentation.format;
59 let (method, path) = match cmd.action {
60 Some(ApiAction::Call { method, path }) => (method, path),
61 Some(ApiAction::Get { path }) => ("GET".to_string(), path),
62 Some(ApiAction::Post { path }) => ("POST".to_string(), path),
63 None => {
64 let m = cmd
65 .method
66 .ok_or_else(|| anyhow!("Method is required (e.g. 'api call GET /api/roms')"))?;
67 let p = cmd
68 .path
69 .ok_or_else(|| anyhow!("Path is required (e.g. 'api call GET /api/roms')"))?;
70 (m, p)
71 }
72 };
73
74 let mut query_pairs = Vec::new();
75 for q in &cmd.query {
76 if let Some((k, v)) = q.split_once('=') {
77 query_pairs.push((k.to_string(), v.to_string()));
78 } else {
79 eprintln!(
80 "warning: ignoring malformed --query value {:?}; expected key=value",
81 q
82 );
83 }
84 }
85
86 let body = if let Some(data) = &cmd.data {
87 Some(serde_json::from_str(data)?)
88 } else {
89 None
90 };
91
92 let value = client
93 .request_json(&method, &path, &query_pairs, body)
94 .await?;
95
96 match format {
97 OutputFormat::Json => {
98 println!("{}", serde_json::to_string_pretty(&value)?);
99 }
100 OutputFormat::Text => {
101 println!("{}", serde_json::to_string_pretty(&value)?);
102 }
103 }
104 Ok(())
105}