cURL to Rust
Convert a cURL command into a Rust reqwest request.
Related Tools
Convert a cURL command into a Go net/http request.
Generate a Rust struct with serde derive attributes from a JSON document.
Convert a cURL command into a Python requests call.
Beautify and pretty-print JSON with configurable indentation.
Convert a cURL command into a Node.js fetch call.
Convert a cURL command into a PHP curl_setopt call.
Documentation
What is curl-to-Rust?
This tool converts a curl command into an async Rust program built on reqwest, the de facto standard HTTP client crate for Rust (built on hyper), running under the tokio async runtime.
How it works
Curl's flags are parsed into method, url, headers, a raw body string, form fields, Basic Auth, and the insecure flag. The Rust emitter builds a reqwest::Client, then chains a request builder: .header(key, value) for each curl -H, .basic_auth(user, Some(pass)) for -u, and .body(...) for -d/--data — passed through as a raw Rust string literal (using a raw string r#"..."# when the body itself contains double quotes, so nothing needs escaping). The HTTP method is built via reqwest::Method::from_bytes(...) rather than reqwest's named constructors (Client::get, Client::post, etc.), because that accepts any method string — including less common verbs like PATCH or a custom method — not just the handful reqwest exposes helpers for.
Features
- Async output using
#[tokio::main]andreqwest - Any HTTP method supported via
Method::from_bytes, not just the common ones - Body passed through as a raw string, using
r#"..."#automatically when it contains quotes -F/--form uploads viamultipart::Form—.text(key, value)for fields,.file(key, path).await?for files (reqwest reads the file from disk directly, no manual I/O needed)-k/--insecure mapped toClientBuilder::danger_accept_invalid_certs(true)
Example
Input: curl -X POST https://api.example.com/v1/users -H "Content-Type: application/json" -H "X-Api-Key: abc123" -d '{"name":"Ada Lovelace","role":"admin"}'
Output:
use reqwest::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let req = client.request(reqwest::Method::from_bytes(b"POST")?, "https://api.example.com/v1/users")
.header("Content-Type", "application/json")
.header("X-Api-Key", "abc123")
.body(r#"{"name":"Ada Lovelace","role":"admin"}"#);
let response = req.send().await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}Common errors
The output needs the reqwest and tokio crates in Cargo.toml — tokio specifically needs its "full" feature (or at minimum "rt-multi-thread" and "macros") enabled, since #[tokio::main] won't compile without it. Forgetting reqwest's "multipart" feature flag will fail to compile any command that used -F.
Best practices
Reuse one Client across many requests instead of constructing a new one each time — it holds a connection pool internally and is cheap to clone. Always propagate errors with ? (as the generated code does) rather than .unwrap(), and avoid danger_accept_invalid_certs(true) outside local development.
Frequently Asked Questions
Why reqwest specifically?▾
reqwest is the de facto standard async HTTP client for Rust, built on hyper — the generated code targets it directly rather than a lower-level alternative, since it's what most Rust HTTP code in the wild already uses.
Does this need tokio?▾
Yes — reqwest's async API needs an async runtime, and the generated main function is annotated #[tokio::main], which requires the tokio crate with the "full" (or at least "rt-multi-thread" + "macros") feature enabled in Cargo.toml.
How is an arbitrary HTTP method (like PATCH) handled?▾
Via reqwest::Method::from_bytes(...), which accepts any method string — not just the handful reqwest exposes as named constructors (get, post, put, delete) — so unusual verbs from the original curl command still work.
Does it support multipart file uploads?▾
Yes, via reqwest::multipart::Form — text fields use .text(key, value) and file fields use .file(key, path).await?, which reads the file from disk directly (unlike the Node/Go generators, reqwest's API makes this a one-line call).