coman/cli/
commands.rs

1use std::fmt;
2
3use clap::Subcommand;
4
5use crate::cli::{manager::ManagerCommands, request::RequestCommands};
6
7#[derive(Subcommand)]
8pub enum Commands {
9    #[command(about = "List APIs Collections")]
10    List {
11        #[clap(short = 'c', long = "col", default_value = "", required = false)]
12        col: String,
13
14        #[clap(short = 'e', long = "endpoint", default_value = "", required = false)]
15        endpoint: String,
16
17        #[clap(short = 'q', long = "quiet", default_value = "false")]
18        quiet: bool,
19
20        #[clap(short, long, default_value = "false")]
21        verbose: bool,
22    },
23
24    #[command(about = "Managing APIs")]
25    Man {
26        #[command(subcommand)]
27        command: ManagerCommands,
28    },
29
30    #[command(about = "Sending requests")]
31    Req {
32        #[command(subcommand)]
33        command: RequestCommands,
34
35        #[clap(short, long, default_value = "false")]
36        verbose: bool,
37
38        #[clap(short, long, required = false, default_value = "false")]
39        stream: bool,
40    },
41
42    #[command(about = "Running collections endpoints")]
43    Run {
44        collection: String,
45        endpoint: String,
46
47        #[clap(short, long, default_value = "false")]
48        verbose: bool,
49
50        #[clap(short, long, required = false, default_value = "false")]
51        stream: bool,
52    },
53
54    #[command(about = "Print request URL with headers and body")]
55    Url {
56        collection: String,
57        endpoint: String,
58    },
59
60    #[command(about = "Run tests")]
61    Test { collection: String },
62}
63
64impl fmt::Display for Commands {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        match self {
67            Commands::List {
68                col,
69                endpoint,
70                quiet,
71                verbose,
72            } => write!(
73                f,
74                "List Command: {} - {} - {} - {}",
75                col, endpoint, quiet, verbose
76            ),
77            Commands::Man { command } => write!(f, "Man Command: {}", command),
78            Commands::Req {
79                command,
80                verbose,
81                stream,
82            } => {
83                write!(
84                    f,
85                    "Req Command: {} (verbose: {}) (stream: {})",
86                    command, verbose, stream
87                )
88            }
89            Commands::Run {
90                collection,
91                endpoint,
92                verbose,
93                stream,
94            } => {
95                write!(
96                    f,
97                    "Run Command: collection: '{}', endpoint: '{}', verbose: {}, stream: {}",
98                    collection, endpoint, verbose, stream
99                )
100            }
101            Commands::Url {
102                collection,
103                endpoint,
104            } => {
105                write!(
106                    f,
107                    "Url Command: collection: '{}', endpoint: '{}'",
108                    collection, endpoint
109                )
110            }
111            Commands::Test { collection } => {
112                write!(f, "Test Command: collection: '{}'", collection)
113            }
114        }
115    }
116}
117
118impl Commands {
119    pub fn run_url(
120        &self,
121        collection: &str,
122        endpoint: &str,
123    ) -> Result<(), Box<dyn std::error::Error>> {
124        let command = ManagerCommands::get_endpoint_command(collection, endpoint)
125            .ok_or_else(|| format!("Endpoint not found: {}/{}", collection, endpoint))?;
126
127        let data = command.get_data();
128
129        let headers_url = data
130            .headers
131            .iter()
132            .map(|(key, value)| format!("-H \"{}: {}\"", key, value))
133            .collect::<Vec<_>>()
134            .join(" ");
135
136        let body_flag = if !data.body.is_empty() {
137            format!("-b '{}'", data.body)
138        } else {
139            String::new()
140        };
141
142        let url = format!(
143            "{} '{}' {} {}",
144            command.to_string().to_lowercase(),
145            data.url,
146            headers_url,
147            body_flag
148        );
149        println!("coman req -v {}", url);
150
151        Ok(())
152    }
153
154    pub async fn run_request(
155        &self,
156        collection: &str,
157        endpoint: &str,
158        verbose: &bool,
159        stdin_input: &Vec<u8>,
160        stream: &bool,
161    ) -> Result<(), Box<dyn std::error::Error>> {
162        if *verbose {
163            println!(
164                "Running collection '{}' with endpoint '{}'",
165                collection, endpoint
166            );
167        }
168
169        let command = ManagerCommands::get_endpoint_command(collection, endpoint);
170
171        if let Some(cmd) = command {
172            cmd.run(*verbose, stdin_input.to_owned(), *stream).await
173        } else {
174            Err(format!("Endpoint not found: {} - {}", collection, endpoint).into())
175        }
176    }
177
178    pub async fn run(&self, stdin_input: Vec<u8>) -> Result<(), Box<dyn std::error::Error>> {
179        match self {
180            Commands::List {
181                col,
182                endpoint,
183                quiet,
184                verbose,
185            } => ManagerCommands::List {
186                col: col.to_owned(),
187                endpoint: endpoint.to_owned(),
188                verbose: *verbose,
189                quiet: *quiet,
190            }
191            .run(),
192            Commands::Man { command } => command.run(),
193            Commands::Req {
194                command,
195                verbose,
196                stream,
197            } => command.run(*verbose, stdin_input, *stream).await,
198            Commands::Run {
199                collection,
200                endpoint,
201                verbose,
202                stream,
203            } => {
204                self.run_request(collection, endpoint, verbose, &stdin_input, stream)
205                    .await
206            }
207            Commands::Url {
208                collection,
209                endpoint,
210            } => self.run_url(collection, endpoint),
211            Commands::Test { collection } => self.run_tests(collection).await,
212        }
213    }
214}