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.

HTTP ClientRubySimpleAPIJSON ParsingXML Parsing

GitHub Overview

jnunemaker/httparty

:tada: Makes http fun again!

Stars5,878
Watchers62
Forks966
Created:July 28, 2008
Language:Ruby
License:MIT License

Topics

httphttpartyruby

Star History

jnunemaker/httparty Star History
Data as of: 10/22/2025, 09:54 AM

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"'