A Rust library for parsing curl commands into structured HTTP request objects.
Many APIs provide curl examples to help users get started quickly. This crate bridges the gap between curl command examples and Rust code by parsing curl commands into structured ParsedRequest objects that can be easily converted to HTTP requests.
- Parse curl commands into structured Rust objects
- Template support for dynamic values (e.g., API tokens)
- Automatic conversions for common patterns
- reqwest integration (optional)
- High performance with optimized parsing
-X, --request- HTTP method-H, --header- HTTP headers-d, --data- Request body-u- Basic authentication-L, --location- Follow redirects-k, --insecure- Skip SSL verification
Add this to your Cargo.toml:
[dependencies]
curl-parser = "0.6"reqwest(enabled by default) - Enables conversion toreqwest::RequestBuilderuri(enabled by default) - Parses URLs intohttp::Uritype
To use without default features:
[dependencies]
curl-parser = { version = "0.6", default-features = false }use curl_parser::ParsedRequest;
use std::str::FromStr;
let curl_cmd = "curl https://api.example.com/users";
let request = ParsedRequest::from_str(curl_cmd)?;
println!("Method: {}", request.method);
println!("URL: {}", request.url);use curl_parser::ParsedRequest;
use serde_json::json;
let curl_cmd = r#"curl -X POST https://api.github.com/repos \
-H "Authorization: Bearer {{ token }}" \
-d '{"name": "{{ repo_name }}"}"#;
let context = json!({
"token": "your_github_token",
"repo_name": "my-new-repo"
});
let request = ParsedRequest::load(curl_cmd, context)?;use curl_parser::ParsedRequest;
use std::str::FromStr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let curl_cmd = "curl https://api.github.com/users/rust-lang";
let parsed = ParsedRequest::from_str(curl_cmd)?;
// Convert to reqwest::RequestBuilder
let request: reqwest::RequestBuilder = parsed.try_into()?;
// Send the request
let response = request.send().await?;
println!("Status: {}", response.status());
Ok(())
}let curl = r#"curl -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer token123' \
-d '{"name": "John Doe", "email": "[email protected]"}"#;
let request = ParsedRequest::from_str(curl)?;
assert_eq!(request.method, Method::POST);
assert_eq!(request.body, vec![r#"{"name": "John Doe", "email": "[email protected]"}"#]);let curl = r#"curl https://api.stripe.com/v1/charges \
-u sk_test_1234: \
-H "Stripe-Version: 2022-11-15""#;
let request = ParsedRequest::from_str(curl)?;
// The -u flag is automatically converted to Authorization: Basic headerlet curl = r#"curl -X POST https://httpbin.org/post \
-d 'name=John' \
-d 'age=30' \
-d 'city=New York'"#;
let request = ParsedRequest::from_str(curl)?;
// Multiple -d flags are collected and form-urlencodedThe parser correctly handles escaped JSON in headers:
let curl = r#"curl https://api.example.com \
-H "X-Custom-Data: {\"key\":\"value\",\"nested\":{\"data\":true}}"#;
let request = ParsedRequest::from_str(curl)?;
// The escaped JSON is properly unescaped in the header valueIf a request body is provided without an explicit method, POST is automatically used:
let curl = r#"curl https://api.example.com -d '{"data": "value"}'"#;
let request = ParsedRequest::from_str(curl)?;
assert_eq!(request.method, Method::POST); // Automatically set to POSTThe parser automatically adds common default headers:
Accept: */*if not specifiedContent-Type: application/x-www-form-urlencodedfor form data
This crate is optimized for performance with:
- Cached template environment (60%+ improvement for template operations)
- Pre-allocated collections for common sizes
- Efficient string operations using byte-level matching
- Optimized grammar rules for the Pest parser
Run benchmarks with:
cargo bench --bench parsing_benchmarkcargo buildcargo testcargo clippy
cargo fmtContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.