Loading page…
Rust walkthroughs
Loading page…
Reqwest is an ergonomic, feature-rich HTTP client built on top of hyper and tokio. It provides both blocking and async APIs, automatic JSON serialization, cookie handling, connection pooling, and TLS support. For most HTTP client needs in Rust, reqwest is the go-to choice.
Key features:
# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }use reqwest::Client;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct CreateUser {
name: String,
email: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// ===== Basic GET Request =====
let body = reqwest::get("https://httpbin.org/get")
.await?
.text()
.await?;
println!("GET response: {}", body);
// ===== Using a Client (recommended for multiple requests) =====
let client = Client::new();
// GET with query parameters
let response = client
.get("https://httpbin.org/get")
.query(&[("page", "1"), ("limit", "10")])
.send()
.await?;
println!("Status: {}", response.status());
// ===== JSON Response =====
let user: User = client
.get("https://jsonplaceholder.typicode.com/users/1")
.send()
.await?
.json()
.await?;
println!("User: {:?}", user);
// ===== POST with JSON Body =====
let new_user = CreateUser {
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
let created: User = client
.post("https://jsonplaceholder.typicode.com/users")
.json(&new_user)
.send()
.await?
.json()
.await?;
println!("Created: {:?}", created);
Ok(())
}use reqwest::{Client, header};
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct ApiResponse {
status: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut headers = header::HeaderMap::new();
headers.insert(
header::AUTHORIZATION,
header::HeaderValue::from_static("Bearer my-secret-token"),
);
headers.insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
);
let client = Client::builder()
.default_headers(headers)
.build()?;
// Request inherits default headers
let response = client
.get("https://httpbin.org/headers")
.send()
.await?;
println!("Response: {}", response.text().await?);
// ===== Per-Request Headers =====
let response = client
.get("https://httpbin.org/headers")
.header("X-Custom-Header", "custom-value")
.bearer_auth("another-token")
.basic_auth("username", Some("password"))
.send()
.await?;
println!("Status: {}", response.status());
Ok(())
}use reqwest::Client;
use serde::Serialize;
#[derive(Serialize)]
struct LoginForm {
username: String,
password: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// ===== URL-Encoded Form =====
let form = LoginForm {
username: "alice".to_string(),
password: "secret".to_string(),
};
let response = client
.post("https://httpbin.org/post")
.form(&form)
.send()
.await?;
println!("Form response: {}", response.text().await?);
// ===== Manual Form Data =====
let response = client
.post("https://httpbin.org/post")
.body("field1=value1&field2=value2")
.header("Content-Type", "application/x-www-form-urlencoded")
.send()
.await?;
println!("Status: {}", response.status());
// ===== Multipart Form (File Upload) =====
let file_content = "This is file content";
let form = reqwest::multipart::Form::new()
.text("field", "value")
.part("file", reqwest::multipart::Part::bytes(file_content.as_bytes())
.file_name("example.txt")
.mime_str("text/plain")?);
let response = client
.post("https://httpbin.org/post")
.multipart(form)
.send()
.await?;
println!("Multipart status: {}", response.status());
Ok(())
}use reqwest::{Client, StatusCode};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::builder()
.timeout(Duration::from_secs(10))
.connect_timeout(Duration::from_secs(5))
.build()?;
// ===== Error Handling =====
let response = match client.get("https://httpbin.org/status/404").send().await {
Ok(resp) => resp,
Err(e) => {
if e.is_timeout() {
eprintln!("Request timed out");
} else if e.is_connect() {
eprintln!("Connection failed");
} else {
eprintln!("Request error: {}", e);
}
return Err(e.into());
}
};
match response.status() {
StatusCode::OK => println!("Success"),
StatusCode::NOT_FOUND => println!("Not found"),
StatusCode::INTERNAL_SERVER_ERROR => println!("Server error"),
status => println!("Other status: {}", status),
}
// ===== Response Inspection =====
let response = client
.get("https://httpbin.org/get")
.send()
.await?;
println!("Status: {}", response.status());
println!("Headers:");
for (name, value) in response.headers() {
println!(" {}: {:?}", name, value);
}
// Response body can only be consumed once
let text = response.text().await?;
println!("Body length: {} bytes", text.len());
Ok(())
}use reqwest::{Client, Proxy, Certificate};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// ===== Custom Client Configuration =====
let client = Client::builder()
.timeout(Duration::from_secs(30))
.connect_timeout(Duration::from_secs(10))
.pool_max_idle_per_host(10)
.pool_idle_timeout(Duration::from_secs(60))
.user_agent("MyApp/1.0")
.redirect(reqwest::redirect::Policy::limited(5))
.build()?;
// ===== Proxy Configuration =====
#[cfg(feature = "socks")]
let proxy = Proxy::all("socks5://127.0.0.1:1080")?;
#[cfg(not(feature = "socks"))]
let proxy = Proxy::https("http://proxy.example.com:8080")?;
let client_with_proxy = Client::builder()
.proxy(proxy)
.build()?;
// ===== Cookie Store =====
let client = Client::builder()
.cookie_store(true)
.build()?;
// First request sets cookies
client.get("https://httpbin.org/cookies/set/session/abc123").send().await?;
// Second request sends cookies automatically
let response = client.get("https://httpbin.org/cookies").send().await?;
println!("Cookies: {}", response.text().await?);
Ok(())
}# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json", "blocking"] }
serde = { version = "1", features = ["derive"] }use reqwest::blocking::Client;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Post {
id: u32,
title: String,
body: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Blocking GET request
let posts: Vec<Post> = client
.get("https://jsonplaceholder.typicode.com/posts")
.query(&[("_limit", "5")])
.send()?
.json()?;
for post in posts {
println!("{}: {}", post.id, post.title);
}
Ok(())
}use reqwest::Client;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Stream response to file
let mut response = client
.get("https://httpbin.org/bytes/1024")
.send()
.await?;
let mut file = File::create("downloaded.bin").await?;
while let Some(chunk) = response.chunk().await? {
file.write_all(&chunk).await?;
}
println!("Download complete");
// Stream request body
let content = "Large content here...";
let body = reqwest::Body::wrap_stream(futures_util::stream::iter(
vec![Ok::<_, std::io::Error>(content.as_bytes().to_vec())]
));
let response = client
.post("https://httpbin.org/post")
.body(body)
.send()
.await?;
println!("Upload status: {}", response.status());
Ok(())
}reqwest::get(url) for simple one-off GET requestsClient instance for multiple requests—it enables connection pooling and cookie persistence.json(&data) automatically serializes and sets Content-Type header.form(&data) sends URL-encoded form datamultipart::Form for file uploads and mixed content.header() adds custom headers; Client::builder().default_headers() sets defaults for all requests.bearer_auth(token) and .basic_auth(user, pass) handle authentication.timeout() and .connect_timeout() to prevent hanging on slow/unreachable servers.status() returns StatusCode; check .is_success() or .is_client_error().text(), .json(), .bytes(), .chunk() for streaming.is_timeout(), .is_connect(), .is_status() help categorize failuresreqwest::blocking module for synchronous code without async runtimejson, blocking, cookies, rustls-tls (or native-tls)