| Crates.io | frakt |
| lib.rs | frakt |
| version | 0.1.0 |
| created_at | 2025-09-29 01:52:33.353715+00 |
| updated_at | 2025-09-29 01:52:33.353715+00 |
| description | Ergonomic platform HTTP client bindings for Rust |
| homepage | |
| repository | https://github.com/bbqsrc/frakt |
| max_upload_size | |
| id | 1858805 |
| size | 495,119 |
High-performance, async-first HTTP client for Rust. Cross-platform with native backends: NSURLSession on Apple platforms, WinHTTP on Windows, and Reqwest elsewhere.
Add this to your Cargo.toml:
[dependencies]
frakt = "0.1"
The library automatically selects the best native backend for each platform. You can also manually specify a backend using BackendType if needed.
use frakt::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a client
let client = Client::builder()
.user_agent("MyApp/1.0")
.timeout(std::time::Duration::from_secs(30))
.build()?;
// Make a GET request
let response = client
.get("https://httpbin.org/json")
.header("Accept", "application/json")
.send()
.await?;
println!("Status: {}", response.status());
let json: serde_json::Value = response.json().await?;
println!("Response: {}", json);
Ok(())
}
// GET request
let response = client.get("https://api.example.com/data").send().await?;
// POST with JSON
let response = client
.post("https://api.example.com/users")
.header("Content-Type", "application/json")
.body(r#"{"name": "John", "email": "john@example.com"}"#)
.send()
.await?;
use frakt::Auth;
// Basic authentication
let response = client
.get("https://api.example.com/protected")
.auth(Auth::Basic {
username: "user".to_string(),
password: "pass".to_string(),
})
.send()
.await?;
// Bearer token
let response = client
.get("https://api.example.com/protected")
.auth(Auth::Bearer {
token: "your-token".to_string(),
})
.send()
.await?;
let response = client
.get("https://example.com/large-file.zip")
.progress(|downloaded, total| {
if let Some(total) = total {
let percent = (downloaded as f64 / total as f64) * 100.0;
println!("Progress: {:.1}%", percent);
}
})
.send()
.await?;
// Download directly to file
client
.download("https://example.com/file.zip")
.to_file("./downloads/file.zip")
.progress(|downloaded, total| {
println!("Downloaded: {} / {:?} bytes", downloaded, total);
})
.send()
.await?;
use frakt::{Message, CloseCode};
let websocket = client
.websocket()
.maximum_message_size(1024 * 1024)
.connect("wss://echo.websocket.org")
.await?;
// Send message
websocket.send(Message::text("Hello, WebSocket!")).await?;
// Receive message
let message = websocket.receive().await?;
match message {
Message::Text(text) => println!("Received: {}", text),
Message::Binary(data) => println!("Received {} bytes", data.len()),
}
// Close connection
websocket.close(CloseCode::Normal, Some("Goodbye"));
let client = Client::builder()
.use_cookies(true)
.build()?;
// Cookies are automatically managed
let response = client.get("https://httpbin.org/cookies/set/session/abc123").send().await?;
let response = client.get("https://httpbin.org/cookies").send().await?; // Cookie sent automatically
let client = Client::builder()
.http_proxy("proxy.example.com", 8080)
.proxy_auth("username", "password")
.build()?;
use tokio::io::AsyncReadExt;
let response = client.get("https://example.com/large-file").send().await?;
let mut stream = response.stream();
let mut buffer = [0u8; 8192];
while let bytes_read = stream.read(&mut buffer).await? {
if bytes_read == 0 { break; }
// Process chunk
process_chunk(&buffer[..bytes_read]);
}
Run examples with cargo run --example <name>:
auth - Authentication methods (Basic, Bearer, Custom)cookies - Cookie management and automatic handlingdownload - Basic file downloadsfile_download - Direct-to-file downloads with progressfile_upload - File uploads using Body::from_file()multipart - Multipart form data uploadsprogress - Progress tracking for downloadsproxy - Proxy configuration (HTTP/HTTPS/SOCKS)streaming - Streaming large responses with AsyncReadupload_task - Upload tasks with progress trackingwebsocket - WebSocket client usagebackground_download - Background downloads (iOS)This library provides a unified HTTP client interface with platform-native backends. On Apple platforms, it uses direct Rust bindings to NSURLSession via objc2. On Windows, it uses WinHTTP APIs. On other platforms, it uses the battle-tested Reqwest library. Key design principles:
All errors are mapped to Rust's Result type:
use frakt::Error;
match client.get("https://invalid-url").send().await {
Ok(response) => println!("Success: {}", response.status()),
Err(Error::InvalidUrl) => println!("Invalid URL"),
Err(Error::Network(msg)) => println!("Network error: {}", msg),
Err(Error::Timeout) => println!("Request timed out"),
Err(e) => println!("Other error: {}", e),
}
frakt leverages platform-native performance optimizations:
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.