Skip to content

Kazy1014/rust-http-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust HTTP Client

Rust License: MIT

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"

クイックスタート

シンプルなGETリクエスト

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(())
}

Axios風のグローバル関数

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
Loading

データフロー図

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
Loading

依存関係の方向

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
Loading

コンポーネント間の相互作用

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
Loading

層の責務

  • ドメイン層: ビジネスルールとドメインモデルを定義

    • HTTPプロトコルの概念をモデル化(Request, Response, Method, Headers等)
    • ビジネスルールの実装(ステータスコードの判定、URLの検証等)
    • 外部依存を持たない純粋なビジネスロジック
  • アプリケーション層: ユースケースとビジネスロジックを実装

    • HTTPリクエストの組み立てと送信の調整
    • デフォルト設定の適用
    • エラーハンドリングの統一
  • インフラストラクチャ層: 外部システムとの通信を実装

    • Hyperライブラリを使用した実際のHTTP通信
    • ドメイン層のインターフェースの具体的な実装
    • ネットワークレベルの処理
  • プレゼンテーション層: ユーザー向けの使いやすいAPIを提供

    • 直感的なメソッド名とインターフェース
    • ビルダーパターンによる柔軟な設定
    • Axios風のグローバル関数

高度な使用例

POSTリクエストでJSONを送信

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

API リファレンス

Client

メインのHTTPクライアント

  • new() - 新しいクライアントインスタンスを作成
  • builder() - クライアントビルダーを取得
  • get(url) - GETリクエストを送信
  • post(url, body) - POSTリクエストを送信
  • put(url, body) - PUTリクエストを送信
  • delete(url) - DELETEリクエストを送信
  • patch(url, body) - PATCHリクエストを送信
  • request(method, url) - カスタムリクエストビルダーを作成

ClientBuilder

クライアントをカスタマイズするためのビルダー

  • default_header(key, value) - デフォルトヘッダーを設定
  • timeout(duration) - タイムアウトを設定
  • user_agent(agent) - User-Agentを設定
  • build() - クライアントを構築

RequestBuilder

リクエストをカスタマイズするためのビルダー

  • header(key, value) - ヘッダーを追加
  • json(body) - JSONボディを設定
  • text(body) - テキストボディを設定
  • form(data) - フォームデータを設定
  • query(key, value) - クエリパラメータを追加
  • bearer_token(token) - Bearer認証トークンを設定
  • timeout(duration) - タイムアウトを設定
  • send() - リクエストを送信

HttpResponse

HTTPレスポンス

  • status - ステータスコード
  • headers - レスポンスヘッダー
  • json<T>() - JSONとしてパース
  • text() - テキストとして取得
  • bytes() - バイト配列として取得

今後の実装予定

  • リトライメカニズム
  • インターセプター
  • プロキシサポート
  • WebSocketサポート
  • ストリーミングレスポンス
  • ファイルアップロード/ダウンロード
  • キャッシング
  • レート制限
  • メトリクスとロギング

コントリビューション

プルリクエストやイシューの報告を歓迎します!

ライセンス

MIT License

作者

Your Name

謝辞

このライブラリは以下のプロジェクトにインスパイアされています:

  • Axios - JavaScriptのHTTPクライアント
  • Hyper - Rust用HTTPライブラリ
  • Reqwest - Rust用HTTPクライアント

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors