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::RequestBuilder
uri
(enabled by default) - Parses URLs intohttp::Uri
type
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": "john@example.com"}"#;
let request = ParsedRequest::from_str(curl)?;
assert_eq!(request.method, Method::POST);
assert_eq!(request.body, vec![r#"{"name": "John Doe", "email": "john@example.com"}"#]);
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 header
let 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-urlencoded
The 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 value
If 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 POST
The parser automatically adds common default headers:
Accept: */*
if not specifiedContent-Type: application/x-www-form-urlencoded
for 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_benchmark
cargo build
cargo test
cargo clippy
cargo fmt
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.