A C#-style HttpClient API surface for async Rust, backed by tokio + rustls.
The crate mirrors the public shape of System.Net.Http.HttpClient so callers
familiar with the .NET model can map concepts 1:1: HttpClient,
HttpRequestMessage, HttpResponseMessage, HttpMethod, HttpHeaders,
HttpContent (and its subtypes), CancellationToken. Internally the
transport is HTTP/1.1 over tokio TCP, with HTTPS via rustls.
This iteration covers the core C# surface:
HttpClientwithBaseAddress,Timeout,DefaultRequestVersion,DefaultRequestHeadersGetAsync/GetStringAsync/GetByteArrayAsync/GetStreamAsyncPostAsync/PutAsync/DeleteAsync/PatchAsync/HeadAsync/OptionsAsyncSendAsync(HttpRequestMessage, CancellationToken)HttpRequestMessagewithMethod,RequestUri,Version,VersionPolicy,Headers,ContentHttpResponseMessagewithStatusCode,Version,Headers,Content,IsSuccessStatusCode,EnsureSuccessStatusCode()HttpMethod(Get, Post, Put, Delete, Head, Options, Patch, Trace, Connect, Custom)HttpHeaders/HttpRequestHeaders/HttpResponseHeaders/HttpContentHeaders(case-insensitive, multi-valued)HttpContenttrait +StringContent,ByteArrayContent,StreamContent,FormUrlEncodedContent,MultipartContent,MultipartFormDataContentCancellationTokenwithnone,new,child_token,link_with,with_timeoutHttpVersion+HttpVersionPolicyMediaTypeHeaderValueHttpRequestException(mirrors C#'sHttpRequestException) andOperationCanceledException
Out of scope (this iteration): HTTP/2, HTTP/3, DelegatingHandler
middleware, proxies, cookies, authentication handlers, request retries.
use httpclient::{HttpClient, CancellationToken, StringContent};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = HttpClient::new();
let mut response = client
.get_async("https://httpbin.org/get", CancellationToken::none())
.await?;
println!("status: {}", response.status_code());
let body = response.content_mut().read_as_string().await?;
println!("{body}");
Ok(())
}With a body and POST:
use httpclient::{HttpClient, CancellationToken, FormUrlEncodedContent};
let client = HttpClient::new();
let form = FormUrlEncodedContent::new(vec![("a", "1"), ("b", "hello world")]);
let mut response = client
.post_async(
"https://httpbin.org/post",
Box::new(form),
CancellationToken::none(),
)
.await?;
let body = response.content_mut().read_as_string().await?;use httpclient::HttpClientBuilder;
use std::time::Duration;
use httpclient::uri::Uri;
let client = HttpClientBuilder::new()
.base_address(Some(Uri::parse("https://api.example.com/v1/")?))
.timeout(Duration::from_secs(30))
.build();use std::time::Duration;
use httpclient::CancellationToken;
let token = CancellationToken::new().with_timeout(Duration::from_secs(5));
let response = client.get_async("https://api.example.com/data", token).await;
// Returns `Err(HttpRequestError::Canceled(OperationCanceledException))` on timeout.Run any of these from the crate root:
cargo run --example basic_get
cargo run --example post_string
cargo run --example post_formcargo testThe test suite is self-contained — it uses an in-process HTTP/1.1 test
server (tests/support/server.rs) that listens on 127.0.0.1:0 and records
incoming requests for assertion. No external network, no external test
endpoints, no curl.
Coverage:
- 32 unit tests across
HttpMethod,HttpHeaders,Uri,MediaTypeHeaderValue,CancellationToken,HttpRequestException, and thetransport/h1codec. - 6 integration tests using the in-process server: GET shape, POST form, POST string, byte-array body, redirect chain, and timeout cancellation.
Apache-2.0