ConfigsApr 13, 2026·3 min read

Reqwest — Ergonomic HTTP Client for Rust

Reqwest is the most popular HTTP client library for Rust. It provides a high-level, async API for making HTTP requests with automatic JSON serialization, TLS, cookie management, proxy support, and connection pooling — the Rust equivalent of Python requests.

AI
AI Open Source · Community
Quick Use

Use it first, then decide how deep to go

This block should tell both the user and the agent what to copy, install, and apply first.

cargo add reqwest --features json
cargo add tokio --features full
cargo add serde --features derive
use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct User {
    login: String,
    id: u64,
    public_repos: u32,
}

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    // Simple GET
    let body = reqwest::get("https://httpbin.org/ip")
        .await?
        .text()
        .await?;
    println!("{}", body);

    // JSON deserialization
    let user: User = reqwest::get("https://api.github.com/users/rust-lang")
        .await?
        .json()
        .await?;
    println!("{:?}", user);

    Ok(())
}

Introduction

Reqwest is the go-to HTTP client for Rust applications. Just as the Python requests library made HTTP simple, Reqwest brings the same ergonomics to Rust — with the added benefits of async/await, compile-time type safety, and automatic JSON serialization via Serde.

With over 12,000 GitHub stars, Reqwest is the most downloaded HTTP client on crates.io. It is used by virtually every Rust application that makes HTTP requests, from CLI tools to web scrapers to API clients.

What Reqwest Does

Reqwest handles the complete HTTP client lifecycle: building requests with headers and bodies, managing TLS connections, following redirects, handling cookies, connection pooling, timeouts, and response parsing. It supports both async (default) and blocking APIs.

Architecture Overview

[Your Rust Code]
reqwest::get(url).await?
        |
   [Reqwest Client]
   Connection pool
   Cookie jar
   Redirect policy
        |
   [Request Builder]
   Headers, body, query
   JSON serialization
   Form/multipart encoding
        |
   [hyper (HTTP engine)]
   HTTP/1.1 and HTTP/2
        |
   [rustls or native-tls]
   TLS encryption
        |
   [tokio (async runtime)]
   Async I/O

Self-Hosting & Configuration

use reqwest::{Client, header};
use serde::{Serialize, Deserialize};
use std::time::Duration;

#[derive(Serialize)]
struct CreateUser {
    name: String,
    email: String,
}

#[derive(Deserialize)]
struct ApiResponse {
    id: u64,
    status: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a reusable client with defaults
    let client = Client::builder()
        .timeout(Duration::from_secs(30))
        .default_headers({
            let mut headers = header::HeaderMap::new();
            headers.insert("Authorization", "Bearer token123".parse()?);
            headers
        })
        .user_agent("my-app/1.0")
        .build()?;

    // POST with JSON body
    let resp: ApiResponse = client
        .post("https://api.example.com/users")
        .json(&CreateUser {
            name: "Alice".into(),
            email: "alice@example.com".into(),
        })
        .send()
        .await?
        .json()
        .await?;

    // GET with query parameters
    let users: Vec<User> = client
        .get("https://api.example.com/users")
        .query(&[("page", "1"), ("limit", "10")])
        .send()
        .await?
        .json()
        .await?;

    // Download a file
    let bytes = client
        .get("https://example.com/file.pdf")
        .send()
        .await?
        .bytes()
        .await?;
    std::fs::write("file.pdf", bytes)?;

    Ok(())
}

Key Features

  • Async by Default — async/await API with tokio runtime
  • JSON Support — automatic serialization/deserialization via Serde
  • Connection Pooling — reuse connections across requests
  • TLS — rustls (pure Rust) or native-tls backends
  • Cookie Management — automatic cookie jar support
  • Redirect Following — configurable redirect policy
  • Proxy Support — HTTP, HTTPS, and SOCKS5 proxies
  • Blocking API — synchronous API available via feature flag

Comparison with Similar Tools

Feature Reqwest ureq hyper surf requests (Python)
Async Yes (default) No (blocking) Yes (low-level) Yes No (use httpx)
Ease of Use High Very High Low High Very High
JSON Built-in (Serde) Manual Manual Built-in Built-in
Connection Pool Yes Yes Manual Yes Yes
TLS rustls / native rustls Manual Manual Built-in
Best For General HTTP Simple scripts Custom HTTP async-std apps Python

FAQ

Q: Reqwest vs hyper — when should I use which? A: Reqwest for application-level HTTP requests (APIs, web scraping). hyper for building HTTP servers or when you need low-level control over the HTTP protocol.

Q: How do I use Reqwest without async? A: Enable the "blocking" feature: cargo add reqwest --features blocking. Then use reqwest::blocking::get() for synchronous requests.

Q: How do I handle errors? A: Reqwest returns reqwest::Error which implements std::error::Error. Use the ? operator for propagation, or match on error kinds (timeout, connection, decode, status).

Q: Does Reqwest support HTTP/2? A: Yes. Reqwest supports HTTP/2 via hyper. Enable with .http2_prior_knowledge() for known HTTP/2 servers, or let ALPN negotiate automatically with TLS.

Sources

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets