Skip to main content

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        #[clap(
42            short,
43            long,
44            required = false,
45            help = "Input data for the request body (can be used with -v) Example: -o 'lines,34-35' to print lines 34 to 35 of the response body' or -o 'lines' to print all lines of the response body'"
46        )]
47        output: Option<String>,
48    },
49
50    #[command(about = "Running collections endpoints")]
51    Run {
52        collection: String,
53        endpoint: String,
54
55        #[clap(short, long, default_value = "false")]
56        verbose: bool,
57
58        #[clap(short, long, required = false, default_value = "false")]
59        stream: bool,
60
61        #[clap(short, long, required = false)]
62        output: Option<String>,
63    },
64
65    #[command(about = "Print request URL with headers and body")]
66    Url {
67        collection: String,
68        endpoint: String,
69    },
70
71    #[command(about = "Run tests")]
72    Test { collection: String },
73}
74
75impl fmt::Display for Commands {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        match self {
78            Commands::List {
79                col,
80                endpoint,
81                quiet,
82                verbose,
83            } => write!(
84                f,
85                "List Command: {} - {} - {} - {}",
86                col, endpoint, quiet, verbose
87            ),
88            Commands::Man { command } => write!(f, "Man Command: {}", command),
89            Commands::Req {
90                command,
91                verbose,
92                stream,
93                output,
94            } => {
95                write!(
96                    f,
97                    "Req Command: {} (verbose: {}) (stream: {}) (output: {:?})",
98                    command, verbose, stream, output
99                )
100            }
101            Commands::Run {
102                collection,
103                endpoint,
104                verbose,
105                stream,
106                output,
107            } => {
108                write!(
109                    f,
110                    "Run Command: collection: '{}', endpoint: '{}', verbose: {}, stream: {}, output: {:?}",
111                    collection, endpoint, verbose, stream, output
112                )
113            }
114            Commands::Url {
115                collection,
116                endpoint,
117            } => {
118                write!(
119                    f,
120                    "Url Command: collection: '{}', endpoint: '{}'",
121                    collection, endpoint
122                )
123            }
124            Commands::Test { collection } => {
125                write!(f, "Test Command: collection: '{}'", collection)
126            }
127        }
128    }
129}
130
131impl Commands {
132    pub async fn run_url(
133        &self,
134        collection: &str,
135        endpoint: &str,
136    ) -> Result<(), Box<dyn std::error::Error>> {
137        let command = ManagerCommands::get_endpoint_command(collection, endpoint)
138            .await
139            .ok_or("Endpoint not found")?;
140
141        let data = command.get_data();
142
143        let headers_url = data
144            .headers
145            .iter()
146            .map(|(key, value)| format!("-H \"{}: {}\"", key, value))
147            .collect::<Vec<_>>()
148            .join(" ");
149
150        let body_flag = if !data.body.is_empty() {
151            format!("-b '{}'", data.body)
152        } else {
153            String::new()
154        };
155
156        let url = format!(
157            "{} '{}' {} {}",
158            command.to_string().to_lowercase(),
159            data.url,
160            headers_url,
161            body_flag
162        );
163        println!("coman req -v {}", url);
164
165        Ok(())
166    }
167
168    pub async fn run_request(
169        &self,
170        collection: &str,
171        endpoint: &str,
172        verbose: &bool,
173        stdin_input: &Vec<u8>,
174        stream: &bool,
175        output: &Option<String>,
176    ) -> Result<(), Box<dyn std::error::Error>> {
177        if *verbose {
178            println!(
179                "Running collection '{}' with endpoint '{}'",
180                collection, endpoint
181            );
182        }
183
184        let command = ManagerCommands::get_endpoint_command(collection, endpoint)
185            .await
186            .ok_or("Endpoint not found")?;
187
188        command
189            .run(*verbose, stdin_input.to_owned(), *stream, output)
190            .await
191    }
192
193    pub async fn run(&self, stdin_input: Vec<u8>) -> Result<(), Box<dyn std::error::Error>> {
194        match self {
195            Commands::List {
196                col,
197                endpoint,
198                quiet,
199                verbose,
200            } => {
201                ManagerCommands::List {
202                    col: col.to_owned(),
203                    endpoint: endpoint.to_owned(),
204                    verbose: *verbose,
205                    quiet: *quiet,
206                }
207                .run()
208                .await
209            }
210            Commands::Man { command } => command.run().await,
211            Commands::Req {
212                command,
213                verbose,
214                stream,
215                output,
216            } => command.run(*verbose, stdin_input, *stream, output).await,
217            Commands::Run {
218                collection,
219                endpoint,
220                verbose,
221                stream,
222                output,
223            } => {
224                self.run_request(collection, endpoint, verbose, &stdin_input, stream, output)
225                    .await
226            }
227            Commands::Url {
228                collection,
229                endpoint,
230            } => self.run_url(collection, endpoint).await,
231            Commands::Test { collection } => self.run_tests(collection).await,
232        }
233    }
234}