Zenwave
Async HTTP client for Rust. Works on native (Tokio/Hyper, Apple URLSession, libcurl) and wasm32 (Fetch API). Same API everywhere, middleware you compose yourself.
Getting started
[]
= "0.5"
use ;
async
get, post, put, delete are one-shot convenience functions. For anything
more involved, build a client:
use Duration;
use ;
async
Every method on Client (enable_cache, timeout, bearer_auth, basic_auth,
enable_cookie, retry, .with(custom_middleware)) wraps the client in another
middleware layer. Order matters — the outermost layer runs first.
Request builder
Once you have a client, .get(url), .post(url), etc. return a RequestBuilder.
It has methods for setting the request and methods for reading the response:
Setting the request:
.header(name, value), .bearer_auth(token), .basic_auth(user, pass),
.json_body(&T), .bytes_body(vec), .file_body("path").await,
.reader_body(reader, len), .stream_body(stream)
Reading the response (consume the RequestBuilder by awaiting, then call on
Response, or call directly on the builder as a shortcut):
.json::<T>(), .string(), .bytes(), .form::<T>(), .sse()
The ResponseExt trait adds .into_json::<T>(), .into_string(), .into_bytes(),
.into_sse(), .error_for_status() directly on Response.
Middleware
All built-in features are middleware. You can write your own by implementing
the Middleware trait from http-kit and passing it to .with().
Built-in middleware:
| Method | What it does |
|---|---|
.timeout(duration) |
Fails with 504 if the request takes longer than duration |
.enable_cache() |
RFC-compliant Cache-Control / ETag / Last-Modified caching in memory |
.enable_cookie() |
In-memory cookie jar |
.enable_persistent_cookie() |
Cookie jar backed by a file on disk (native only) |
.bearer_auth(token) |
Adds Authorization: Bearer <token> to every request |
.basic_auth(user, pass) |
Adds Authorization: Basic <base64> to every request |
.retry(n) |
Retries failed requests up to n times |
.with(OAuth2ClientCredentials::new(...)) |
Client-credentials OAuth2 flow with automatic refresh |
Redirects are on by default. Call zenwave::client().disable_redirect() to get the
raw backend, or use zenwave::raw_client().
File downloads with resume
use Client;
async
If the file already exists, zenwave sends a Range header and appends. Pass
DownloadOptions { resume_existing: false } via .download_to_path_with() to
start from scratch. Native only.
WebSockets
Requires the ws feature (on by default). Uses async-tungstenite on native,
web_sys::WebSocket on wasm.
use ;
async
You can split a connection for concurrent send/recv:
# use websocket;
# async
Proxy support
Available with the hyper-backend or curl-backend features (native only).
use Proxy;
// Read HTTP_PROXY / HTTPS_PROXY / NO_PROXY from env
let proxy = from_env;
// Or build manually — supports http, socks4, socks4a, socks5, socks5h
let proxy = builder
.http
.no_proxy
.build;
Backends and feature flags
On wasm32, the built-in Fetch backend is used automatically. No feature selection needed or available.
On native, pick a backend:
| Feature | Backend | TLS | Notes |
|---|---|---|---|
hyper-backend + rustls |
Hyper | rustls | Default. |
hyper-backend + native-tls |
Hyper | Platform native | OpenSSL / SChannel / Security.framework |
curl-backend |
libcurl | libcurl's | Smaller binary if you have system libcurl |
apple-backend |
URLSession | Security.framework | Experimental. macOS/iOS only |
The default feature enables hyper-backend, both TLS implementations (the right
one is selected at compile time based on target), and ws.
Common dependency lines:
# Default — hyper + platform-appropriate TLS + websockets
= "0.5"
# Hyper with only rustls
= { = "0.5", = false, = ["hyper-rustls", "ws"] }
# Curl backend
= { = "0.5", = false, = ["curl-backend"] }
# Apple URLSession
= { = "0.5", = false, = ["apple-backend"] }
Other features: proxy (auto-enabled by curl-backend), ws (websocket support).
Examples
License
MIT