3 unstable releases
Uses new Rust 2024
| new 0.2.1 | Mar 13, 2026 |
|---|---|
| 0.2.0 | Mar 13, 2026 |
| 0.1.0 | Aug 19, 2024 |
#1311 in Configuration
110KB
2K
SLoC
Caller For Rust
English | 简体中文
A flexible, configurable Web API request library built with Rust, supporting multiple API endpoints management through configuration files.
Features
- 🚀 Async Calls: Built on Tokio async runtime, supports high concurrency requests
- ⚡ Configuration Management: Define API endpoints through configuration files (JSON/YAML/TOML)
- 🔄 Hot Reload: Support for configuration file hot reload, update configuration without restarting
- 📥 File Download: Built-in file download functionality with automatic format detection
- 🔁 Retry Mechanism: Automatic retry with exponential backoff for failed requests
- 🔐 Authentication Support: Built-in multiple authentication mechanisms (header, query, basic auth)
- 📊 Result Parsing: Powerful JSON result parsing with deep path access
- 🛡️ Error Handling: Comprehensive error types and error handling mechanisms
- 🧪 Test Coverage: Built-in comprehensive unit and integration tests
- 🏗️ Modular Architecture: Clear layered architecture, easy to extend and maintain
Architecture Design
Project Structure
src/
├── core/ # Core business logic
│ ├── context.rs # Call context management
│ └── constants.rs # Constant definitions
├── domain/ # Domain models
│ ├── api_item.rs # API item definitions
│ ├── api_result.rs # API response results
│ ├── authorization.rs # Authentication related
│ ├── caller_config.rs # Call configuration
│ ├── download_result.rs # Download result handling
│ ├── retry_config.rs # Retry configuration
│ └── service_item.rs # Service item definitions
├── config/ # Configuration management
│ └── config_loader.rs # Configuration loader
├── infra/ # Infrastructure layer
│ └── http.rs # HTTP client wrapper
└── shared/ # Shared modules
└── error.rs # Error definitions
Workflow
- Configuration Loading: Load API configuration from file (JSON/YAML/TOML)
- Context Management: Manage call context and middleware
- HTTP Call: Construct and send HTTP requests (with optional retry)
- Result Processing: Parse and format response results
Quick Start
Add Dependency
[dependencies]
caller = "0.2.0"
tokio = { version = "1.0", features = ["full"] }
Basic Usage
use caller::call;
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Simple call
let result = call("JP.list", None).await?;
// Parse result
println!("Status: {}", result.status_code);
println!("Raw response: {}", result.raw);
// Get specific field
if let Some(first_title) = result.get_as_str("0.title") {
println!("First post title: {}", first_title);
}
// Call with parameters
let params = HashMap::from([
("post_id".to_string(), "1".to_string()),
("userId".to_string(), "1".to_string()),
]);
let result = call("JP.get", Some(params)).await?;
Ok(())
}
Call with Retry
use caller::{call_with_retry, RetryConfig};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create retry configuration
let retry_config = RetryConfig::new()
.with_max_retries(3)
.with_base_delay(Duration::from_millis(500))
.with_max_delay(Duration::from_secs(30));
// Call with automatic retry
let result = call_with_retry("JP.list", None, retry_config).await?;
Ok(())
}
File Download
use caller::download;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Download file with auto-detected format
let result = download("api.download", None, None).await?;
println!("Downloaded {} bytes", result.size_human());
// Save to file
result.save("./downloads", "myfile")?;
// Download with specified file extension
let result = download("api.pdf", None, Some("pdf".to_string())).await?;
result.save("./downloads", "document")?;
Ok(())
}
Configuration File
Create a configuration file to define API endpoints. Supports JSON, YAML, and TOML formats.
JSON Example (caller.json)
{
"Authorizations": [
{
"Name": "BearerToken",
"HeaderName": "Authorization",
"Type": "Bearer",
"Token": "your-token-here"
}
],
"ServiceItems": [
{
"ApiName": "weibo",
"BaseUrl": "https://weibo.com/ajax",
"ApiItems": [
{
"Method": "hot",
"Url": "/side/hotSearch",
"HttpMethod": "GET",
"ParamType": "query",
"Description": "Get Weibo hot search",
"Timeout": 5000,
"NeedCache": true,
"CacheTime": 300
}
]
},
{
"ApiName": "JP",
"BaseUrl": "https://jsonplaceholder.typicode.com",
"ApiItems": [
{
"Method": "get",
"Url": "/posts/{post_id}",
"HttpMethod": "GET",
"ParamType": "path"
},
{
"Method": "create",
"Url": "/posts",
"HttpMethod": "POST",
"ParamType": "json",
"ContentType": "application/json",
"AuthorizationType": "BearerToken"
}
]
}
]
}
Parameter Types
| Parameter Type | Description | Example |
|---|---|---|
none |
No parameters | /posts |
query |
Query parameters | /posts?userId=1&id=1 |
path |
Path parameters | /posts/1 |
json |
JSON request body | {"title": "Hello", "body": "World"} |
path,json |
Path parameters + JSON body | /posts/1 + {"title": "Updated"} |
API Reference
Main Types
ApiResult
pub struct ApiResult {
pub status_code: StatusCode,
pub raw: String,
pub j_obj: Value,
}
DownloadResult
pub struct DownloadResult {
pub status_code: StatusCode,
pub content: Vec<u8>,
pub content_type: String,
pub file_extension: String,
pub suggested_filename: Option<String>,
}
RetryConfig
pub struct RetryConfig {
pub max_retries: u32,
pub base_delay: Duration,
pub max_delay: Duration,
pub retry_status_codes: Vec<u16>,
pub retry_on_network_error: bool,
}
CallerError
pub enum CallerError {
ConfigError(String),
HttpError(reqwest::Error),
JsonError(String),
IoError(String),
ServiceNotFound(String),
MethodNotFound(String),
ParamMissing(String),
AuthenticationError(String),
}
Core Methods
api_result.get_as_str(key: &str) -> Option<&str>
Get string value, supports deep path like "0.title"
api_result.get_as_i64(key: &str) -> Option<i64>
Get integer value
api_result.get_as_bool(key: &str) -> Option<bool>
Get boolean value
api_result.get(key: &str) -> Option<&Value>
Get native JSON value
download_result.save<P: AsRef<Path>>(directory: P, base_name: &str) -> Result<String, CallerError>
Save downloaded content to file, returns the filename
download_result.size_human() -> String
Get human-readable file size (e.g., "1.23 MB")
Public API Functions
call(method: &str, params: Option<HashMap<String, String>>) -> Result<ApiResult, CallerError>
use caller::call;
use std::collections::HashMap;
// Call without parameters
let result = call("JP.list", None).await?;
// Call with parameters
let params = HashMap::from([
("post_id".to_string(), "1".to_string()),
]);
let result = call("JP.get", Some(params)).await?;
call_with_retry(method: &str, params: Option<HashMap<String, String>>, retry_config: RetryConfig) -> Result<ApiResult, CallerError>
use caller::{call_with_retry, RetryConfig};
use std::time::Duration;
let retry_config = RetryConfig::new()
.with_max_retries(3)
.with_base_delay(Duration::from_millis(500));
let result = call_with_retry("JP.list", None, retry_config).await?;
download(method: &str, params: Option<HashMap<String, String>>, extension: Option<String>) -> Result<DownloadResult, CallerError>
use caller::download;
// Download with auto-detected format
let result = download("api.download", None, None).await?;
result.save("./downloads", "file")?;
// Download with specified extension
let result = download("api.pdf", None, Some("pdf".to_string())).await?;
Configuration Management
init_config() -> Result<(), CallerError>
Initialize configuration by loading from file
reload_config() -> Result<(), CallerError>
Manually reload configuration from file
watch_config() -> Result<(), CallerError>
Start watching config file for changes (500ms debounce)
watch_config_with_debounce(debounce: Duration) -> Result<(), CallerError>
Start watching with custom debounce time
stop_watch_config()
Stop watching config file
is_watching_config() -> bool
Check if config is currently being watched
is_config_loaded() -> bool
Check if configuration is loaded
use caller::{init_config, watch_config, stop_watch_config, is_watching_config};
// Initialize configuration
init_config()?;
// Start file watching
watch_config()?;
// Check status
if is_watching_config() {
println!("Configuration file is being watched");
}
// Stop watching
stop_watch_config();
Multi-Format Configuration Support
Caller supports multiple configuration file formats:
Supported Formats
- JSON (
.json) - YAML (
.yaml,.yml) - TOML (
.toml)
Format Conversion
use caller::config::config_loader::{ConfigLoader, ConfigFormat};
// Convert between formats
ConfigLoader::convert_config("config.json", "config.yaml")?;
ConfigLoader::convert_config("config.yaml", "config.toml")?;
// Explicit format specification
ConfigLoader::convert_config_with_format(
"config.json",
"output.txt",
ConfigFormat::Yaml
)?;
See docs/MULTI_FORMAT_CONFIG.md for detailed documentation.
Testing
Run all tests:
cargo test
Run specific tests:
cargo test test_call_list_posts
Build and Release
# Build
cargo build
# Run examples
cargo run --example basic_usage
# Format code
cargo fmt
# Check code
cargo check
Contributing
- Fork this repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Create a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details
Changelog
v0.2.0
- Multi-format Configuration Support: Add support for JSON, YAML, and TOML configuration file formats
- Configuration Format Conversion: Add configuration file format conversion capabilities (convert between JSON, YAML, and TOML)
- File Download: Add file download functionality with automatic format detection
- Retry Mechanism: Add automatic retry with exponential backoff for failed requests
- Retry Configuration: Add configurable retry behavior with
RetryConfig - Download Result: Add comprehensive download result handling with
DownloadResult - Serialization Support: Add Serialize trait to all configuration structures
- Complete Examples: Create complete configuration file examples in all three formats
- Comprehensive Tests: Add 16 multi-format configuration test cases
- Documentation: Update documentation to explain new features and multi-format support
v0.1.0
- Initial release
- Support for configuration-based API calls
- Support for multiple HTTP methods and parameter types
- Built-in authentication and caching support
- Comprehensive error handling
- Full test coverage
Dependencies
~9–25MB
~306K SLoC