HTTP Clients in Ruby
Ruby gives you several ways to make HTTP requests. You can go with the standard library’s Net::HTTP, pull in the versatile Faraday gem with its middleware stack, or use HTTParty for quick one-liners. Each has a place depending on your needs.
This guide compares the three main approaches and shows you when to use which.
Net::HTTP — The Standard Library Workhorse
Net::HTTP ships with Ruby. No gems needed, no dependencies to manage. It handles everything from simple GET requests to persistent connections with custom headers and timeouts.
Basic GET Request
require 'net/http'
require 'uri'
uri = URI('https://api.github.com/repos/ruby/ruby')
response = Net::HTTP.get_response(uri)
puts response.code # => "200"
puts response['content-type'] # => "application/json; charset=utf-8"
puts response.body
For HTTPS, enable SSL:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
response = http.get(uri)
Setting Headers
Pass a hash to add headers:
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer your-token'
request['Accept'] = 'application/json'
response = http.request(request)
Timeouts
http.open_timeout = 5 # seconds to wait for a connection
http.read_timeout = 10 # seconds to wait for a response
response = http.get(uri)
Persistent Connections
Reuse the same connection across multiple requests:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.start
# Connection stays open across these requests
10.times do
response = http.get('/users/1')
puts response.code
end
http.finish
POST with Body
require 'json'
uri = URI('https://httpbin.org/post')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = JSON.generate({ key: 'value' })
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.code # => "200"
Faraday — Composable Middleware
Faraday wraps HTTP clients behind a uniform interface. Its real power is the middleware stack — you can add retry logic, JSON encoding, authentication, and logging as separate components.
Installation
# Gemfile
gem 'faraday'
Basic Usage
require 'faraday'
conn = Faraday.new(url: 'https://api.github.com') do |f|
f.response :json
f.adapter Faraday.default_adapter
end
response = conn.get('/repos/ruby/ruby')
puts response.body['description']
Middleware
Middleware pieces compose to add behavior:
conn = Faraday.new(url: 'https://api.github.com') do |f|
f.response :json
f.request :retry, max: 3, interval: 0.5
f.adapter Faraday.default_adapter
end
Common middleware gems:
faraday-retry— automatic retries with backofffaraday-follow_redirects— follow HTTP redirectsfaraday-multipart— file uploadsfaraday-oauth— OAuth authentication
Adapters
Faraday delegates to an underlying adapter. Swap adapters without changing your code:
# Uses Net::HTTP by default, but you can choose:
Faraday.new adapter: :patron # libcurl bindings
Faraday.new adapter: :httpclient # Java-based HTTP client
Custom Headers
conn = Faraday.new(url: 'https://api.github.com') do |f|
f.headers['Authorization'] = 'token YOUR_TOKEN'
f.headers['Accept'] = 'application/vnd.github.v3+json'
end
response = conn.get('/user')
HTTParty — One-Liners
HTTParty is the quickest way to get going. Make a GET request in a single line:
require 'httparty'
response = HTTParty.get('https://api.github.com/repos/ruby/ruby')
puts response.code
puts response.parsed_response['description']
Class-Based Setup
Register a base URL and default options on a class:
require 'httparty'
class GitHub
include HTTParty
base_uri 'https://api.github.com'
headers 'Accept' => 'application/vnd.github.v3+json'
end
# Now each call uses the base URI
repos = GitHub.get('/users/ruby/repos')
puts repos.first['name']
Authentication
# Basic Auth
response = HTTParty.get(
'https://api.github.com/user',
basic_auth: { username: 'user', password: 'token' }
)
# API Token
response = HTTParty.get(
'https://api.github.com/user',
headers: { 'Authorization' => 'token YOUR_TOKEN' }
)
Query Parameters
response = HTTParty.get(
'https://api.github.com/search/code',
query: { q: 'language:ruby', sort: 'stars' }
)
Error Handling
All three libraries raise exceptions on network failures. Handle them consistently:
require 'net/http'
require 'uri'
def fetch(url)
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.open_timeout = 5
http.read_timeout = 10
http.start
response = http.get(uri)
http.finish
case response
when Net::HTTPSuccess
response.body
when Net::HTTPRedirection
fetch(response['Location']) # follow redirect
else
raise "Unexpected response: #{response.code}"
end
rescue Net::OpenTimeout, Net::ReadTimeout => e
puts "Timeout: #{e.message}"
nil
rescue SocketError, Errno::ECONNREFUSED => e
puts "Connection error: #{e.message}"
nil
end
With Faraday, add the middleware and handle exceptions after the fact:
conn = Faraday.new(url: 'https://api.github.com') do |f|
f.response :raise_error
f.adapter Faraday.default_adapter
end
begin
response = conn.get('/repos/ruby/ruby')
rescue Faraday::Error => e
puts "Request failed: #{e.message}"
end
Retry Logic
Net::HTTP Manual Retry
def fetch_with_retry(url, max_attempts: 3)
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
max_attempts.times do |attempt|
begin
http.open_timeout = 5
http.read_timeout = 10
http.start
return http.get(uri)
rescue Net::OpenTimeout, Net::ReadTimeout => e
puts "Attempt #{attempt + 1} failed: #{e.message}"
sleep 2 ** attempt # exponential backoff
ensure
http.finish if http.started?
end
end
raise "Failed after #{max_attempts} attempts"
end
Faraday Retry Middleware
require 'faraday'
require 'faraday/retry'
conn = Faraday.new(url: 'https://api.github.com') do |f|
f.response :raise_error
f.request :retry,
max: 3,
interval: 0.5,
backoff_factor: 2,
exceptions: [Faraday::Error::TimeoutError, Errno::ECONNREFUSED]
f.adapter Faraday.default_adapter
end
Which Should You Use?
| Library | Best For |
|---|---|
| Net::HTTP | Scripts, one-off requests, minimal dependencies |
| Faraday | Composable HTTP layers, testing, reusable clients |
| HTTParty | Quick API calls, prototyping, class-based clients |
For a small script or DevOps automation, Net::HTTP is fine. When you need to add logging, retries, or authentication, Faraday pays off. Reach for HTTParty when you want to set up a class-based API client in minutes.
See Also
- /reference/modules/net-http/ — Net::HTTP module reference
- /guides/ruby-json-and-xml/ — Parsing JSON and XML in Ruby
- /guides/ruby-net-http-requests/ — Deep dive into Net::HTTP requests