Resty

Go向けのシンプルなHTTPおよびRESTクライアント。net/httpの内部的な使用によりパフォーマンスを維持しながら、より使いやすいAPIを提供。自動JSON/XML解析、OAuth/Bearer認証、リトライ機能、デバッグ、ミドルウェアサポートを内蔵。

HTTPクライアントGoRESTミドルウェア認証JSON

GitHub概要

go-resty/resty

Simple HTTP, REST, and SSE client library for Go

ホームページ:https://resty.dev
スター11,056
ウォッチ100
フォーク764
作成日:2015年8月28日
言語:Go
ライセンス:MIT License

トピックス

backoffcircuit-breakercurl-commanddigest-authenticationgogo-librarygo-restygolanggolang-libraryhacktoberfesthttp-clienthttp-traceload-balancermiddlewareredirectsrest-clientretryservice-discoverysrv-recordsse-client

スター履歴

go-resty/resty Star History
データ取得日時: 2025/7/18 01:38

ライブラリ

Resty

概要

Restyは「Go言語向けのシンプルで機能豊富なHTTP/RESTクライアント」として開発された、GoエコシステムでネイティブのHTTPクライアントとして広く採用されている高レベルHTTPライブラリです。「シンプルさと豊富な機能の両立」を重視して設計され、net/httpパッケージ上に構築された強力な抽象化により、チェイン可能なAPI、自動リトライ機能、ミドルウェアシステム、多様な認証オプション、JSON/XML自動処理を提供。Go開発者にとって直感的で効率的なHTTP通信を実現し、REST API消費からWebサービス開発まで幅広いシナリオで活用されています。

詳細

Resty 2025年版(v3系)は、Go HTTPクライアントの成熟したソリューションとして継続的な進化を遂げています。Client、Request、Responseの3つの主要コンポーネントを中心とした設計により、HTTPリクエストのライフサイクル全体を包括的に管理。スレッドセーフな実装(sync.RWMutex使用)により複数ゴルーチンからの安全な利用を保証し、豊富なミドルウェアシステム、自動リトライ機能、OAuth/Basic/JWT認証、サーバーサイドイベント(SSE)対応、トレース機能、カスタムDNSリゾルバー等、エンタープライズグレードのHTTP通信要件を満たします。net/httpとの比較において、Restyは高レベルAPIによる開発効率向上と豊富な組み込み機能を提供します。

主な特徴

  • チェイン可能なAPI: 直感的で流暢なインターフェースによる簡潔なコード記述
  • 強力なミドルウェアシステム: リクエスト/レスポンス処理のカスタマイズ
  • 自動リトライ機能: 設定可能なリトライ条件とバックオフ戦略
  • 包括的認証サポート: Basic、Bearer、Digest、OAuth認証の組み込み対応
  • 自動JSON/XML処理: 構造体の自動シリアライゼーション/デシリアライゼーション
  • スレッドセーフ設計: 並行処理環境での安全な利用

メリット・デメリット

メリット

  • net/httpと比較して大幅に簡潔で読みやすいコード記述
  • 豊富な組み込み機能による高い開発効率と生産性向上
  • 強力なミドルウェアシステムによる高度なカスタマイズ性
  • 自動リトライとエラーハンドリングによる堅牢性
  • 包括的な認証オプションによるエンタープライズレベル対応
  • スレッドセーフ設計による並行処理での安全性

デメリット

  • net/httpと比較してやや高い学習コストと抽象化レベル
  • 外部依存関係の追加によるバイナリサイズの若干増加
  • 非常に特殊なHTTP要件では低レベル制御が制限される場合
  • 高度な機能を使わない場合はnet/httpで十分な場合もある
  • バージョンアップ時のAPI変更による移行コスト
  • デバッグ時に内部実装の理解が必要になる場合

参考ページ

書き方の例

インストールと基本セットアップ

// go.mod に追加
require resty.dev/v3

// またはGo 1.17+でのインストール
go get resty.dev/v3
package main

import (
    "fmt"
    "resty.dev/v3"
)

// 基本的なクライアント初期化
func main() {
    // クライアント作成(リソース管理のため必ずdeferでClose)
    client := resty.New()
    defer client.Close()
    
    // 基本設定
    client.SetBaseURL("https://api.example.com").
        SetTimeout(30 * time.Second).
        SetRetryCount(3).
        SetRetryWaitTime(1 * time.Second).
        SetHeader("User-Agent", "MyApp/1.0").
        SetHeader("Accept", "application/json")
}

// 高度なクライアント設定
func createAdvancedClient() *resty.Client {
    client := resty.New()
    
    // デバッグモード有効化
    client.SetDebug(true)
    
    // プロキシ設定
    client.SetProxy("http://proxy.example.com:8080")
    
    // SSL/TLS設定
    client.SetRootCertificate("/path/to/root/cert.pem").
        SetClientCertificates("/path/to/client.crt", "/path/to/client.key")
    
    // リダイレクト設定
    client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(5))
    
    return client
}

// データ構造定義例
type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
    Name     string `json:"name"`
}

type LoginRequest struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

type LoginResponse struct {
    Token     string `json:"token"`
    User      User   `json:"user"`
    ExpiresIn int    `json:"expires_in"`
}

type ErrorResponse struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Details string `json:"details"`
}

基本的なリクエスト(GET/POST/PUT/DELETE)

package main

import (
    "fmt"
    "strconv"
    "time"
    "resty.dev/v3"
)

func basicRequestsExample() {
    client := resty.New()
    defer client.Close()
    
    // 基本的なGETリクエスト
    resp, err := client.R().
        Get("https://httpbin.org/get")
    
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    fmt.Printf("Status Code: %d\n", resp.StatusCode())
    fmt.Printf("Status: %s\n", resp.Status())
    fmt.Printf("Time: %v\n", resp.Time())
    fmt.Printf("Body: %s\n", resp.String())
    
    // クエリパラメータ付きGETリクエスト
    resp, err = client.R().
        SetQueryParams(map[string]string{
            "page":   "1",
            "limit":  "10",
            "sort":   "name",
            "order":  "asc",
            "filter": "active",
        }).
        SetHeader("Accept", "application/json").
        SetAuthToken("your-bearer-token").
        Get("https://api.example.com/users")
    
    fmt.Printf("GET with params: %s\n", resp.String())
    
    // POSTリクエスト(JSON)
    loginReq := LoginRequest{
        Username: "testuser",
        Password: "testpass",
    }
    
    var loginResp LoginResponse
    var errResp ErrorResponse
    
    resp, err = client.R().
        SetBody(loginReq).               // 自動的にJSONエンコード
        SetResult(&loginResp).           // 成功時のレスポンス先
        SetError(&errResp).              // エラー時のレスポンス先
        Post("https://api.example.com/login")
    
    if err != nil {
        fmt.Printf("Request Error: %v\n", err)
        return
    }
    
    if resp.IsSuccess() {
        fmt.Printf("Login Success: Token=%s, User=%s\n", 
            loginResp.Token, loginResp.User.Name)
    } else {
        fmt.Printf("Login Failed: %s - %s\n", 
            errResp.Message, errResp.Details)
    }
    
    // PUTリクエスト(ユーザー更新)
    userUpdate := User{
        ID:       123,
        Username: "updateduser",
        Email:    "[email protected]",
        Name:     "Updated Name",
    }
    
    resp, err = client.R().
        SetBody(userUpdate).
        SetAuthToken(loginResp.Token).
        SetError(&errResp).
        Put("https://api.example.com/users/123")
    
    if resp.IsSuccess() {
        fmt.Println("User updated successfully")
    } else {
        fmt.Printf("Update failed: %s\n", errResp.Message)
    }
    
    // DELETEリクエスト
    resp, err = client.R().
        SetAuthToken(loginResp.Token).
        SetError(&errResp).
        Delete("https://api.example.com/users/123")
    
    if resp.IsSuccess() {
        fmt.Println("User deleted successfully")
    } else {
        fmt.Printf("Delete failed: %s\n", errResp.Message)
    }
    
    // PATCHリクエスト(部分更新)
    partialUpdate := map[string]interface{}{
        "email": "[email protected]",
        "name":  "New Name",
    }
    
    resp, err = client.R().
        SetBody(partialUpdate).
        SetAuthToken(loginResp.Token).
        SetError(&errResp).
        Patch("https://api.example.com/users/123")
    
    if resp.IsSuccess() {
        fmt.Println("User partially updated")
    }
}

// 様々なボディタイプの送信例
func requestBodyTypesExample() {
    client := resty.New()
    defer client.Close()
    
    // 構造体をボディとして送信
    user := User{Username: "test", Email: "[email protected]"}
    client.R().SetBody(user).Post("https://api.example.com/users")
    
    // Mapをボディとして送信
    data := map[string]interface{}{
        "name":  "Test",
        "value": 123,
    }
    client.R().SetBody(data).Post("https://api.example.com/data")
    
    // 文字列をボディとして送信
    jsonStr := `{"username":"test", "password":"pass"}`
    client.R().
        SetContentType("application/json").
        SetBody(jsonStr).
        Post("https://api.example.com/login")
    
    // バイト配列をボディとして送信
    jsonBytes := []byte(`{"key":"value"}`)
    client.R().
        SetContentType("application/json").
        SetBody(jsonBytes).
        Post("https://api.example.com/data")
    
    // io.Readerをボディとして送信(v3ではストリーム化)
    reader := strings.NewReader(`{"stream":"data"}`)
    client.R().
        SetContentType("application/json").
        SetBody(reader).
        Post("https://api.example.com/stream")
}

認証とセキュリティ

package main

import (
    "context"
    "golang.org/x/oauth2/clientcredentials"
    "resty.dev/v3"
)

// Basic認証
func basicAuthExample() {
    client := resty.New()
    defer client.Close()
    
    // クライアント全体でBasic認証を設定
    client.SetBasicAuth("username", "password")
    
    // 特定リクエストのみBasic認証
    resp, err := client.R().
        SetBasicAuth("username", "password").
        Get("https://api.example.com/protected")
    
    fmt.Println(err, resp)
}

// Bearer Token認証
func bearerTokenExample() {
    client := resty.New()
    defer client.Close()
    
    // クライアント全体でBearer Token設定
    client.SetAuthToken("your-jwt-token-here")
    
    // 特定リクエストのみBearer Token
    resp, err := client.R().
        SetAuthToken("specific-token").
        Get("https://api.example.com/users")
    
    // カスタム認証スキーム
    client.SetAuthScheme("Custom")
    // 結果: Authorization: Custom your-token
    
    // カスタムヘッダー名
    client.SetHeaderAuthorizationKey("X-API-Key")
    // 結果: X-API-Key: Bearer your-token
    
    fmt.Println(err, resp)
}

// Digest認証
func digestAuthExample() {
    client := resty.New()
    defer client.Close()
    
    // Digest認証設定(MD5, SHA-256, SHA-512対応)
    client.SetDigestAuth("username", "password")
    
    resp, err := client.R().
        Get("https://api.example.com/digest-protected")
    
    fmt.Println(err, resp)
}

// OAuth2 Client Credentials
func oauth2Example() {
    // OAuth2 Client Credentials設定
    clientCredConfig := &clientcredentials.Config{
        ClientID:     "your-client-id",
        ClientSecret: "your-client-secret",
        TokenURL:     "https://auth.example.com/oauth2/token",
        Scopes:       []string{"read", "write"},
    }
    
    // 方法1: OAuth2クライアントを直接使用
    credClient := clientCredConfig.Client(context.Background())
    client := resty.NewWithClient(credClient)
    defer client.Close()
    
    // 方法2: カスタムミドルウェアでトークン管理
    client2 := resty.New()
    defer client2.Close()
    
    client2.AddRequestMiddleware(func(c *resty.Client, req *resty.Request) error {
        token, err := clientCredConfig.Token(req.Context())
        if err != nil {
            return err
        }
        
        req.SetAuthScheme(token.Type()).
            SetAuthToken(token.AccessToken)
        
        return nil
    })
    
    // 使用例
    resp, err := client2.R().Get("https://api.example.com/protected")
    fmt.Println(err, resp)
}

// カスタム認証ミドルウェア
func customAuthExample() {
    client := resty.New()
    defer client.Close()
    
    client.AddRequestMiddleware(func(c *resty.Client, req *resty.Request) error {
        // カスタム認証ロジック
        apiKey := "your-api-key"
        timestamp := time.Now().Unix()
        signature := generateSignature(apiKey, timestamp) // 独自実装
        
        req.SetHeader("X-API-Key", apiKey).
            SetHeader("X-Timestamp", strconv.FormatInt(timestamp, 10)).
            SetHeader("X-Signature", signature)
        
        return nil
    })
    
    resp, err := client.R().Get("https://api.example.com/secure")
    fmt.Println(err, resp)
}

func generateSignature(apiKey string, timestamp int64) string {
    // 署名生成ロジック(例:HMAC-SHA256など)
    return "generated-signature"
}

// SSL/TLS設定
func sslTlsExample() {
    client := resty.New()
    defer client.Close()
    
    // ルート証明書設定
    client.SetRootCertificate("/path/to/root/cert.pem")
    
    // クライアント証明書設定
    client.SetCertificates("/path/to/client.crt", "/path/to/client.key")
    
    // 文字列から証明書設定
    certStr := `-----BEGIN CERTIFICATE-----
    ... cert content ...
    -----END CERTIFICATE-----`
    client.SetClientRootCertificateFromString(certStr)
    
    // 証明書ウォッチャー(証明書の自動更新)
    certWatcherOpts := &resty.CertWatcherOptions{
        PoolInterval: 12 * time.Hour,
    }
    client.SetClientRootCertificatesWatcher(
        certWatcherOpts,
        "/path/to/cert1.pem",
        "/path/to/cert2.pem",
    )
    
    // プロキシ設定
    client.SetProxy("http://proxy.example.com:8080")
    
    // SOCKS5プロキシ
    client.SetProxy("socks5://127.0.0.1:1080")
    
    resp, err := client.R().Get("https://secure-api.example.com/data")
    fmt.Println(err, resp)
}

ミドルウェアとカスタマイズ

package main

import (
    "log"
    "time"
    "resty.dev/v3"
)

// リクエストミドルウェア
func requestMiddlewareExample() {
    client := resty.New()
    defer client.Close()
    
    // ログミドルウェア
    client.AddRequestMiddleware(func(c *resty.Client, req *resty.Request) error {
        log.Printf("Request: %s %s", req.Method, req.URL)
        return nil
    })
    
    // レート制限ミドルウェア
    lastRequest := time.Now()
    minInterval := 100 * time.Millisecond
    
    client.AddRequestMiddleware(func(c *resty.Client, req *resty.Request) error {
        elapsed := time.Since(lastRequest)
        if elapsed < minInterval {
            time.Sleep(minInterval - elapsed)
        }
        lastRequest = time.Now()
        return nil
    })
    
    // リクエストID追加ミドルウェア
    client.AddRequestMiddleware(func(c *resty.Client, req *resty.Request) error {
        requestID := generateRequestID() // 独自実装
        req.SetHeader("X-Request-ID", requestID)
        return nil
    })
    
    // 複数ミドルウェアの順序指定
    client.SetRequestMiddlewares(
        customAuth1Middleware,
        customAuth2Middleware,
        resty.PrepareRequestMiddleware, // この後でRawRequestが利用可能
        customLoggingMiddleware,
        customMetricsMiddleware,
    )
}

// レスポンスミドルウェア
func responseMiddlewareExample() {
    client := resty.New()
    defer client.Close()
    
    // レスポンスログミドルウェア
    client.AddResponseMiddleware(func(c *resty.Client, res *resty.Response) error {
        log.Printf("Response: %d %s (%v)", 
            res.StatusCode(), res.Status(), res.Time())
        return nil
    })
    
    // メトリクス収集ミドルウェア
    client.AddResponseMiddleware(func(c *resty.Client, res *resty.Response) error {
        // メトリクス送信
        sendMetrics(res.Request.Method, res.StatusCode(), res.Time())
        return nil
    })
    
    // エラー処理ミドルウェア
    client.AddResponseMiddleware(func(c *resty.Client, res *resty.Response) error {
        if res.StatusCode() >= 400 {
            log.Printf("HTTP Error: %d - %s", res.StatusCode(), res.String())
            // 必要に応じてエラーを下流に伝播
            // return errors.New("HTTP error occurred")
        }
        return nil
    })
    
    // 複数レスポンスミドルウェアの順序指定
    client.SetResponseMiddlewares(
        customMetricsMiddleware,
        customLoggingMiddleware,
        resty.AutoParseResponseMiddleware, // この前ではボディは読み込まれない
        customPostProcessMiddleware,
        resty.SaveToFileResponseMiddleware, // Request.SetOutputFileName使用時
        customCleanupMiddleware,
    )
}

// カスタムコンテンツエンコーダー/デコーダー
func customEncodersExample() {
    client := resty.New()
    defer client.Close()
    
    // カスタムエンコーダー追加
    client.AddContentTypeEncoder("application/x-custom", func(w io.Writer, v any) error {
        // カスタムエンコーディングロジック
        data := fmt.Sprintf("CUSTOM:%v", v)
        _, err := w.Write([]byte(data))
        return err
    })
    
    // カスタムデコーダー追加
    client.AddContentTypeDecoder("application/x-custom", func(r io.Reader, v any) error {
        // カスタムデコーディングロジック
        data, err := io.ReadAll(r)
        if err != nil {
            return err
        }
        
        // vに結果を設定(型アサーションが必要)
        if ptr, ok := v.(*string); ok {
            *ptr = string(data)
        }
        return nil
    })
    
    // カスタム圧縮解除器
    client.AddContentDecompresser("custom-compress", func(r io.ReadCloser) (io.ReadCloser, error) {
        // カスタム圧縮解除ロジック
        return r, nil // 例:何もしない
    })
}

// ヘルパー関数
func generateRequestID() string {
    return fmt.Sprintf("req-%d", time.Now().UnixNano())
}

func sendMetrics(method string, statusCode int, duration time.Duration) {
    // メトリクス送信ロジック
    log.Printf("Metrics: %s %d %v", method, statusCode, duration)
}

func customAuth1Middleware(c *resty.Client, req *resty.Request) error {
    // カスタム認証1
    return nil
}

func customAuth2Middleware(c *resty.Client, req *resty.Request) error {
    // カスタム認証2
    return nil
}

func customLoggingMiddleware(c *resty.Client, res *resty.Response) error {
    log.Printf("Custom log: %s", res.Status())
    return nil
}

func customMetricsMiddleware(c *resty.Client, res *resty.Response) error {
    // メトリクス処理
    return nil
}

func customPostProcessMiddleware(c *resty.Client, res *resty.Response) error {
    // レスポンス後処理
    return nil
}

func customCleanupMiddleware(c *resty.Client, res *resty.Response) error {
    // クリーンアップ処理
    return nil
}

エラーハンドリングとリトライ機能

package main

import (
    "errors"
    "time"
    "resty.dev/v3"
)

// 基本的なエラーハンドリング
func basicErrorHandlingExample() {
    client := resty.New()
    defer client.Close()
    
    var result map[string]interface{}
    var errorResp ErrorResponse
    
    resp, err := client.R().
        SetResult(&result).
        SetError(&errorResp).
        Get("https://api.example.com/data")
    
    if err != nil {
        fmt.Printf("Request Error: %v\n", err)
        return
    }
    
    if resp.IsSuccess() {
        fmt.Printf("Success: %+v\n", result)
    } else if resp.IsError() {
        fmt.Printf("API Error: %d - %s\n", 
            resp.StatusCode(), errorResp.Message)
    } else {
        fmt.Printf("Unexpected Status: %d\n", resp.StatusCode())
    }
}

// 自動リトライ設定
func retryConfigurationExample() {
    client := resty.New()
    defer client.Close()
    
    // クライアントレベルのリトライ設定
    client.SetRetryCount(3).
        SetRetryWaitTime(1 * time.Second).
        SetRetryMaxWaitTime(10 * time.Second)
    
    // カスタムリトライ条件追加
    client.AddRetryConditions(
        func(res *resty.Response, err error) bool {
            // ネットワークエラーの場合はリトライ
            if err != nil {
                return true
            }
            
            // 5xxエラーの場合はリトライ
            if res.StatusCode() >= 500 {
                return true
            }
            
            // レート制限の場合はリトライ
            if res.StatusCode() == 429 {
                return true
            }
            
            return false
        },
        func(res *resty.Response, err error) bool {
            // タイムアウトの場合はリトライ
            if err != nil && strings.Contains(err.Error(), "timeout") {
                return true
            }
            return false
        },
    )
    
    // リトライフック(各リトライ間で実行)
    client.AddRetryHooks(
        func(res *resty.Response, err error) {
            fmt.Printf("Retry attempt for: %s\n", res.Request.URL)
        },
        func(res *resty.Response, err error) {
            // メトリクス送信など
            sendRetryMetrics(res, err)
        },
    )
}

// リクエストレベルのリトライ設定
func requestLevelRetryExample() {
    client := resty.New()
    defer client.Close()
    
    resp, err := client.R().
        AddRetryConditions(
            func(res *resty.Response, err error) bool {
                // このリクエスト固有のリトライ条件
                return res != nil && res.StatusCode() == 503
            },
        ).
        AddRetryHooks(
            func(res *resty.Response, err error) {
                // このリクエスト固有のリトライフック
                fmt.Println("Request-specific retry hook")
            },
        ).
        SetRetryCount(5). // このリクエストのみ5回リトライ
        Get("https://api.example.com/unstable")
    
    fmt.Println(err, resp)
}

// 包括的なエラーハンドリング関数
func comprehensiveErrorHandling() {
    client := resty.New()
    defer client.Close()
    
    result, err := safeAPICall(client, "https://api.example.com/data")
    if err != nil {
        fmt.Printf("API Call Failed: %v\n", err)
        return
    }
    
    fmt.Printf("API Call Success: %+v\n", result)
}

func safeAPICall(client *resty.Client, url string) (map[string]interface{}, error) {
    var result map[string]interface{}
    var errorResp ErrorResponse
    
    resp, err := client.R().
        SetResult(&result).
        SetError(&errorResp).
        SetRetryCount(3).
        AddRetryConditions(
            func(res *resty.Response, err error) bool {
                if err != nil {
                    return true // ネットワークエラーはリトライ
                }
                return res.StatusCode() >= 500 || res.StatusCode() == 429
            },
        ).
        Get(url)
    
    if err != nil {
        return nil, fmt.Errorf("request failed: %w", err)
    }
    
    switch {
    case resp.IsSuccess():
        return result, nil
    case resp.StatusCode() == 401:
        return nil, errors.New("authentication failed")
    case resp.StatusCode() == 403:
        return nil, errors.New("access denied")
    case resp.StatusCode() == 404:
        return nil, errors.New("resource not found")
    case resp.StatusCode() == 429:
        return nil, errors.New("rate limit exceeded")
    case resp.IsError():
        return nil, fmt.Errorf("API error: %d - %s", resp.StatusCode(), errorResp.Message)
    default:
        return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode())
    }
}

// 回路ブレーカーパターン実装
type CircuitBreaker struct {
    failures    int
    lastFailure time.Time
    threshold   int
    timeout     time.Duration
    isOpen      bool
}

func NewCircuitBreaker(threshold int, timeout time.Duration) *CircuitBreaker {
    return &CircuitBreaker{
        threshold: threshold,
        timeout:   timeout,
    }
}

func (cb *CircuitBreaker) Call(client *resty.Client, url string) (*resty.Response, error) {
    if cb.isOpen {
        if time.Since(cb.lastFailure) > cb.timeout {
            cb.isOpen = false
            cb.failures = 0
        } else {
            return nil, errors.New("circuit breaker is open")
        }
    }
    
    resp, err := client.R().Get(url)
    
    if err != nil || resp.StatusCode() >= 500 {
        cb.failures++
        cb.lastFailure = time.Now()
        
        if cb.failures >= cb.threshold {
            cb.isOpen = true
        }
        
        if err != nil {
            return nil, err
        }
        return resp, fmt.Errorf("server error: %d", resp.StatusCode())
    }
    
    cb.failures = 0
    return resp, nil
}

func sendRetryMetrics(res *resty.Response, err error) {
    // リトライメトリクスの送信
    fmt.Printf("Retry metrics: %v, %v\n", res, err)
}

高度な機能とパフォーマンス最適化

package main

import (
    "context"
    "net"
    "time"
    "resty.dev/v3"
)

// フォームデータとファイルアップロード
func formsAndFilesExample() {
    client := resty.New()
    defer client.Close()
    
    // フォームデータ送信
    resp, err := client.R().
        SetFormData(map[string]string{
            "username":   "myuser",
            "password":   "mypass",
            "first_name": "John",
            "last_name":  "Doe",
            "email":      "[email protected]",
        }).
        Post("https://api.example.com/register")
    
    fmt.Println(err, resp)
    
    // ファイルアップロード
    resp, err = client.R().
        SetFile("document", "/path/to/file.pdf").
        SetFormData(map[string]string{
            "title":       "Important Document",
            "description": "This is a test upload",
        }).
        Post("https://api.example.com/upload")
    
    fmt.Println(err, resp)
    
    // マルチパートファイルアップロード
    resp, err = client.R().
        SetFiles(map[string]string{
            "file1": "/path/to/file1.txt",
            "file2": "/path/to/file2.jpg",
            "file3": "/path/to/file3.pdf",
        }).
        SetFormData(map[string]string{
            "batch_name": "document_batch_1",
            "category":   "legal_documents",
        }).
        Post("https://api.example.com/batch-upload")
    
    fmt.Println(err, resp)
}

// カスタムDNSリゾルバー
func customDNSExample() {
    // カスタムDNSリゾルバー設定
    dialer := &net.Dialer{
        Resolver: &net.Resolver{
            PreferGo: true,
            Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
                d := net.Dialer{
                    Timeout: 20 * time.Second,
                }
                return d.DialContext(ctx, "udp", "8.8.8.8:53") // Google DNS
            },
        },
    }
    
    client := resty.NewWithDialer(dialer)
    defer client.Close()
    
    resp, err := client.R().Get("https://api.example.com/data")
    fmt.Println(err, resp)
}

// サーバーサイドイベント(SSE)
func serverSentEventsExample() {
    // SSEクライアント作成
    es := resty.NewEventSource().
        SetURL("https://api.example.com/events").
        SetHeader("Authorization", "Bearer your-token").
        OnMessage(func(e interface{}) {
            event := e.(*resty.Event)
            fmt.Printf("Event: %s, Data: %s\n", event.Event, event.Data)
        }, nil).
        OnError(func(err error) {
            fmt.Printf("SSE Error: %v\n", err)
        }).
        OnOpen(func() {
            fmt.Println("SSE Connection opened")
        }).
        OnClose(func() {
            fmt.Println("SSE Connection closed")
        })
    
    // SSE接続開始
    err := es.Get()
    if err != nil {
        fmt.Printf("SSE Failed: %v\n", err)
    }
}

// デバッグとトレース
func debugAndTraceExample() {
    client := resty.New()
    defer client.Close()
    
    // デバッグモード有効化
    client.SetDebug(true)
    
    // トレース有効化でリクエスト実行
    resp, err := client.R().
        EnableTrace().
        Get("https://httpbin.org/get")
    
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    // トレース情報取得
    traceInfo := resp.Request.TraceInfo()
    fmt.Printf("DNS Lookup: %v\n", traceInfo.DNSLookup)
    fmt.Printf("Connect Time: %v\n", traceInfo.ConnTime)
    fmt.Printf("TLS Handshake: %v\n", traceInfo.TLSHandshake)
    fmt.Printf("Server Time: %v\n", traceInfo.ServerTime)
    fmt.Printf("Response Time: %v\n", traceInfo.ResponseTime)
    fmt.Printf("Total Time: %v\n", traceInfo.TotalTime)
    fmt.Printf("Is Connection Reused: %v\n", traceInfo.IsConnReused)
    fmt.Printf("Remote Address: %v\n", traceInfo.RemoteAddr)
    
    // cURLコマンド生成
    curlCmd := resp.Request.CurlCmd()
    fmt.Printf("Equivalent cURL command:\n%s\n", curlCmd)
}

// 生のHTTPレスポンス処理
func rawResponseExample() {
    client := resty.New()
    defer client.Close()
    
    // 自動パースを無効化して生レスポンスを取得
    resp, err := client.R().
        SetDoNotParseResponse(true).
        Get("https://httpbin.org/json")
    
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    defer resp.Body.Close() // 必ずクローズ
    
    // 生レスポンスボディを読み込み
    bodyBytes, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Read Error: %v\n", err)
        return
    }
    
    fmt.Printf("Raw Response: %s\n", string(bodyBytes))
}

// レスポンス内容の強制的な型指定
func forceContentTypeExample() {
    client := resty.New()
    defer client.Close()
    
    var result map[string]interface{}
    
    // Content-Typeに関係なくJSONとして解析を強制
    resp, err := client.R().
        SetResult(&result).
        SetForceResponseContentType("application/json").
        Get("https://api.example.com/data-with-wrong-content-type")
    
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    if resp.IsSuccess() {
        fmt.Printf("Forced JSON parsing result: %+v\n", result)
    }
}

// 並行リクエスト処理
func concurrentRequestsExample() {
    client := resty.New()
    defer client.Close()
    
    urls := []string{
        "https://httpbin.org/get?id=1",
        "https://httpbin.org/get?id=2",
        "https://httpbin.org/get?id=3",
        "https://httpbin.org/get?id=4",
        "https://httpbin.org/get?id=5",
    }
    
    type Result struct {
        URL        string
        StatusCode int
        Body       string
        Error      error
    }
    
    results := make(chan Result, len(urls))
    
    // 並行リクエスト実行
    for _, url := range urls {
        go func(u string) {
            resp, err := client.R().Get(u)
            results <- Result{
                URL:        u,
                StatusCode: resp.StatusCode(),
                Body:       resp.String(),
                Error:      err,
            }
        }(url)
    }
    
    // 結果収集
    for i := 0; i < len(urls); i++ {
        result := <-results
        if result.Error != nil {
            fmt.Printf("Error for %s: %v\n", result.URL, result.Error)
        } else {
            fmt.Printf("Success for %s: %d\n", result.URL, result.StatusCode)
        }
    }
}