HTTParty
Ruby向けの使いやすいHTTPクライアントgem。「HTTPを楽しく」をコンセプトに、直感的で分かりやすい構文を提供。Net::HTTPベースで構築され、自動JSON/XML解析、認証、Cookie処理機能を内蔵。Ruby初心者やサイドプロジェクトで人気。
GitHub概要
スター5,878
ウォッチ62
フォーク966
作成日:2008年7月28日
言語:Ruby
ライセンス:MIT License
トピックス
httphttpartyruby
スター履歴
データ取得日時: 2025/10/22 09:54
ライブラリ
HTTParty
概要
HTTPartyは「HTTPを楽しくする」をコンセプトとしたRuby用のHTTPクライアントライブラリです。RESTful Webサービスの利用を極めて簡単にし、直感的なAPIでHTTPリクエストの送信とレスポンス処理を提供します。自動的なJSON/XML解析、認証サポート、設定の柔軟性を特徴とし、Ruby開発者にとって最も使いやすいHTTPライブラリの一つとして広く採用されています。シンプルな一行のコードから本格的なAPIクライアント構築まで、幅広い用途に対応します。
詳細
HTTParty 2025年版(v0.23.1)は、15年以上の開発実績を持つ成熟したHTTPクライアントライブラリとして確固たる地位を維持しています。Ruby 2.7.0以降をサポートし、Ruby 3.4との互換性も確保されています。モジュール式のアーキテクチャによりクラスメソッドとしての直接使用と、カスタムAPIクライアントクラスへのインクルードの両方に対応。レスポンスの自動フォーマット検出、包括的な認証機能、SSL設定、広範なリクエストカスタマイズオプションにより、個人プロジェクトから企業レベルのAPI統合まで対応可能です。
主な特徴
- シンプルなAPI: 直感的で読みやすいHTTPリクエスト記述
- 自動レスポンス解析: JSON、XML、CSV、YAMLの自動パース機能
- 包括的認証サポート: Basic認証、Digest認証、カスタムヘッダー対応
- 柔軟な設定: ベースURI、デフォルトパラメータ、タイムアウト設定
- コマンドラインツール: httpartyコマンドによるターミナルでの直接利用
- モジュール式設計: 直接使用とクラスインクルードの両方に対応
メリット・デメリット
メリット
- Rubyエコシステムでの高い普及率と豊富なコミュニティサポート
- 極めて分かりやすいAPIによる高い学習効率と開発生産性
- 自動JSON/XML解析により手動パース処理が不要
- Rails、Sinatraなどのフレームワークとの優れた統合性
- コマンドラインツールによるAPI探索と動作確認の容易さ
- 15年以上の開発実績による高い安定性と信頼性
デメリット
- パフォーマンス重視の用途では他のライブラリより速度が劣る
- 大量の並列リクエスト処理には向かない
- 非同期処理機能が限定的(単純な同期処理ベース)
- HTTP/2対応が不完全(基本的にHTTP/1.1ベース)
- 機能の豊富さゆえに軽量性では劣る部分がある
- 高度なHTTP機能(ストリーミング等)のサポートは限定的
参考ページ
書き方の例
インストールと基本セットアップ
# HTTPartyのインストール
gem install httparty
# Gemfileに追加
echo 'gem "httparty"' >> Gemfile
bundle install
# バージョン確認
ruby -e "require 'httparty'; puts HTTParty::VERSION"
# コマンドラインツールのヘルプ表示
httparty --help
基本的なリクエスト(GET/POST/PUT/DELETE)
require 'httparty'
# 基本的なGETリクエスト(クラスメソッド使用)
response = HTTParty.get('https://api.example.com/users')
puts response.code # 200
puts response.message # OK
puts response.headers # ヘッダー情報
puts response.body # レスポンスボディ
puts response.parsed_response # 解析済みレスポンス(JSON→Hash)
# クエリパラメータ付きGETリクエスト
response = HTTParty.get('https://api.example.com/users', {
query: {
page: 1,
limit: 10,
sort: 'created_at'
}
})
puts response.request.uri # https://api.example.com/users?page=1&limit=10&sort=created_at
# ヘッダー付きGETリクエスト
response = HTTParty.get('https://api.example.com/protected', {
headers: {
'Authorization' => 'Bearer your-token',
'Content-Type' => 'application/json',
'User-Agent' => 'MyApp/1.0'
}
})
# POSTリクエスト(JSON送信)
user_data = {
name: '田中太郎',
email: '[email protected]',
age: 30
}
response = HTTParty.post('https://api.example.com/users', {
body: user_data.to_json,
headers: {
'Content-Type' => 'application/json',
'Authorization' => 'Bearer your-token'
}
})
if response.success?
created_user = response.parsed_response
puts "ユーザー作成完了: ID=#{created_user['id']}"
else
puts "エラー: #{response.code} - #{response.message}"
puts response.body
end
# POSTリクエスト(フォームデータ送信)
response = HTTParty.post('https://api.example.com/login', {
body: {
username: 'testuser',
password: 'secret123'
}
})
# PUTリクエスト(データ更新)
updated_data = {
name: '田中次郎',
email: '[email protected]'
}
response = HTTParty.put('https://api.example.com/users/123', {
body: updated_data.to_json,
headers: { 'Content-Type' => 'application/json' }
})
# DELETEリクエスト
response = HTTParty.delete('https://api.example.com/users/123', {
headers: { 'Authorization' => 'Bearer your-token' }
})
puts "削除成功" if response.success?
# レスポンス詳細情報の確認
puts "ステータス: #{response.code}"
puts "メッセージ: #{response.message}"
puts "ヘッダー: #{response.headers.inspect}"
puts "本文: #{response.body}"
puts "解析結果: #{response.parsed_response}"
APIクライアントクラスの構築(インクルードパターン)
require 'httparty'
# HTTPartyモジュールをインクルードしたAPIクライアント
class StackExchangeClient
include HTTParty
# ベースURIとデフォルト設定
base_uri 'api.stackexchange.com'
default_timeout 30
headers 'User-Agent' => 'MyApp/1.0'
def initialize(site = 'stackoverflow')
@options = { query: { site: site } }
end
def questions(page: 1, pagesize: 30)
self.class.get('/2.2/questions', @options.merge(
query: @options[:query].merge(page: page, pagesize: pagesize)
))
end
def users(page: 1, pagesize: 30)
self.class.get('/2.2/users', @options.merge(
query: @options[:query].merge(page: page, pagesize: pagesize)
))
end
def question_by_id(question_id)
self.class.get("/2.2/questions/#{question_id}", @options)
end
end
# APIクライアントの使用
client = StackExchangeClient.new('stackoverflow')
questions = client.questions(page: 1, pagesize: 10)
if questions.success?
questions.parsed_response['items'].each do |question|
puts "タイトル: #{question['title']}"
puts "作成日: #{Time.at(question['creation_date'])}"
puts "タグ: #{question['tags'].join(', ')}"
puts "---"
end
else
puts "エラー: #{questions.code} - #{questions.message}"
end
# より高度なAPIクライアント例
class GitHubAPIClient
include HTTParty
base_uri 'https://api.github.com'
headers 'Accept' => 'application/vnd.github.v3+json'
default_timeout 30
def initialize(token = nil)
if token
self.class.headers 'Authorization' => "token #{token}"
end
end
def user(username)
self.class.get("/users/#{username}")
end
def repositories(username, type: 'all')
self.class.get("/users/#{username}/repos", {
query: { type: type, sort: 'updated', direction: 'desc' }
})
end
def repository(owner, repo)
self.class.get("/repos/#{owner}/#{repo}")
end
def create_issue(owner, repo, title, body = nil, labels = [])
self.class.post("/repos/#{owner}/#{repo}/issues", {
body: {
title: title,
body: body,
labels: labels
}.to_json,
headers: { 'Content-Type' => 'application/json' }
})
end
end
# GitHub APIクライアントの使用
github = GitHubAPIClient.new('your-github-token')
user_info = github.user('octocat')
if user_info.success?
user = user_info.parsed_response
puts "ユーザー: #{user['name']} (@#{user['login']})"
puts "公開リポジトリ: #{user['public_repos']}個"
puts "フォロワー: #{user['followers']}人"
end
認証とセキュリティ設定
require 'httparty'
# Basic認証の設定
class APIClientWithBasicAuth
include HTTParty
base_uri 'https://api.example.com'
basic_auth 'username', 'password'
end
# または個別リクエストでBasic認証
response = HTTParty.get('https://api.example.com/private', {
basic_auth: {
username: 'your_username',
password: 'your_password'
}
})
# Digest認証の設定
class APIClientWithDigestAuth
include HTTParty
base_uri 'https://api.example.com'
digest_auth 'username', 'password'
end
# カスタム認証ヘッダー
class APIClientWithTokenAuth
include HTTParty
base_uri 'https://api.example.com'
def initialize(api_key)
self.class.headers 'X-API-Key' => api_key
end
end
# SSL証明書設定
class SecureAPIClient
include HTTParty
base_uri 'https://secure-api.example.com'
# SSL証明書ファイルの指定
ssl_ca_file '/path/to/certificate.pem'
ssl_ca_path '/path/to/certificates/'
# クライアント証明書の設定
pem File.read('/path/to/client.pem'), 'password'
# SSL検証を無効化(開発環境のみ)
# ssl_verify false
end
# プロキシ設定
class ProxyAPIClient
include HTTParty
base_uri 'https://api.example.com'
http_proxy 'proxy.example.com', 8080, 'proxy_user', 'proxy_pass'
end
# タイムアウト設定
class TimeoutAPIClient
include HTTParty
base_uri 'https://api.example.com'
default_timeout 30 # 全体のタイムアウト
open_timeout 10 # 接続タイムアウト
read_timeout 15 # 読み込みタイムアウト
write_timeout 10 # 書き込みタイムアウト
end
# ヘッダーとCookie管理
class StatefulAPIClient
include HTTParty
base_uri 'https://api.example.com'
def initialize
@cookies = {}
end
def login(username, password)
response = self.class.post('/login', {
body: { username: username, password: password }.to_json,
headers: { 'Content-Type' => 'application/json' }
})
if response.success?
# レスポンスからCookieを取得
@cookies = response.headers['set-cookie']
true
else
false
end
end
def authenticated_request(endpoint)
self.class.get(endpoint, {
headers: { 'Cookie' => @cookies }
})
end
end
エラーハンドリングとデバッグ
require 'httparty'
# 包括的なエラーハンドリング
def safe_api_request(url, options = {})
begin
response = HTTParty.get(url, options)
case response.code
when 200..299
return { success: true, data: response.parsed_response }
when 400
return { success: false, error: 'Bad Request', details: response.body }
when 401
return { success: false, error: 'Unauthorized', details: '認証が必要です' }
when 403
return { success: false, error: 'Forbidden', details: 'アクセス権限がありません' }
when 404
return { success: false, error: 'Not Found', details: 'リソースが見つかりません' }
when 429
return { success: false, error: 'Too Many Requests', details: 'リクエスト制限に達しました' }
when 500..599
return { success: false, error: 'Server Error', details: 'サーバーエラーが発生しました' }
else
return { success: false, error: 'Unknown Error', details: "ステータス: #{response.code}" }
end
rescue Net::TimeoutError => e
return { success: false, error: 'Timeout', details: 'リクエストがタイムアウトしました' }
rescue Net::OpenTimeout => e
return { success: false, error: 'Connection Timeout', details: '接続タイムアウトが発生しました' }
rescue SocketError => e
return { success: false, error: 'Network Error', details: 'ネットワークエラーが発生しました' }
rescue JSON::ParserError => e
return { success: false, error: 'Parse Error', details: 'レスポンスの解析に失敗しました' }
rescue StandardError => e
return { success: false, error: 'Unexpected Error', details: e.message }
end
end
# 使用例
result = safe_api_request('https://api.example.com/data', {
headers: { 'Authorization' => 'Bearer token' },
timeout: 10
})
if result[:success]
puts "データ取得成功:"
puts result[:data]
else
puts "エラー: #{result[:error]}"
puts "詳細: #{result[:details]}"
end
# リトライ機能付きリクエスト
def request_with_retry(url, options = {}, max_retries = 3)
retries = 0
begin
response = HTTParty.get(url, options)
if response.success?
return response
elsif response.code >= 500 || response.code == 429
# サーバーエラーまたはレート制限の場合リトライ
raise StandardError, "HTTP #{response.code}: #{response.message}"
else
# クライアントエラーはリトライしない
return response
end
rescue StandardError => e
retries += 1
if retries <= max_retries
sleep_time = 2 ** retries # exponential backoff
puts "リクエスト失敗 (試行#{retries}/#{max_retries}): #{e.message}"
puts "#{sleep_time}秒後に再試行..."
sleep(sleep_time)
retry
else
puts "最大再試行回数に達しました: #{e.message}"
raise e
end
end
end
# デバッグ用APIクライアント
class DebugAPIClient
include HTTParty
base_uri 'https://api.example.com'
# デバッグ出力の有効化
debug_output $stdout
def self.verbose_request(method, endpoint, options = {})
puts "=== リクエスト詳細 ==="
puts "メソッド: #{method.upcase}"
puts "URL: #{base_uri}#{endpoint}"
puts "ヘッダー: #{headers.merge(options[:headers] || {}).inspect}"
puts "ボディ: #{options[:body].inspect}" if options[:body]
puts "========================"
response = send(method, endpoint, options)
puts "=== レスポンス詳細 ==="
puts "ステータス: #{response.code} #{response.message}"
puts "ヘッダー: #{response.headers.inspect}"
puts "ボディ: #{response.body}"
puts "========================"
response
end
end
# 使用例
DebugAPIClient.verbose_request(:get, '/users/123', {
headers: { 'Authorization' => 'Bearer token' }
})
# レスポンス時間測定
def timed_request(url, options = {})
start_time = Time.now
response = HTTParty.get(url, options)
end_time = Time.now
duration = ((end_time - start_time) * 1000).round(2)
puts "リクエスト完了: #{response.code} in #{duration}ms"
puts "URL: #{url}"
puts "レスポンスサイズ: #{response.body.length} bytes"
response
end
# バッチリクエスト処理
def batch_requests(urls, options = {})
results = []
urls.each_with_index do |url, index|
puts "処理中 (#{index + 1}/#{urls.length}): #{url}"
result = safe_api_request(url, options)
results << result.merge(url: url)
# API負荷軽減のための待機
sleep(0.5) if index < urls.length - 1
end
successful = results.count { |r| r[:success] }
puts "完了: #{successful}/#{urls.length} 成功"
results
end
# 使用例
urls = [
'https://api.example.com/users/1',
'https://api.example.com/users/2',
'https://api.example.com/users/3'
]
results = batch_requests(urls, {
headers: { 'Authorization' => 'Bearer token' },
timeout: 10
})
results.each do |result|
if result[:success]
puts "✓ #{result[:url]}: 成功"
else
puts "✗ #{result[:url]}: #{result[:error]}"
end
end
コマンドラインツールの活用
# 基本的なHTTPリクエスト
httparty "https://api.example.com/users"
# 整形されたJSON出力
httparty --json "https://api.example.com/users"
# 整形されたXML出力
httparty --xml "https://api.example.com/data.xml"
# POSTリクエスト(データ送信)
httparty --post --body='{"name":"test"}' --headers='Content-Type:application/json' "https://api.example.com/users"
# 認証付きリクエスト
httparty --headers='Authorization:Bearer your-token' "https://api.example.com/protected"
# クエリパラメータ付きリクエスト
httparty "https://api.example.com/search?q=ruby&limit=10"
# レスポンスヘッダーの表示
httparty --include-headers "https://api.example.com/users"
# リダイレクト詳細表示
httparty --verbose "https://api.example.com/redirect"
# タイムアウト設定
httparty --timeout=30 "https://slow-api.example.com/data"
# ファイルへの出力
httparty "https://api.example.com/users" > users.json
# エラー時の詳細表示
httparty --debug "https://api.example.com/error-endpoint"
# 複数リクエストの実行(Bashループ)
for i in {1..5}; do
echo "ユーザー $i:"
httparty "https://api.example.com/users/$i"
echo "---"
done
# APIエンドポイント探索
httparty "https://api.example.com" | grep -E '"[a-zA-Z_]+_url"'