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}