use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "mrapids")]
#[command(about = "Your OpenAPI, but executable", long_about = None)]
#[command(version)]
#[command(before_help = crate::core::banner::get_help_header())]
#[command(after_help = get_help_footer())]
#[command(override_help = get_grouped_help())]
pub struct Args {
#[command(subcommand)]
pub command: Commands,
#[arg(long, global = true, value_name = "ENV")]
pub env: Option<String>,
#[arg(long = "output-format", global = true, value_name = "FORMAT")]
pub output_format: Option<String>,
#[arg(long, short = 'q', global = true)]
pub quiet: bool,
#[arg(long, short = 'v', global = true)]
pub verbose: bool,
#[arg(long, global = true)]
pub trace: bool,
#[arg(long, global = true)]
pub no_color: bool,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(display_order = 1)]
Init(InitCommand),
#[command(alias = "search", alias = "discover", display_order = 2)]
Explore(ExploreCommand),
#[command(display_order = 3)]
Show(ShowCommand),
#[command(display_order = 4)]
Validate(ValidateCommand),
#[command(display_order = 5)]
Run(RunCommand),
#[command(display_order = 6)]
Test(TestCommand),
#[command(display_order = 7)]
List(ListCommand),
#[command(alias = "generate", display_order = 8)]
Gen(GenCommand),
#[command(display_order = 9)]
Flatten(FlattenCommand),
#[command(display_order = 10)]
Collection(CollectionCommand),
#[command(alias = "tests-init", display_order = 11)]
SetupTests(SetupTestsCommand),
#[command(display_order = 12)]
Auth(AuthCommand),
#[command(alias = "config", display_order = 13)]
InitConfig(InitConfigCommand),
#[command(display_order = 14)]
Diff(DiffCommand),
#[command(display_order = 15)]
Cleanup(CleanupCommand),
}
#[derive(Parser)]
pub struct ValidateCommand {
pub spec: PathBuf,
#[arg(long)]
pub strict: bool,
#[arg(long)]
pub lint: bool,
#[arg(long, requires = "lint")]
pub rules: Option<PathBuf>,
#[arg(short, long, value_enum, default_value = "text")]
pub format: ValidateFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ValidateFormat {
Text,
Json,
}
#[derive(Parser)]
pub struct InitCommand {
#[arg(default_value = "my-api-project")]
pub name: String,
#[arg(short, long, default_value = "rest")]
pub template: String,
#[arg(long, value_name = "URL", conflicts_with = "from_file")]
pub from_url: Option<String>,
#[arg(long, value_name = "FILE", conflicts_with = "from_url")]
pub from_file: Option<String>,
#[arg(short, long)]
pub force: bool,
#[arg(long)]
pub allow_insecure: bool,
}
#[derive(Parser)]
#[command(
args_override_self = true,
after_help = "EXAMPLES:
# Execute an API operation
mrapids run users/get-by-username --param username=octocat
# POST request with data
mrapids run repos/create --data '{\"name\": \"my-repo\"}'
# Use authentication profile
mrapids run users/get-authenticated --profile github
# Search with special characters (NO encoding needed - mrapids handles it)
mrapids run search/repos --param q=\"language:javascript stars:>1000\" --param sort=stars
# Save response to file
mrapids run users/list --save users.json
# Show as curl command
mrapids run repos/get --param owner=octocat --param repo=hello-world --as-curl
IMPORTANT TIPS:
• Parameters are automatically URL-encoded - pass them as plain text
• Use quotes for values with spaces: --param q=\"user:octocat type:pr\"
• Data can be read from file: --data @request.json or --file request.json"
)]
pub struct RunCommand {
pub operation: String,
#[arg(short, long, conflicts_with = "file", help_heading = "Data Input")]
pub data: Option<String>,
#[arg(short, long, conflicts_with = "data", help_heading = "Data Input")]
pub file: Option<PathBuf>,
#[arg(long, help_heading = "Common Parameters")]
pub id: Option<String>,
#[arg(long, help_heading = "Common Parameters")]
pub name: Option<String>,
#[arg(long, help_heading = "Common Parameters")]
pub status: Option<String>,
#[arg(long, help_heading = "Common Parameters")]
pub limit: Option<u32>,
#[arg(long, help_heading = "Common Parameters")]
pub offset: Option<u32>,
#[arg(long, help_heading = "Common Parameters")]
pub sort: Option<String>,
#[arg(
long = "param",
value_name = "KEY=VALUE",
help_heading = "Request Parameters"
)]
pub params: Vec<String>,
#[arg(
long = "query",
value_name = "KEY=VALUE",
help_heading = "Request Parameters"
)]
pub query_params: Vec<String>,
#[arg(
short = 'H',
long = "header",
value_name = "KEY: VALUE",
help_heading = "Request Parameters"
)]
pub headers: Vec<String>,
#[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
pub auth: Option<String>,
#[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
pub api_key: Option<String>,
#[arg(long = "profile", value_name = "PROFILE", conflicts_with_all = &["auth", "api_key"], help_heading = "Authentication")]
pub auth_profile: Option<String>,
#[arg(short, long, default_value = "development")]
pub env: String,
#[arg(short, long)]
pub url: Option<String>,
#[arg(short, long, default_value = "pretty")]
pub output: String,
#[arg(long)]
pub save: Option<PathBuf>,
#[arg(long)]
pub template: Option<String>,
#[arg(long = "set", value_name = "KEY=VALUE")]
pub template_vars: Vec<String>,
#[arg(long, help_heading = "Testing & Debugging")]
pub required_only: bool,
#[arg(short, long, help_heading = "Testing & Debugging")]
pub verbose: bool,
#[arg(long, help_heading = "Testing & Debugging")]
pub dry_run: bool,
#[arg(long, help_heading = "Testing & Debugging")]
pub as_curl: bool,
#[arg(long, help_heading = "Data Input")]
pub edit: bool,
#[arg(long, help_heading = "Data Input")]
pub stdin: bool,
#[arg(long, default_value = "0", help_heading = "Request Options")]
pub retry: u32,
#[arg(long, default_value = "30", help_heading = "Request Options")]
pub timeout: u32,
#[arg(long, help_heading = "Security")]
pub allow_insecure: bool,
#[arg(long, help_heading = "Security")]
pub no_warnings: bool,
}
#[derive(Parser)]
pub struct TestCommand {
pub spec: PathBuf,
#[arg(long)]
pub all: bool,
#[arg(short, long)]
pub operation: Option<String>,
#[arg(long, default_value = "true")]
pub cleanup: bool,
#[arg(long)]
pub keep_artifacts: bool,
#[arg(long)]
pub allow_insecure: bool,
#[arg(long)]
pub no_warnings: bool,
}
#[derive(Parser)]
pub struct AnalyzeCommand {
pub spec: Option<PathBuf>,
#[arg(short, long)]
pub operation: Option<String>,
#[arg(short = 'd', long, default_value = ".")]
pub output: PathBuf,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub skip_data: bool,
#[arg(long)]
pub skip_validate: bool,
#[arg(short, long)]
pub force: bool,
#[arg(long, default_value = "true")]
pub cleanup_backups: bool,
}
#[derive(Parser)]
pub struct ListCommand {
#[arg(value_enum, default_value = "operations")]
pub resource: ListResource,
pub spec: Option<PathBuf>,
#[arg(short, long)]
pub filter: Option<String>,
#[arg(short, long)]
pub method: Option<String>,
#[arg(short, long)]
pub tag: Option<String>,
#[arg(long, value_enum, default_value = "table")]
pub format: ListFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ListResource {
Operations,
Requests,
All,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ListFormat {
Table,
Simple,
Json,
Yaml,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum GenerateTarget {
Typescript,
Python,
Go,
Rust,
Java,
Csharp,
Ruby,
Php,
Swift,
Kotlin,
Curl,
Postman,
}
#[derive(Parser)]
pub struct SetupTestsCommand {
pub spec: PathBuf,
#[arg(short, long, value_enum, default_value = "npm")]
pub format: TestSetupFormat,
#[arg(short, long, default_value = ".")]
pub output: PathBuf,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub with_examples: bool,
#[arg(long)]
pub with_env: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum TestSetupFormat {
Npm,
Make,
Shell,
Compose,
Curl,
All,
}
#[derive(Parser)]
pub struct CleanupCommand {
#[arg(long, default_value = "true")]
pub test_artifacts: bool,
#[arg(long, default_value = "true")]
pub empty_dirs: bool,
#[arg(long, default_value = "true")]
pub backups: bool,
#[arg(long, default_value = "true")]
pub preserve_specs: bool,
#[arg(short, long, default_value = ".")]
pub path: PathBuf,
#[arg(long)]
pub dry_run: bool,
}
#[derive(Parser)]
pub struct ShowCommand {
pub operation: String,
pub spec: Option<PathBuf>,
#[arg(long)]
pub examples: bool,
#[arg(short, long, value_enum, default_value = "pretty")]
pub format: ShowFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ShowFormat {
Pretty,
Json,
Yaml,
}
#[derive(Parser)]
pub struct InitConfigCommand {
#[arg(short, long, default_value = "development")]
pub env: String,
#[arg(short, long)]
pub api: Option<String>,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(short, long)]
pub force: bool,
}
#[derive(Parser)]
pub struct ExploreCommand {
pub keyword: String,
#[arg(short, long)]
pub spec: Option<PathBuf>,
#[arg(short, long, default_value = "5")]
pub limit: usize,
#[arg(long)]
pub detailed: bool,
#[arg(short, long, value_enum, default_value = "pretty")]
pub format: ExploreFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ExploreFormat {
Pretty,
Simple,
Json,
}
#[derive(Parser)]
pub struct AuthCommand {
#[command(subcommand)]
pub command: AuthCommands,
}
#[derive(Subcommand)]
pub enum AuthCommands {
Login {
provider: String,
#[arg(long)]
client_id: Option<String>,
#[arg(long)]
client_secret: Option<String>,
#[arg(long)]
auth_url: Option<String>,
#[arg(long)]
token_url: Option<String>,
#[arg(long, value_delimiter = ' ')]
scopes: Vec<String>,
#[arg(long)]
profile: Option<String>,
#[arg(long)]
setup_help: bool,
},
List {
#[arg(long)]
detailed: bool,
},
Show {
profile: String,
#[arg(long)]
show_tokens: bool,
},
Refresh {
profile: String,
},
Logout {
profile: String,
#[arg(long)]
force: bool,
},
Test {
profile: String,
},
Setup {
provider: String,
},
}
#[derive(Parser)]
pub struct FlattenCommand {
pub spec: PathBuf,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(short, long, value_enum, default_value = "yaml")]
pub format: FlattenFormat,
#[arg(long)]
pub include_unused: bool,
#[arg(long)]
pub resolve_external: bool,
#[arg(long)]
pub allow_insecure: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum FlattenFormat {
Yaml,
Json,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum SdkLanguage {
Typescript,
Python,
Go,
Rust,
}
#[derive(Parser)]
pub struct DiffCommand {
pub old_spec: PathBuf,
pub new_spec: PathBuf,
#[arg(long, alias = "breaking")]
pub breaking_only: bool,
#[arg(short, long, value_enum, default_value = "text")]
pub format: DiffFormat,
#[arg(long)]
pub fail_on_breaking: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum DiffFormat {
Text,
Json,
Markdown,
}
#[derive(Parser)]
pub struct GenCommand {
#[command(subcommand)]
pub target: GenTarget,
}
#[derive(Subcommand)]
pub enum GenTarget {
Snippets(GenSnippetsCommand),
Sdk(GenSdkCommand),
Stubs(GenStubsCommand),
Fixtures(GenFixturesCommand),
}
#[derive(Parser)]
pub struct GenSnippetsCommand {
pub spec: Option<PathBuf>,
#[arg(short, long, default_value = "./examples")]
pub output: PathBuf,
#[arg(long)]
pub operation: Option<String>,
#[arg(long, value_enum, default_value = "json")]
pub format: SnippetFormat,
#[arg(long)]
pub curl: bool,
#[arg(long)]
pub httpie: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum SnippetFormat {
Json,
Yaml,
Curl,
Httpie,
All,
}
#[derive(Parser)]
pub struct GenSdkCommand {
pub spec: Option<PathBuf>,
#[arg(short, long, value_enum)]
pub language: SdkLanguage,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(long)]
pub package: Option<String>,
#[arg(long, default_value = "true")]
pub docs: bool,
#[arg(long, default_value = "true")]
pub examples: bool,
}
#[derive(Parser)]
pub struct GenStubsCommand {
pub spec: Option<PathBuf>,
#[arg(short, long)]
pub framework: String,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[arg(long)]
pub with_tests: bool,
#[arg(long)]
pub with_validation: bool,
}
#[derive(Parser)]
pub struct GenFixturesCommand {
pub spec: Option<PathBuf>,
#[arg(short, long, default_value = "./fixtures")]
pub output: PathBuf,
#[arg(long, default_value = "10")]
pub count: u32,
#[arg(long)]
pub schema: Vec<String>,
#[arg(long)]
pub seed: Option<u64>,
#[arg(long, value_enum, default_value = "json")]
pub format: FixtureFormat,
}
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum FixtureFormat {
Json,
Yaml,
Csv,
}
#[derive(Parser)]
pub struct CollectionCommand {
#[command(subcommand)]
pub command: CollectionSubcommand,
}
#[derive(Subcommand)]
pub enum CollectionSubcommand {
List {
#[arg(long, default_value = ".mrapids/collections")]
dir: PathBuf,
},
Show {
name: String,
#[arg(long, default_value = ".mrapids/collections")]
dir: PathBuf,
},
Validate {
name: String,
#[arg(long, default_value = ".mrapids/collections")]
dir: PathBuf,
#[arg(long)]
spec: Option<PathBuf>,
},
Run {
name: String,
#[arg(long, default_value = ".mrapids/collections")]
dir: PathBuf,
#[arg(long, default_value = "pretty")]
output: String,
#[arg(long)]
save_all: Option<PathBuf>,
#[arg(long)]
save_summary: Option<PathBuf>,
#[arg(long = "var", value_parser = parse_key_val::<String, String>)]
variables: Vec<(String, String)>,
#[arg(long = "profile", value_name = "PROFILE")]
auth_profile: Option<String>,
#[arg(long)]
continue_on_error: bool,
#[arg(long = "request")]
requests: Vec<String>,
#[arg(long = "skip")]
skip_requests: Vec<String>,
#[arg(long)]
use_env: bool,
#[arg(long)]
env_file: Option<PathBuf>,
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long)]
env: Option<String>,
},
Test {
name: String,
#[arg(long, default_value = ".mrapids/collections")]
dir: PathBuf,
#[arg(long)]
spec: Option<PathBuf>,
#[arg(long = "profile", value_name = "PROFILE")]
auth_profile: Option<String>,
#[arg(long, default_value = "pretty")]
output: String,
#[arg(long)]
continue_on_error: bool,
},
}
fn parse_key_val<T, U>(
s: &str,
) -> Result<(T, U), Box<dyn std::error::Error + Send + Sync + 'static>>
where
T: std::str::FromStr,
T::Err: std::error::Error + Send + Sync + 'static,
U: std::str::FromStr,
U::Err: std::error::Error + Send + Sync + 'static,
{
let pos = s
.find('=')
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
}
fn get_grouped_help() -> &'static str {
r#" ╭──────────────────────────────────────────╮
│ ○ ○ M I C R O R A P I D ○ ○ │
│ ╲ ╱ ╲ ╱ │
│ ═ 🤖 agent automation 🤖 ═ │
│ ╱ ╲ your api, automated ╱ ╲ │
│ ○ ○ ○ ○ │
╰──────────────────────────────────────────╯
>> mrapids.exe --mode agent
>> status: [READY] ████████████ 100%
Your OpenAPI, but executable
The blazing fast API automation toolkit
Usage: mrapids [OPTIONS] <COMMAND>
GETTING STARTED
init Initialize a new MicroRapid project
explore Discover what operations are available in your API
show Show detailed information about specific operations
validate Ensure your OpenAPI specification is correct
EXECUTION & TESTING
run Execute API operations directly
test Run automated tests against your API
list List available operations, requests, or resources
CODE GENERATION
gen Generate SDKs, examples, test fixtures, and code
flatten Resolve all $ref references in your specification
AUTOMATION & WORKFLOWS
collection Manage and run complex API request collections
setup-tests Set up complete test environment automatically
CONFIGURATION
auth Manage OAuth and API authentication
init-config Initialize environment configurations
UTILITIES
diff Compare specifications for breaking changes
cleanup Clean up test artifacts and temporary files
help Print this message or the help of the given subcommand(s)
Options:
--env <ENV> Environment name (dev, staging, prod)
--output-format <FORMAT> Output format (json, yaml, table, pretty)
-q, --quiet Suppress all output except errors
-v, --verbose Enable verbose output
--trace Enable trace output (includes HTTP requests/responses)
--no-color Disable colored output
-h, --help Print help
-V, --version Print version
EXAMPLES:
# Start with a new project
mrapids init my-api --from-url https://api.example.com/openapi.json
# Explore available operations
mrapids explore user
# Execute an operation
mrapids run GetUser --id 123
# Generate an SDK
mrapids gen sdk --language typescript --output ./sdk
# Run a test collection
mrapids collection run smoke-tests
For detailed help on any command:
mrapids <command> --help
For more information, visit: https://microrapid.io/"#
}
fn get_help_footer() -> &'static str {
r#"
EXAMPLES:
# Start with a new project
mrapids init my-api --from-url https://api.example.com/openapi.json
# Explore available operations
mrapids explore user
# Execute an operation
mrapids run GetUser --id 123
# Generate an SDK
mrapids gen sdk --language typescript --output ./sdk
# Run a test collection
mrapids collection run smoke-tests
For detailed help on any command:
mrapids <command> --help
For more information, visit: https://microrapid.io/"#
}