HTTParty
Easy-to-use HTTP client gem for Ruby. Provides intuitive and understandable syntax with concept of 'making HTTP fun'. Built on Net::HTTP with built-in automatic JSON/XML parsing, authentication, and cookie processing. Popular among Ruby beginners and side projects.
GitHub Overview
Topics
Star History
Library
HTTParty
Overview
HTTParty is a Ruby HTTP client library with the concept of "making HTTP fun again." It makes consuming RESTful web services extremely easy, providing an intuitive API for sending HTTP requests and processing responses. Featuring automatic JSON/XML parsing, authentication support, and flexible configuration, it has been widely adopted as one of the most user-friendly HTTP libraries for Ruby developers. It supports a wide range of use cases from simple one-liner code to building full-featured API clients.
Details
HTTParty 2025 edition (v0.23.1) maintains its solid position as a mature HTTP client library with over 15 years of development experience. It supports Ruby 2.7.0 and later, with compatibility ensured for Ruby 3.4. The modular architecture supports both direct use as class methods and inclusion into custom API client classes. With automatic response format detection, comprehensive authentication features, SSL configuration, and extensive request customization options, it can handle everything from personal projects to enterprise-level API integrations.
Key Features
- Simple API: Intuitive and readable HTTP request description
- Automatic Response Parsing: Auto-parsing for JSON, XML, CSV, and YAML
- Comprehensive Authentication Support: Basic auth, Digest auth, and custom headers
- Flexible Configuration: Base URI, default parameters, and timeout settings
- Command Line Tool: Direct terminal usage with httparty command
- Modular Design: Support for both direct use and class inclusion
Pros and Cons
Pros
- High adoption rate in Ruby ecosystem with rich community support
- Extremely understandable API providing high learning efficiency and development productivity
- Automatic JSON/XML parsing eliminates need for manual parsing
- Excellent integration with frameworks like Rails and Sinatra
- Easy API exploration and operation verification through command-line tool
- High stability and reliability backed by over 15 years of development
Cons
- Performance inferior to other libraries for performance-critical applications
- Not suitable for handling large numbers of parallel requests
- Limited asynchronous processing capabilities (simple synchronous processing based)
- Incomplete HTTP/2 support (primarily HTTP/1.1 based)
- Less lightweight due to feature richness
- Limited support for advanced HTTP features (streaming, etc.)
Reference Pages
Code Examples
Installation and Basic Setup
# Install HTTParty
gem install httparty
# Add to Gemfile
echo 'gem "httparty"' >> Gemfile
bundle install
# Check version
ruby -e "require 'httparty'; puts HTTParty::VERSION"
# Display command-line tool help
httparty --help
Basic Requests (GET/POST/PUT/DELETE)
require 'httparty'
# Basic GET request (using class methods)
response = HTTParty.get('https://api.example.com/users')
puts response.code # 200
puts response.message # OK
puts response.headers # Header information
puts response.body # Response body
puts response.parsed_response # Parsed response (JSON→Hash)
# GET request with query parameters
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 request with headers
response = HTTParty.get('https://api.example.com/protected', {
headers: {
'Authorization' => 'Bearer your-token',
'Content-Type' => 'application/json',
'User-Agent' => 'MyApp/1.0'
}
})
# POST request (sending JSON)
user_data = {
name: 'John Doe',
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 "User created successfully: ID=#{created_user['id']}"
else
puts "Error: #{response.code} - #{response.message}"
puts response.body
end
# POST request (sending form data)
response = HTTParty.post('https://api.example.com/login', {
body: {
username: 'testuser',
password: 'secret123'
}
})
# PUT request (data update)
updated_data = {
name: 'Jane Doe',
email: '[email protected]'
}
response = HTTParty.put('https://api.example.com/users/123', {
body: updated_data.to_json,
headers: { 'Content-Type' => 'application/json' }
})
# DELETE request
response = HTTParty.delete('https://api.example.com/users/123', {
headers: { 'Authorization' => 'Bearer your-token' }
})
puts "Deletion successful" if response.success?
# Check detailed response information
puts "Status: #{response.code}"
puts "Message: #{response.message}"
puts "Headers: #{response.headers.inspect}"
puts "Body: #{response.body}"
puts "Parsed Response: #{response.parsed_response}"
Building API Client Classes (Include Pattern)
require 'httparty'
# API client including HTTParty module
class StackExchangeClient
include HTTParty
# Base URI and default settings
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
# Using the API client
client = StackExchangeClient.new('stackoverflow')
questions = client.questions(page: 1, pagesize: 10)
if questions.success?
questions.parsed_response['items'].each do |question|
puts "Title: #{question['title']}"
puts "Created: #{Time.at(question['creation_date'])}"
puts "Tags: #{question['tags'].join(', ')}"
puts "---"
end
else
puts "Error: #{questions.code} - #{questions.message}"
end
# More advanced API client example
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
# Using GitHub API client
github = GitHubAPIClient.new('your-github-token')
user_info = github.user('octocat')
if user_info.success?
user = user_info.parsed_response
puts "User: #{user['name']} (@#{user['login']})"
puts "Public repositories: #{user['public_repos']}"
puts "Followers: #{user['followers']}"
end
Authentication and Security Configuration
require 'httparty'
# Basic authentication configuration
class APIClientWithBasicAuth
include HTTParty
base_uri 'https://api.example.com'
basic_auth 'username', 'password'
end
# Or Basic auth for individual requests
response = HTTParty.get('https://api.example.com/private', {
basic_auth: {
username: 'your_username',
password: 'your_password'
}
})
# Digest authentication configuration
class APIClientWithDigestAuth
include HTTParty
base_uri 'https://api.example.com'
digest_auth 'username', 'password'
end
# Custom authentication headers
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 certificate configuration
class SecureAPIClient
include HTTParty
base_uri 'https://secure-api.example.com'
# Specify SSL certificate file
ssl_ca_file '/path/to/certificate.pem'
ssl_ca_path '/path/to/certificates/'
# Client certificate configuration
pem File.read('/path/to/client.pem'), 'password'
# Disable SSL verification (development only)
# ssl_verify false
end
# Proxy configuration
class ProxyAPIClient
include HTTParty
base_uri 'https://api.example.com'
http_proxy 'proxy.example.com', 8080, 'proxy_user', 'proxy_pass'
end
# Timeout configuration
class TimeoutAPIClient
include HTTParty
base_uri 'https://api.example.com'
default_timeout 30 # Overall timeout
open_timeout 10 # Connection timeout
read_timeout 15 # Read timeout
write_timeout 10 # Write timeout
end
# Header and cookie management
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?
# Extract cookies from response
@cookies = response.headers['set-cookie']
true
else
false
end
end
def authenticated_request(endpoint)
self.class.get(endpoint, {
headers: { 'Cookie' => @cookies }
})
end
end
Error Handling and Debugging
require 'httparty'
# Comprehensive error handling
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: 'Authentication required' }
when 403
return { success: false, error: 'Forbidden', details: 'Access permission denied' }
when 404
return { success: false, error: 'Not Found', details: 'Resource not found' }
when 429
return { success: false, error: 'Too Many Requests', details: 'Rate limit reached' }
when 500..599
return { success: false, error: 'Server Error', details: 'Server error occurred' }
else
return { success: false, error: 'Unknown Error', details: "Status: #{response.code}" }
end
rescue Net::TimeoutError => e
return { success: false, error: 'Timeout', details: 'Request timed out' }
rescue Net::OpenTimeout => e
return { success: false, error: 'Connection Timeout', details: 'Connection timeout occurred' }
rescue SocketError => e
return { success: false, error: 'Network Error', details: 'Network error occurred' }
rescue JSON::ParserError => e
return { success: false, error: 'Parse Error', details: 'Failed to parse response' }
rescue StandardError => e
return { success: false, error: 'Unexpected Error', details: e.message }
end
end
# Usage example
result = safe_api_request('https://api.example.com/data', {
headers: { 'Authorization' => 'Bearer token' },
timeout: 10
})
if result[:success]
puts "Data retrieval successful:"
puts result[:data]
else
puts "Error: #{result[:error]}"
puts "Details: #{result[:details]}"
end
# Request with retry functionality
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
# Retry for server errors or rate limiting
raise StandardError, "HTTP #{response.code}: #{response.message}"
else
# Don't retry client errors
return response
end
rescue StandardError => e
retries += 1
if retries <= max_retries
sleep_time = 2 ** retries # exponential backoff
puts "Request failed (attempt #{retries}/#{max_retries}): #{e.message}"
puts "Retrying in #{sleep_time} seconds..."
sleep(sleep_time)
retry
else
puts "Maximum retry attempts reached: #{e.message}"
raise e
end
end
end
# Debug API client
class DebugAPIClient
include HTTParty
base_uri 'https://api.example.com'
# Enable debug output
debug_output $stdout
def self.verbose_request(method, endpoint, options = {})
puts "=== Request Details ==="
puts "Method: #{method.upcase}"
puts "URL: #{base_uri}#{endpoint}"
puts "Headers: #{headers.merge(options[:headers] || {}).inspect}"
puts "Body: #{options[:body].inspect}" if options[:body]
puts "======================="
response = send(method, endpoint, options)
puts "=== Response Details ==="
puts "Status: #{response.code} #{response.message}"
puts "Headers: #{response.headers.inspect}"
puts "Body: #{response.body}"
puts "========================"
response
end
end
# Usage example
DebugAPIClient.verbose_request(:get, '/users/123', {
headers: { 'Authorization' => 'Bearer token' }
})
# Response time measurement
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 "Request completed: #{response.code} in #{duration}ms"
puts "URL: #{url}"
puts "Response size: #{response.body.length} bytes"
response
end
# Batch request processing
def batch_requests(urls, options = {})
results = []
urls.each_with_index do |url, index|
puts "Processing (#{index + 1}/#{urls.length}): #{url}"
result = safe_api_request(url, options)
results << result.merge(url: url)
# Wait to reduce API load
sleep(0.5) if index < urls.length - 1
end
successful = results.count { |r| r[:success] }
puts "Completed: #{successful}/#{urls.length} successful"
results
end
# Usage example
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]}: Success"
else
puts "✗ #{result[:url]}: #{result[:error]}"
end
end
Command Line Tool Usage
# Basic HTTP request
httparty "https://api.example.com/users"
# Formatted JSON output
httparty --json "https://api.example.com/users"
# Formatted XML output
httparty --xml "https://api.example.com/data.xml"
# POST request (sending data)
httparty --post --body='{"name":"test"}' --headers='Content-Type:application/json' "https://api.example.com/users"
# Authenticated request
httparty --headers='Authorization:Bearer your-token' "https://api.example.com/protected"
# Request with query parameters
httparty "https://api.example.com/search?q=ruby&limit=10"
# Display response headers
httparty --include-headers "https://api.example.com/users"
# Verbose redirect display
httparty --verbose "https://api.example.com/redirect"
# Timeout configuration
httparty --timeout=30 "https://slow-api.example.com/data"
# Output to file
httparty "https://api.example.com/users" > users.json
# Detailed error display
httparty --debug "https://api.example.com/error-endpoint"
# Execute multiple requests (Bash loop)
for i in {1..5}; do
echo "User $i:"
httparty "https://api.example.com/users/$i"
echo "---"
done
# API endpoint exploration
httparty "https://api.example.com" | grep -E '"[a-zA-Z_]+_url"'