HTTP Clients (reqwest)
Call external HTTP APIs from Rust with reqwest - async requests, JSON, timeouts, and rustls TLS.
Search across all documentation pages
Call external HTTP APIs from Rust with reqwest - async requests, JSON, timeouts, and rustls TLS.
Quick-reference recipe card - copy-paste ready.
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()?;
let user: User = client
.get("https://api.example.com/users/1")
.bearer_auth(token)
.send()
.await?
.error_for_status()?
.json()
.await?;When to reach for this: Any Rust service integrating with REST webhooks, payment APIs, or internal microservices.
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct CreateItem { name: String }
#[derive(Deserialize)]
struct Item { id: u64, name: String }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(15))
.user_agent("my-rust-service/1.0")
.build()?;
let created: Item = client
.post("https://httpbin.org/post")
.json(&CreateItem { name: "widget".into() })
.send()
.await?
.error_for_status()?
.json()
.await?;
let status = client.get("https://httpbin.org/status/404").send().await?;
assert_eq!(status.status(), StatusCode::NOT_FOUND);
Ok(())
}What this demonstrates:
Client reused across requests (connection pooling)..json() for serde request and response bodies.error_for_status() turns 4xx/5xx into errors.Client per process maintains connection pool to hosts.rustls-tls feature for TLS without OpenSSL.| Setting | Purpose |
|---|---|
timeout | End-to-end request limit |
connect_timeout | TCP/TLS handshake cap |
pool_max_idle_per_host | Keep-alive tuning |
user_agent | Identify your service in logs |
// Reuse client in Axum State
#[derive(Clone)]
struct HttpClients { outbound: reqwest::Client }error_for_status drops useful JSON errors. Fix: Read body on failure for logging.danger_accept_invalid_certs in prod. Fix: Proper CA bundle with rustls.json().await loads all into memory. Fix: Stream with bytes_stream.| Alternative | Use When | Don't Use When |
|---|---|---|
hyper client directly | Full control | Standard REST calls |
ureq | Blocking CLI tools | Async Tokio services |
awc | Actix ecosystem | Axum/Tokio stack |
reqwest::blocking for sync contexts only.
.header("X-Request-Id", id) per request or default headers on builder.
multipart::Form for file uploads.
Client::builder().proxy(reqwest::Proxy::http(url)?).
Not built-in - see Retries page or reqwest-middleware crate.
Identity PKCS8 via rustls config on custom connector.
Enabled by default where server supports.
wiremock or mockito against handler code using injected client.
Handled by system resolver; custom hyper connector for advanced cases.
Respect Retry-After header in retry layer.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026