1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "mrapids")]
6#[command(about = "Your OpenAPI, but executable", long_about = None)]
7#[command(version)]
8#[command(before_help = crate::core::banner::get_help_header())]
9#[command(after_help = get_help_footer())]
10#[command(override_help = get_grouped_help())]
11pub struct Args {
12 #[command(subcommand)]
13 pub command: Commands,
14
15 #[arg(long, global = true, value_name = "ENV")]
17 pub env: Option<String>,
18
19 #[arg(long = "output-format", global = true, value_name = "FORMAT")]
21 pub output_format: Option<String>,
22
23 #[arg(long, short = 'q', global = true)]
25 pub quiet: bool,
26
27 #[arg(long, short = 'v', global = true)]
29 pub verbose: bool,
30
31 #[arg(long, global = true)]
33 pub trace: bool,
34
35 #[arg(long, global = true)]
37 pub no_color: bool,
38}
39
40#[derive(Subcommand)]
41pub enum Commands {
42 #[command(display_order = 1)]
45 Init(InitCommand),
46
47 #[command(alias = "search", alias = "discover", display_order = 2)]
49 Explore(ExploreCommand),
50
51 #[command(display_order = 3)]
53 Show(ShowCommand),
54
55 #[command(display_order = 4)]
57 Validate(ValidateCommand),
58
59 #[command(display_order = 5)]
62 Run(RunCommand),
63
64 #[command(display_order = 6)]
66 Test(TestCommand),
67
68 #[command(display_order = 7)]
70 List(ListCommand),
71
72 #[command(alias = "generate", display_order = 8)]
75 Gen(GenCommand),
76
77 #[command(display_order = 9)]
79 Flatten(FlattenCommand),
80
81 #[command(display_order = 10)]
84 Collection(CollectionCommand),
85
86 #[command(alias = "tests-init", display_order = 11)]
88 SetupTests(SetupTestsCommand),
89
90 #[command(display_order = 12)]
93 Auth(AuthCommand),
94
95 #[command(alias = "config", display_order = 13)]
97 InitConfig(InitConfigCommand),
98
99 #[command(display_order = 14)]
102 Diff(DiffCommand),
103
104 #[command(display_order = 15)]
106 Cleanup(CleanupCommand),
107}
108
109#[derive(Parser)]
110pub struct ValidateCommand {
111 pub spec: PathBuf,
113
114 #[arg(long)]
116 pub strict: bool,
117
118 #[arg(long)]
120 pub lint: bool,
121
122 #[arg(long, requires = "lint")]
124 pub rules: Option<PathBuf>,
125
126 #[arg(short, long, value_enum, default_value = "text")]
128 pub format: ValidateFormat,
129}
130
131#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
132pub enum ValidateFormat {
133 Text,
135 Json,
137}
138
139#[derive(Parser)]
140pub struct InitCommand {
141 #[arg(default_value = "my-api-project")]
143 pub name: String,
144
145 #[arg(short, long, default_value = "rest")]
147 pub template: String,
148
149 #[arg(long, value_name = "URL", conflicts_with = "from_file")]
151 pub from_url: Option<String>,
152
153 #[arg(long, value_name = "FILE", conflicts_with = "from_url")]
155 pub from_file: Option<String>,
156
157 #[arg(short, long)]
159 pub force: bool,
160
161 #[arg(long)]
163 pub allow_insecure: bool,
164}
165
166#[derive(Parser)]
167#[command(
168 args_override_self = true,
169 after_help = "EXAMPLES:
170 # Execute an API operation
171 mrapids run users/get-by-username --param username=octocat
172
173 # POST request with data
174 mrapids run repos/create --data '{\"name\": \"my-repo\"}'
175
176 # Use authentication profile
177 mrapids run users/get-authenticated --profile github
178
179 # Search with special characters (NO encoding needed - mrapids handles it)
180 mrapids run search/repos --param q=\"language:javascript stars:>1000\" --param sort=stars
181
182 # Save response to file
183 mrapids run users/list --save users.json
184
185 # Show as curl command
186 mrapids run repos/get --param owner=octocat --param repo=hello-world --as-curl
187
188IMPORTANT TIPS:
189 • Parameters are automatically URL-encoded - pass them as plain text
190 • Use quotes for values with spaces: --param q=\"user:octocat type:pr\"
191 • Data can be read from file: --data @request.json or --file request.json"
192)]
193pub struct RunCommand {
194 pub operation: String,
196
197 #[arg(short, long, conflicts_with = "file", help_heading = "Data Input")]
200 pub data: Option<String>,
201
202 #[arg(short, long, conflicts_with = "data", help_heading = "Data Input")]
204 pub file: Option<PathBuf>,
205
206 #[arg(long, help_heading = "Common Parameters")]
209 pub id: Option<String>,
210
211 #[arg(long, help_heading = "Common Parameters")]
213 pub name: Option<String>,
214
215 #[arg(long, help_heading = "Common Parameters")]
217 pub status: Option<String>,
218
219 #[arg(long, help_heading = "Common Parameters")]
221 pub limit: Option<u32>,
222
223 #[arg(long, help_heading = "Common Parameters")]
225 pub offset: Option<u32>,
226
227 #[arg(long, help_heading = "Common Parameters")]
229 pub sort: Option<String>,
230
231 #[arg(
234 long = "param",
235 value_name = "KEY=VALUE",
236 help_heading = "Request Parameters"
237 )]
238 pub params: Vec<String>,
239
240 #[arg(
242 long = "query",
243 value_name = "KEY=VALUE",
244 help_heading = "Request Parameters"
245 )]
246 pub query_params: Vec<String>,
247
248 #[arg(
250 short = 'H',
251 long = "header",
252 value_name = "KEY: VALUE",
253 help_heading = "Request Parameters"
254 )]
255 pub headers: Vec<String>,
256
257 #[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
260 pub auth: Option<String>,
261
262 #[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
264 pub api_key: Option<String>,
265
266 #[arg(long = "profile", value_name = "PROFILE", conflicts_with_all = &["auth", "api_key"], help_heading = "Authentication")]
268 pub auth_profile: Option<String>,
269
270 #[arg(short, long, default_value = "development")]
272 pub env: String,
273
274 #[arg(short, long)]
276 pub url: Option<String>,
277
278 #[arg(short, long, default_value = "pretty")]
280 pub output: String,
281
282 #[arg(long)]
284 pub save: Option<PathBuf>,
285
286 #[arg(long)]
288 pub template: Option<String>,
289
290 #[arg(long = "set", value_name = "KEY=VALUE")]
292 pub template_vars: Vec<String>,
293
294 #[arg(long, help_heading = "Testing & Debugging")]
297 pub required_only: bool,
298
299 #[arg(short, long, help_heading = "Testing & Debugging")]
301 pub verbose: bool,
302
303 #[arg(long, help_heading = "Testing & Debugging")]
305 pub dry_run: bool,
306
307 #[arg(long, help_heading = "Testing & Debugging")]
309 pub as_curl: bool,
310
311 #[arg(long, help_heading = "Data Input")]
313 pub edit: bool,
314
315 #[arg(long, help_heading = "Data Input")]
317 pub stdin: bool,
318
319 #[arg(long, default_value = "0", help_heading = "Request Options")]
322 pub retry: u32,
323
324 #[arg(long, default_value = "30", help_heading = "Request Options")]
326 pub timeout: u32,
327
328 #[arg(long, help_heading = "Security")]
330 pub allow_insecure: bool,
331
332 #[arg(long, help_heading = "Security")]
334 pub no_warnings: bool,
335}
336
337#[derive(Parser)]
338pub struct TestCommand {
339 pub spec: PathBuf,
341
342 #[arg(long)]
344 pub all: bool,
345
346 #[arg(short, long)]
348 pub operation: Option<String>,
349
350 #[arg(long, default_value = "true")]
352 pub cleanup: bool,
353
354 #[arg(long)]
356 pub keep_artifacts: bool,
357
358 #[arg(long)]
360 pub allow_insecure: bool,
361
362 #[arg(long)]
364 pub no_warnings: bool,
365}
366
367#[derive(Parser)]
369pub struct AnalyzeCommand {
370 pub spec: Option<PathBuf>,
372
373 #[arg(short, long)]
375 pub operation: Option<String>,
376
377 #[arg(short = 'd', long, default_value = ".")]
379 pub output: PathBuf,
380
381 #[arg(long)]
383 pub all: bool,
384
385 #[arg(long)]
387 pub skip_data: bool,
388
389 #[arg(long)]
391 pub skip_validate: bool,
392
393 #[arg(short, long)]
395 pub force: bool,
396
397 #[arg(long, default_value = "true")]
399 pub cleanup_backups: bool,
400}
401
402#[derive(Parser)]
403pub struct ListCommand {
404 #[arg(value_enum, default_value = "operations")]
406 pub resource: ListResource,
407
408 pub spec: Option<PathBuf>,
410
411 #[arg(short, long)]
413 pub filter: Option<String>,
414
415 #[arg(short, long)]
417 pub method: Option<String>,
418
419 #[arg(short, long)]
421 pub tag: Option<String>,
422
423 #[arg(long, value_enum, default_value = "table")]
425 pub format: ListFormat,
426}
427
428#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
429pub enum ListResource {
430 Operations,
432 Requests,
434 All,
436}
437
438#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
439pub enum ListFormat {
440 Table,
442 Simple,
444 Json,
446 Yaml,
448}
449
450#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
451pub enum GenerateTarget {
452 Typescript,
454 Python,
456 Go,
458 Rust,
460 Java,
462 Csharp,
464 Ruby,
466 Php,
468 Swift,
470 Kotlin,
472 Curl,
474 Postman,
476}
477
478#[derive(Parser)]
479pub struct SetupTestsCommand {
480 pub spec: PathBuf,
482
483 #[arg(short, long, value_enum, default_value = "npm")]
485 pub format: TestSetupFormat,
486
487 #[arg(short, long, default_value = ".")]
489 pub output: PathBuf,
490
491 #[arg(long)]
493 pub force: bool,
494
495 #[arg(long)]
497 pub dry_run: bool,
498
499 #[arg(long)]
501 pub with_examples: bool,
502
503 #[arg(long)]
505 pub with_env: bool,
506}
507
508#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
509pub enum TestSetupFormat {
510 Npm,
512 Make,
514 Shell,
516 Compose,
518 Curl,
520 All,
522}
523
524#[derive(Parser)]
525pub struct CleanupCommand {
526 #[arg(long, default_value = "true")]
528 pub test_artifacts: bool,
529
530 #[arg(long, default_value = "true")]
532 pub empty_dirs: bool,
533
534 #[arg(long, default_value = "true")]
536 pub backups: bool,
537
538 #[arg(long, default_value = "true")]
540 pub preserve_specs: bool,
541
542 #[arg(short, long, default_value = ".")]
544 pub path: PathBuf,
545
546 #[arg(long)]
548 pub dry_run: bool,
549}
550
551#[derive(Parser)]
552pub struct ShowCommand {
553 pub operation: String,
555
556 pub spec: Option<PathBuf>,
558
559 #[arg(long)]
561 pub examples: bool,
562
563 #[arg(short, long, value_enum, default_value = "pretty")]
565 pub format: ShowFormat,
566}
567
568#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
569pub enum ShowFormat {
570 Pretty,
572 Json,
574 Yaml,
576}
577
578#[derive(Parser)]
579pub struct InitConfigCommand {
580 #[arg(short, long, default_value = "development")]
582 pub env: String,
583
584 #[arg(short, long)]
586 pub api: Option<String>,
587
588 #[arg(short, long)]
590 pub output: Option<PathBuf>,
591
592 #[arg(short, long)]
594 pub force: bool,
595}
596
597#[derive(Parser)]
598pub struct ExploreCommand {
599 pub keyword: String,
601
602 #[arg(short, long)]
604 pub spec: Option<PathBuf>,
605
606 #[arg(short, long, default_value = "5")]
608 pub limit: usize,
609
610 #[arg(long)]
612 pub detailed: bool,
613
614 #[arg(short, long, value_enum, default_value = "pretty")]
616 pub format: ExploreFormat,
617}
618
619#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
620pub enum ExploreFormat {
621 Pretty,
623 Simple,
625 Json,
627}
628
629#[derive(Parser)]
630pub struct AuthCommand {
631 #[command(subcommand)]
632 pub command: AuthCommands,
633}
634
635#[derive(Subcommand)]
636pub enum AuthCommands {
637 Login {
639 provider: String,
641
642 #[arg(long)]
644 client_id: Option<String>,
645
646 #[arg(long)]
648 client_secret: Option<String>,
649
650 #[arg(long)]
652 auth_url: Option<String>,
653
654 #[arg(long)]
656 token_url: Option<String>,
657
658 #[arg(long, value_delimiter = ' ')]
660 scopes: Vec<String>,
661
662 #[arg(long)]
664 profile: Option<String>,
665
666 #[arg(long)]
668 setup_help: bool,
669 },
670
671 List {
673 #[arg(long)]
675 detailed: bool,
676 },
677
678 Show {
680 profile: String,
682
683 #[arg(long)]
685 show_tokens: bool,
686 },
687
688 Refresh {
690 profile: String,
692 },
693
694 Logout {
696 profile: String,
698
699 #[arg(long)]
701 force: bool,
702 },
703
704 Test {
706 profile: String,
708 },
709
710 Setup {
712 provider: String,
714 },
715}
716
717#[derive(Parser)]
718pub struct FlattenCommand {
719 pub spec: PathBuf,
721
722 #[arg(short, long)]
724 pub output: Option<PathBuf>,
725
726 #[arg(short, long, value_enum, default_value = "yaml")]
728 pub format: FlattenFormat,
729
730 #[arg(long)]
732 pub include_unused: bool,
733
734 #[arg(long)]
736 pub resolve_external: bool,
737
738 #[arg(long)]
740 pub allow_insecure: bool,
741}
742
743#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
744pub enum FlattenFormat {
745 Yaml,
747 Json,
749}
750
751#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
752pub enum SdkLanguage {
753 Typescript,
755 Python,
757 Go,
759 Rust,
761}
762
763#[derive(Parser)]
764pub struct DiffCommand {
765 pub old_spec: PathBuf,
767
768 pub new_spec: PathBuf,
770
771 #[arg(long, alias = "breaking")]
773 pub breaking_only: bool,
774
775 #[arg(short, long, value_enum, default_value = "text")]
777 pub format: DiffFormat,
778
779 #[arg(long)]
781 pub fail_on_breaking: bool,
782}
783
784#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
785pub enum DiffFormat {
786 Text,
788 Json,
790 Markdown,
792}
793
794#[derive(Parser)]
795pub struct GenCommand {
796 #[command(subcommand)]
797 pub target: GenTarget,
798}
799
800#[derive(Subcommand)]
801pub enum GenTarget {
802 Snippets(GenSnippetsCommand),
804
805 Sdk(GenSdkCommand),
807
808 Stubs(GenStubsCommand),
810
811 Fixtures(GenFixturesCommand),
813}
814
815#[derive(Parser)]
816pub struct GenSnippetsCommand {
817 pub spec: Option<PathBuf>,
819
820 #[arg(short, long, default_value = "./examples")]
822 pub output: PathBuf,
823
824 #[arg(long)]
826 pub operation: Option<String>,
827
828 #[arg(long, value_enum, default_value = "json")]
830 pub format: SnippetFormat,
831
832 #[arg(long)]
834 pub curl: bool,
835
836 #[arg(long)]
838 pub httpie: bool,
839}
840
841#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
842pub enum SnippetFormat {
843 Json,
844 Yaml,
845 Curl,
846 Httpie,
847 All,
848}
849
850#[derive(Parser)]
851pub struct GenSdkCommand {
852 pub spec: Option<PathBuf>,
854
855 #[arg(short, long, value_enum)]
857 pub language: SdkLanguage,
858
859 #[arg(short, long)]
861 pub output: Option<PathBuf>,
862
863 #[arg(long)]
865 pub package: Option<String>,
866
867 #[arg(long, default_value = "true")]
869 pub docs: bool,
870
871 #[arg(long, default_value = "true")]
873 pub examples: bool,
874}
875
876#[derive(Parser)]
877pub struct GenStubsCommand {
878 pub spec: Option<PathBuf>,
880
881 #[arg(short, long)]
883 pub framework: String,
884
885 #[arg(short, long)]
887 pub output: Option<PathBuf>,
888
889 #[arg(long)]
891 pub with_tests: bool,
892
893 #[arg(long)]
895 pub with_validation: bool,
896}
897
898#[derive(Parser)]
899pub struct GenFixturesCommand {
900 pub spec: Option<PathBuf>,
902
903 #[arg(short, long, default_value = "./fixtures")]
905 pub output: PathBuf,
906
907 #[arg(long, default_value = "10")]
909 pub count: u32,
910
911 #[arg(long)]
913 pub schema: Vec<String>,
914
915 #[arg(long)]
917 pub seed: Option<u64>,
918
919 #[arg(long, value_enum, default_value = "json")]
921 pub format: FixtureFormat,
922}
923
924#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
925pub enum FixtureFormat {
926 Json,
927 Yaml,
928 Csv,
929}
930
931#[derive(Parser)]
932pub struct CollectionCommand {
933 #[command(subcommand)]
934 pub command: CollectionSubcommand,
935}
936
937#[derive(Subcommand)]
938pub enum CollectionSubcommand {
939 List {
941 #[arg(long, default_value = ".mrapids/collections")]
943 dir: PathBuf,
944 },
945
946 Show {
948 name: String,
950
951 #[arg(long, default_value = ".mrapids/collections")]
953 dir: PathBuf,
954 },
955
956 Validate {
958 name: String,
960
961 #[arg(long, default_value = ".mrapids/collections")]
963 dir: PathBuf,
964
965 #[arg(long)]
967 spec: Option<PathBuf>,
968 },
969
970 Run {
972 name: String,
974
975 #[arg(long, default_value = ".mrapids/collections")]
977 dir: PathBuf,
978
979 #[arg(long, default_value = "pretty")]
981 output: String,
982
983 #[arg(long)]
985 save_all: Option<PathBuf>,
986
987 #[arg(long)]
989 save_summary: Option<PathBuf>,
990
991 #[arg(long = "var", value_parser = parse_key_val::<String, String>)]
993 variables: Vec<(String, String)>,
994
995 #[arg(long = "profile", value_name = "PROFILE")]
997 auth_profile: Option<String>,
998
999 #[arg(long)]
1001 continue_on_error: bool,
1002
1003 #[arg(long = "request")]
1005 requests: Vec<String>,
1006
1007 #[arg(long = "skip")]
1009 skip_requests: Vec<String>,
1010
1011 #[arg(long)]
1013 use_env: bool,
1014
1015 #[arg(long)]
1017 env_file: Option<PathBuf>,
1018
1019 #[arg(long)]
1021 spec: Option<PathBuf>,
1022
1023 #[arg(long)]
1025 env: Option<String>,
1026 },
1027
1028 Test {
1030 name: String,
1032
1033 #[arg(long, default_value = ".mrapids/collections")]
1035 dir: PathBuf,
1036
1037 #[arg(long)]
1039 spec: Option<PathBuf>,
1040
1041 #[arg(long = "profile", value_name = "PROFILE")]
1043 auth_profile: Option<String>,
1044
1045 #[arg(long, default_value = "pretty")]
1047 output: String,
1048
1049 #[arg(long)]
1051 continue_on_error: bool,
1052 },
1053}
1054
1055fn parse_key_val<T, U>(
1057 s: &str,
1058) -> Result<(T, U), Box<dyn std::error::Error + Send + Sync + 'static>>
1059where
1060 T: std::str::FromStr,
1061 T::Err: std::error::Error + Send + Sync + 'static,
1062 U: std::str::FromStr,
1063 U::Err: std::error::Error + Send + Sync + 'static,
1064{
1065 let pos = s
1066 .find('=')
1067 .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
1068 Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
1069}
1070
1071fn get_grouped_help() -> &'static str {
1073 r#" ╭──────────────────────────────────────────╮
1074 │ ○ ○ M I C R O R A P I D ○ ○ │
1075 │ ╲ ╱ ╲ ╱ │
1076 │ ═ 🤖 agent automation 🤖 ═ │
1077 │ ╱ ╲ your api, automated ╱ ╲ │
1078 │ ○ ○ ○ ○ │
1079 ╰──────────────────────────────────────────╯
1080
1081 >> mrapids.exe --mode agent
1082 >> status: [READY] ████████████ 100%
1083
1084Your OpenAPI, but executable
1085
1086The blazing fast API automation toolkit
1087
1088Usage: mrapids [OPTIONS] <COMMAND>
1089
1090GETTING STARTED
1091 init Initialize a new MicroRapid project
1092 explore Discover what operations are available in your API
1093 show Show detailed information about specific operations
1094 validate Ensure your OpenAPI specification is correct
1095
1096EXECUTION & TESTING
1097 run Execute API operations directly
1098 test Run automated tests against your API
1099 list List available operations, requests, or resources
1100
1101CODE GENERATION
1102 gen Generate SDKs, examples, test fixtures, and code
1103 flatten Resolve all $ref references in your specification
1104
1105AUTOMATION & WORKFLOWS
1106 collection Manage and run complex API request collections
1107 setup-tests Set up complete test environment automatically
1108
1109CONFIGURATION
1110 auth Manage OAuth and API authentication
1111 init-config Initialize environment configurations
1112
1113UTILITIES
1114 diff Compare specifications for breaking changes
1115 cleanup Clean up test artifacts and temporary files
1116 help Print this message or the help of the given subcommand(s)
1117
1118Options:
1119 --env <ENV> Environment name (dev, staging, prod)
1120 --output-format <FORMAT> Output format (json, yaml, table, pretty)
1121 -q, --quiet Suppress all output except errors
1122 -v, --verbose Enable verbose output
1123 --trace Enable trace output (includes HTTP requests/responses)
1124 --no-color Disable colored output
1125 -h, --help Print help
1126 -V, --version Print version
1127
1128EXAMPLES:
1129 # Start with a new project
1130 mrapids init my-api --from-url https://api.example.com/openapi.json
1131
1132 # Explore available operations
1133 mrapids explore user
1134
1135 # Execute an operation
1136 mrapids run GetUser --id 123
1137
1138 # Generate an SDK
1139 mrapids gen sdk --language typescript --output ./sdk
1140
1141 # Run a test collection
1142 mrapids collection run smoke-tests
1143
1144For detailed help on any command:
1145 mrapids <command> --help
1146
1147For more information, visit: https://microrapid.io/"#
1148}
1149
1150fn get_help_footer() -> &'static str {
1152 r#"
1153EXAMPLES:
1154 # Start with a new project
1155 mrapids init my-api --from-url https://api.example.com/openapi.json
1156
1157 # Explore available operations
1158 mrapids explore user
1159
1160 # Execute an operation
1161 mrapids run GetUser --id 123
1162
1163 # Generate an SDK
1164 mrapids gen sdk --language typescript --output ./sdk
1165
1166 # Run a test collection
1167 mrapids collection run smoke-tests
1168
1169For detailed help on any command:
1170 mrapids <command> --help
1171
1172For more information, visit: https://microrapid.io/"#
1173}