Reqwest Builder
A builder for reqwest requests with support for custom headers, query parameters, and body content, featuring comprehensive error handling.
Features
- Builder Pattern: Trait-based approach for converting request structures into reqwest builders
- Derive Macro: Automatic implementation generation with
reqwest-builder-derive crate
- Multiple Body Types: Support for JSON, form-encoded, multipart, and no-body requests
- Error Handling: Comprehensive error handling with detailed error messages
- File Uploads: Built-in support for file uploads with MIME type detection
- Header Management: Safe header serialization with proper error reporting
- Modular Architecture: Clean separation of concerns with well-organized modules
Error Handling
The library provides custom error types for error handling:
Explicit Error Handling
use reqwest_builder::{IntoReqwestBuilder, ReqwestBuilderError};
match request.into_reqwest_builder(&client, &base_url) {
Ok(builder) => {
}
Err(ReqwestBuilderError::HeaderError { key, value, source }) => {
eprintln!("Invalid header '{}': '{}' - {}", key, value, source);
}
Err(ReqwestBuilderError::SerializationError(msg)) => {
eprintln!("Serialization error: {}", msg);
}
Err(e) => {
eprintln!("Other error: {}", e);
}
}
Error Types
The library provides detailed error information through the ReqwestBuilderError enum:
SerializationError: Issues with JSON serialization
HeaderError: Invalid header names or values
UrlError: URL construction problems
IoError: File I/O errors
InvalidRequest: General request configuration issues
Installation
Add this to your Cargo.toml:
[dependencies]
reqwest-builder = "0.2.0"
reqwest-builder = { version = "0.2.0", features = ["derive"] }
Derive Macro (Recommended)
For easier usage, you can use the reqwest-builder-derive crate to automatically implement the IntoReqwestBuilder trait:
use reqwest_builder::IntoReqwestBuilder;
use serde::Serialize;
#[derive(Serialize, IntoReqwestBuilder)]
#[request(method = "POST", path = "/users/{id}/posts")]
struct CreatePostRequest {
#[path_param]
id: u64,
#[query]
draft: Option<bool>,
#[header(name = "Authorization")]
auth_token: String,
title: String,
content: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest_middleware::ClientBuilder::new(reqwest::Client::new()).build();
let base_url = url::Url::parse("https://api.example.com")?;
let request = CreatePostRequest {
id: 123,
draft: Some(true),
auth_token: "Bearer token123".to_string(),
title: "My Post".to_string(),
content: "Post content here".to_string(),
};
let builder = request.into_reqwest_builder(&client, &base_url)?;
let response = builder.send().await?;
println!("Status: {}", response.status());
Ok(())
}
See the reqwest-builder-derive README for complete documentation on all available attributes and usage patterns.
Manual Implementation
If you prefer to implement the trait manually or need more control, here's how to do it:
use reqwest_builder::{IntoReqwestBuilder, RequestBody, FileUpload};
use serde::Serialize;
#[derive(Serialize)]
struct CreateUserRequest {
name: String,
email: String,
}
#[derive(Serialize)]
struct AuthHeaders {
#[serde(rename = "Authorization")]
authorization: String,
#[serde(rename = "Content-Type")]
content_type: String,
}
impl IntoReqwestBuilder for CreateUserRequest {
type Headers = AuthHeaders;
fn method(&self) -> http::Method {
http::Method::POST
}
fn endpoint(&self) -> String {
"/users".to_string()
}
fn headers(&self) -> Option<Self::Headers> {
Some(AuthHeaders {
authorization: "Bearer token123".to_string(),
content_type: "application/json".to_string(),
})
}
fn body(&self) -> RequestBody {
RequestBody::Json
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest_middleware::ClientBuilder::new(reqwest::Client::new()).build();
let base_url = url::Url::parse("https://api.example.com")?;
let request = CreateUserRequest {
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
};
let builder = request.into_reqwest_builder(&client, &base_url)?;
let response = builder.send().await?;
println!("Status: {}", response.status());
Ok(())
}
File Upload Example
use reqwest_builder::{FileUpload, IntoReqwestBuilder, RequestBody};
let file = FileUpload::from_path("document.pdf")?;
let file = FileUpload::from_bytes(
"data.json".to_string(),
b"{}".to_vec(),
Some("application/json".to_string())
);