cURL to Rust Converter
Convert cURL commands to Rust reqwest code — async/await with tokio, generated instantly
You have a cURL command and need to make the same HTTP request from a Rust program. Rust’s HTTP ecosystem has matured significantly, but writing reqwest boilerplate — imports, async main, client configuration, header insertion — takes time even for experienced Rust developers. This tool generates that boilerplate for you. Paste any cURL command and get a complete, compilable Rust program using the reqwest crate with the tokio async runtime.
Why reqwest?
reqwest is the most widely used async HTTP client in the Rust ecosystem. It wraps hyper (which itself wraps Tokio’s async I/O) and provides a high-level, ergonomic builder API for constructing requests. With over 75 million total downloads on crates.io and adoption across Rust’s major frameworks (Axum, Actix, Leptos), it is the de facto standard choice — the Python requests equivalent for Rust.
No other cURL converter tool currently generates Rust output. If you are evaluating this tool against competitors, you will find this feature is unique to PureDevTools.
Cargo.toml Dependencies
Add these to your Cargo.toml to compile the generated code:
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
The json feature enables .json() deserialization on responses and the ability to pass structs as JSON bodies. The full feature set for tokio includes all async runtimes and utilities needed for the #[tokio::main] macro.
How the Converter Maps cURL Flags to Rust
| cURL flag | reqwest equivalent |
|---|---|
-X PUT | .put(url) on the client |
-H "Content-Type: application/json" | .header("Content-Type", "application/json") |
-d '{"x":1}' | .body(r#"{"x":1}"#) |
-u user:pass | .basic_auth("user", Some("pass")) |
-b "session=abc" | .header("Cookie", "session=abc") |
-k / --insecure | ClientBuilder::new().danger_accept_invalid_certs(true).build()? |
The generated code uses the ? operator for error propagation, returning Result<(), Box<dyn std::error::Error>> from main() — the idiomatic Rust pattern for small programs and examples.
Deserializing JSON Responses
The generated code prints the response as text. To deserialize a JSON API response into a Rust struct, add serde to your dependencies:
serde = { version = "1", features = ["derive"] }
Then define your struct and use .json() on the response:
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct ApiResponse {
id: u64,
name: String,
}
let data: ApiResponse = response.json().await?;
println!("{:?}", data);
Custom Client Configuration
The generated code uses reqwest::Client::new() for straightforward requests. For production use, configure the client with timeouts:
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()?;
reqwest clients are designed to be reused across multiple requests. Create one client at application startup and clone or share it via Arc<Client> rather than constructing a new one per request.
Sending JSON Bodies with Serde
Instead of .body(r#"..."#) with a raw string, you can use .json(&payload) with a serializable struct:
use serde::Serialize;
#[derive(Serialize)]
struct Payload {
key: String,
}
let payload = Payload { key: "value".to_string() };
let response = client.post(url).json(&payload).send().await?;
This sets the Content-Type: application/json header automatically and serializes the struct.
Frequently Asked Questions
Do I need the nightly Rust toolchain?
No. reqwest and tokio both work with stable Rust. The #[tokio::main] macro and the ? operator in async fn main() have been stable since Rust 1.39 and 1.42 respectively.
Why does reqwest use async instead of synchronous requests?
reqwest is primarily designed for async code using tokio. For synchronous (blocking) use, enable the blocking feature in Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }. The blocking API does not require async/await or a tokio runtime.
How do I handle rate limiting in Rust?
Check response.status() for StatusCode::TOO_MANY_REQUESTS (429). Read the Retry-After header with response.headers().get("Retry-After") and sleep using tokio::time::sleep(Duration::from_secs(n)).await before retrying.