Axiosにインスパイアされた、Rust用のシンプルで強力なHTTPクライアントライブラリです。ドメイン駆動設計(DDD)の原則に基づいて構築されており、クリーンで保守しやすいアーキテクチャを提供します。
- 🚀 非同期対応 - Tokioランタイムを使用した高性能な非同期処理
- 🔧 全HTTPメソッド対応 - GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT, TRACE
- 📦 JSONサポート - serdeによる自動シリアライゼーション/デシリアライゼーション
- 🔒 認証サポート - Bearer認証、カスタムヘッダー
- ⏱️ タイムアウト設定 - リクエスト単位でのタイムアウト制御
- 🎯 Axios風API - JavaScriptエンジニアにも馴染みやすいインターフェース
- 🏗️ DDD設計 - クリーンアーキテクチャによる保守性の高い実装
- 🧪 テスタブル - モックリポジトリインターフェースによるテストの容易性
Cargo.tomlに以下を追加:
[dependencies]
rust-http-client = "0.1.0"
tokio = { version = "1.40", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"use rust_http_client::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let response = client.get("https://api.example.com/users").await?;
println!("Status: {}", response.status.as_u16());
// JSONとしてパース
let users: Vec<serde_json::Value> = response.json()?;
println!("Users: {:?}", users);
Ok(())
}use rust_http_client::axios_style;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// グローバル関数を使用
let response = axios_style::get("https://api.example.com/posts").await?;
// POSTリクエスト
let data = serde_json::json!({
"title": "Hello",
"content": "World"
});
let post_response = axios_style::post("https://api.example.com/posts", data).await?;
Ok(())
}use rust_http_client::{Client, ClientBuilder, HttpMethod};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// カスタム設定でクライアントを作成
let client = ClientBuilder::new()
.user_agent("MyApp/1.0")
.timeout(Duration::from_secs(10))
.default_header("X-Api-Key", "your-api-key")
.build();
// リクエストビルダーを使用
let response = client
.request(HttpMethod::Get, "https://api.example.com/protected")
.bearer_token("your-jwt-token")
.query("page", "1")
.query("limit", "20")
.send()
.await?;
Ok(())
}このライブラリはドメイン駆動設計(DDD)の原則に基づいて構築されています:
src/
├── domain/ # ドメイン層
│ ├── entities/ # エンティティ(HttpRequest, HttpResponse)
│ ├── value_objects/ # 値オブジェクト(HttpMethod, Url, Headers)
│ └── repositories/ # リポジトリインターフェース
├── application/ # アプリケーション層
│ └── services/ # ビジネスロジック
├── infrastructure/ # インフラストラクチャ層
│ └── http/ # Hyper実装
└── presentation/ # プレゼンテーション層
└── client.rs # 公開API
graph TB
subgraph "Presentation Layer"
Client[Client API]
AxiosStyle[Axios-style API]
RequestBuilder[Request Builder]
end
subgraph "Application Layer"
HttpClientService[HttpClientService]
ServiceBuilder[Service Request Builder]
end
subgraph "Domain Layer"
subgraph "Entities"
HttpRequest[HttpRequest]
HttpResponse[HttpResponse]
RequestBody[RequestBody]
ResponseBody[ResponseBody]
end
subgraph "Value Objects"
HttpMethod[HttpMethod]
Url[URL]
Headers[Headers]
StatusCode[StatusCode]
end
subgraph "Repositories"
HttpClientRepo[HttpClientRepository<br/><<interface>>]
end
end
subgraph "Infrastructure Layer"
HyperClient[HyperHttpClient]
HyperLib[(Hyper Library)]
end
subgraph "External"
HTTPServer[HTTP Server<br/>External API]
end
%% Presentation to Application
Client --> HttpClientService
AxiosStyle --> Client
RequestBuilder --> ServiceBuilder
%% Application to Domain
HttpClientService --> HttpRequest
HttpClientService --> HttpResponse
HttpClientService --> HttpClientRepo
ServiceBuilder --> HttpRequest
%% Domain relationships
HttpRequest --> HttpMethod
HttpRequest --> Url
HttpRequest --> Headers
HttpRequest --> RequestBody
HttpResponse --> StatusCode
HttpResponse --> Headers
HttpResponse --> ResponseBody
%% Infrastructure implements Domain
HyperClient -.->|implements| HttpClientRepo
%% Infrastructure to External
HyperClient --> HyperLib
HyperLib --> HTTPServer
%% Styling
classDef domainStyle fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef appStyle fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef infraStyle fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef presentStyle fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
classDef externalStyle fill:#ffebee,stroke:#b71c1c,stroke-width:2px
class HttpRequest,HttpResponse,RequestBody,ResponseBody,HttpMethod,Url,Headers,StatusCode,HttpClientRepo domainStyle
class HttpClientService,ServiceBuilder appStyle
class HyperClient,HyperLib infraStyle
class Client,AxiosStyle,RequestBuilder presentStyle
class HTTPServer externalStyle
sequenceDiagram
participant User
participant Client as Client/Axios API
participant Service as HttpClientService
participant Request as HttpRequest Entity
participant Repo as HttpClientRepository
participant Hyper as HyperHttpClient
participant Server as External Server
User->>Client: client.get(url)
Client->>Service: get(url)
Service->>Request: Create HttpRequest
Service->>Service: Apply defaults
Service->>Repo: send(request)
Repo->>Hyper: send(request)
Hyper->>Hyper: Convert to Hyper Request
Hyper->>Server: HTTP GET
Server-->>Hyper: HTTP Response
Hyper->>Hyper: Parse Response
Hyper-->>Repo: HttpResponse
Repo-->>Service: HttpResponse
Service-->>Client: HttpResponse
Client-->>User: Response Data
graph LR
subgraph "Clean Architecture Layers"
direction TB
Presentation[Presentation Layer]
Application[Application Layer]
Domain[Domain Layer]
Infrastructure[Infrastructure Layer]
end
Presentation --> Application
Application --> Domain
Infrastructure --> Domain
%% Styling
classDef clean fill:#f9f9f9,stroke:#333,stroke-width:2px
class Presentation,Application,Domain,Infrastructure clean
flowchart LR
subgraph User["User Application"]
UserCode[User Code]
end
subgraph PublicAPI["Public API"]
direction TB
ClientNew[Client::new]
ClientBuilder[Client::builder]
AxiosGet[axios_style::get]
AxiosPost[axios_style::post]
end
subgraph Core["Core Components"]
direction TB
Service[HttpClientService]
Repository[HttpClientRepository]
Entities[Domain Entities]
end
subgraph Network["Network Layer"]
HyperImpl[Hyper Implementation]
TLS[TLS Support]
end
UserCode --> PublicAPI
PublicAPI --> Service
Service --> Repository
Service --> Entities
Repository <-.-> HyperImpl
HyperImpl --> TLS
TLS --> Internet[Internet]
%% Styling
classDef userStyle fill:#bbdefb,stroke:#1976d2
classDef apiStyle fill:#c8e6c9,stroke:#388e3c
classDef coreStyle fill:#fff9c4,stroke:#f57c00
classDef netStyle fill:#ffccbc,stroke:#d84315
class UserCode userStyle
class ClientNew,ClientBuilder,AxiosGet,AxiosPost apiStyle
class Service,Repository,Entities coreStyle
class HyperImpl,TLS netStyle
-
ドメイン層: ビジネスルールとドメインモデルを定義
- HTTPプロトコルの概念をモデル化(Request, Response, Method, Headers等)
- ビジネスルールの実装(ステータスコードの判定、URLの検証等)
- 外部依存を持たない純粋なビジネスロジック
-
アプリケーション層: ユースケースとビジネスロジックを実装
- HTTPリクエストの組み立てと送信の調整
- デフォルト設定の適用
- エラーハンドリングの統一
-
インフラストラクチャ層: 外部システムとの通信を実装
- Hyperライブラリを使用した実際のHTTP通信
- ドメイン層のインターフェースの具体的な実装
- ネットワークレベルの処理
-
プレゼンテーション層: ユーザー向けの使いやすいAPIを提供
- 直感的なメソッド名とインターフェース
- ビルダーパターンによる柔軟な設定
- Axios風のグローバル関数
use rust_http_client::Client;
use serde::{Serialize, Deserialize};
#[derive(Serialize)]
struct CreateUser {
name: String,
email: String,
}
#[derive(Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let new_user = CreateUser {
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
};
let response = client.post("https://api.example.com/users", new_user).await?;
if response.status.is_success() {
let user: User = response.json()?;
println!("Created user with ID: {}", user.id);
}
Ok(())
}use rust_http_client::{Client, HttpMethod};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let mut form_data = HashMap::new();
form_data.insert("username".to_string(), "john_doe".to_string());
form_data.insert("password".to_string(), "secure123".to_string());
let response = client
.request(HttpMethod::Post, "https://api.example.com/login")
.form(form_data)
.send()
.await?;
Ok(())
}use rust_http_client::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let response = client.get("https://api.example.com/resource").await?;
match response.status.as_u16() {
200..=299 => {
println!("Success!");
}
401 => {
println!("Unauthorized. Please check your credentials.");
}
404 => {
println!("Resource not found.");
}
500..=599 => {
println!("Server error occurred.");
}
_ => {
println!("Unexpected status: {}", response.status.as_u16());
}
}
Ok(())
}cargo run# シンプルなGETリクエスト
cargo run --example simple_get
# JSONのPOST
cargo run --example post_json
# 高度な使用例
cargo run --example advanced_usage# ユニットテストの実行
cargo test
# 統合テストを含むすべてのテストの実行
cargo test --all-featuresメインのHTTPクライアント
new()- 新しいクライアントインスタンスを作成builder()- クライアントビルダーを取得get(url)- GETリクエストを送信post(url, body)- POSTリクエストを送信put(url, body)- PUTリクエストを送信delete(url)- DELETEリクエストを送信patch(url, body)- PATCHリクエストを送信request(method, url)- カスタムリクエストビルダーを作成
クライアントをカスタマイズするためのビルダー
default_header(key, value)- デフォルトヘッダーを設定timeout(duration)- タイムアウトを設定user_agent(agent)- User-Agentを設定build()- クライアントを構築
リクエストをカスタマイズするためのビルダー
header(key, value)- ヘッダーを追加json(body)- JSONボディを設定text(body)- テキストボディを設定form(data)- フォームデータを設定query(key, value)- クエリパラメータを追加bearer_token(token)- Bearer認証トークンを設定timeout(duration)- タイムアウトを設定send()- リクエストを送信
HTTPレスポンス
status- ステータスコードheaders- レスポンスヘッダーjson<T>()- JSONとしてパースtext()- テキストとして取得bytes()- バイト配列として取得
- リトライメカニズム
- インターセプター
- プロキシサポート
- WebSocketサポート
- ストリーミングレスポンス
- ファイルアップロード/ダウンロード
- キャッシング
- レート制限
- メトリクスとロギング
プルリクエストやイシューの報告を歓迎します!
MIT License
Your Name
このライブラリは以下のプロジェクトにインスパイアされています: