Consuming APIs with Ruby
Ruby provides excellent tools for API consumption through its built-in libraries and gems. The net/http
standard library handles basic HTTP operations, while gems like httparty
and faraday
offer more convenient interfaces for complex API interactions.
This tutorial covers consuming REST APIs with Ruby, including authentication, error handling, and real-world examples.
Prerequisites
Ruby 2.7 or later includes the modern HTTP client improvements covered in this guide.
Basic familiarity with Ruby classes, modules, and exception handling will help you apply the API consumption patterns demonstrated here.
Ruby's API consumption approach
Ruby treats HTTP requests as objects with rich APIs for configuration and response handling. The standard library provides low-level control, while popular gems offer high-level convenience methods and automatic JSON parsing.
Core Ruby HTTP tools:
- Net::HTTP: Built-in HTTP client library
- URI: URL parsing and manipulation
- JSON: Response parsing and generation
- HTTParty: Popular gem for simplified API consumption
Create a working directory:
mkdir ruby-api-demo && cd ruby-api-demo
Making your first API call
Ruby's Net::HTTP
provides the foundation for API consumption. The library offers both simple one-line methods and detailed request configuration for complex scenarios.
For your first example, you'll call the Random User Generator API to fetch sample user data:
require 'net/http'
require 'json'
def fetch_random_user
uri = URI('https://randomuser.me/api/')
response = Net::HTTP.get_response(uri)
puts "Status: #{response.code} #{response.message}"
if response.code == '200'
data = JSON.parse(response.body)
user = data['results'].first
name = user['name']
puts "Generated user: #{name['first']} #{name['last']}"
puts "Email: #{user['email']}"
puts "Location: #{user['location']['city']}, #{user['location']['country']}"
else
puts "Request failed with status #{response.code}"
end
end
fetch_random_user
The Net::HTTP.get_response
method returns a response object containing both status information and body content. Ruby's JSON.parse
converts the response string into native Ruby objects for easy manipulation.
Run the basic API example:
ruby basic_api_call.rb
Status: 200 OK
Generated user: Emma Johnson
Email: emma.johnson@example.com
Location: Manchester, United Kingdom
This demonstrates Ruby's straightforward approach to HTTP requests where response data becomes immediately accessible through standard Ruby hash operations.
While the basic example works perfectly for simple scenarios, production applications often need deeper insights into request and response details for debugging and monitoring purposes.
Understanding requests and responses
Ruby's HTTP objects provide comprehensive access to request and response data. Understanding these objects helps you debug API calls and handle different response scenarios effectively.
Let's enhance our existing basic_api_call.rb
to add detailed request and response inspection:
require 'net/http'
require 'json'
def fetch_random_user
uri = URI('https://randomuser.me/api/')
# Create HTTP object for detailed control
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
# Create request object with custom headers
request = Net::HTTP::Get.new(uri)
request['User-Agent'] = 'Ruby-API-Demo/1.0'
puts "=== Request Details ==="
puts "Method: #{request.method}"
puts "URI: #{uri}"
puts "Headers: #{request.to_hash}"
# Make the request
response = http.request(request)
puts "Status: #{response.code} #{response.message}"
puts "Content-Type: #{response['content-type']}"
puts "Body length: #{response.body.length} characters"
if response.code == '200'
data = JSON.parse(response.body)
user = data['results'].first
name = user['name']
puts "Generated user: #{name['first']} #{name['last']}"
puts "Email: #{user['email']}"
puts "Location: #{user['location']['city']}, #{user['location']['country']}"
else
puts "Request failed with status #{response.code}"
end
end
fetch_random_user
The first highlighted section replaces the simple get_response
call with separate HTTP and request objects. This provides access to request headers and debugging information before the request is sent. The second section adds response introspection to see content type and body size.
This manual approach provides complete visibility into the HTTP conversation, useful for debugging API issues and understanding response formats.
Run the enhanced version:
ruby basic_api_call.rb
=== Request Details ===
Method: GET
URI: https://randomuser.me/api/
Headers: {"accept-encoding" => ["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"], "accept" => ["*/*"], "user-agent" => ["Ruby-API-Demo/1.0"], "host" => ["randomuser.me"]}
Status: 200 OK
Content-Type: application/json; charset=utf-8
Body length: 1187 characters
Generated user: Fradique da Paz
Email: fradique.dapaz@example.com
Location: Porto Seguro, Brazil
The output reveals exactly what your Ruby application sends and receives. The request headers show Ruby automatically adds compression support (accept-encoding
) and sets a host header, while preserving your custom user-agent
. The response details confirm the API returns JSON data (application/json
) with a specific character encoding, helping you understand the data format before parsing.
This approach separates request creation from execution, providing access to detailed request and response properties while maintaining the same core functionality. The http.use_ssl = true
setting enables HTTPS for secure API communication.
However, creating HTTP objects and request configurations manually becomes verbose for applications making frequent API calls. This is where higher-level gems like HTTParty shine by simplifying common patterns.
Simplified API calls with HTTParty
While Net::HTTP
provides complete control, the HTTParty gem offers a more convenient interface for common API consumption patterns. HTTParty automatically handles JSON parsing, SSL, and provides a cleaner syntax.
First install HTTParty:
gem install httparty
Let's refactor our Random User example using HTTParty to see the difference:
require 'httparty'
class RandomUserAPI
include HTTParty
base_uri 'https://randomuser.me'
def fetch_user
response = self.class.get('/api/')
if response.success?
user = response.parsed_response['results'].first
name = user['name']
puts "Generated user: #{name['first']} #{name['last']}"
puts "Email: #{user['email']}"
puts "Location: #{user['location']['city']}, #{user['location']['country']}"
else
puts "Error: #{response.code} - #{response.message}"
end
end
end
api = RandomUserAPI.new
api.fetch_user
HTTParty's class-based approach encapsulates the API endpoint configuration. The include HTTParty
statement adds HTTP methods to your class, while base_uri
sets the common URL prefix. The parsed_response
method automatically converts JSON to Ruby objects.
Run the HTTParty version:
ruby httparty_user_api.rb
Generated user: Leo Tanner
Email: leo.tanner@example.com
Location: Lieksa, Finland
This compact example demonstrates HTTParty's power - the core API call reduces to just self.class.get('/api/')
while automatically handling JSON parsing, SSL configuration, and providing convenient response methods like success?
.
Now let's add response inspection to see what HTTParty provides access to:
require 'httparty'
class RandomUserAPI
include HTTParty
base_uri 'https://randomuser.me'
def fetch_user
response = self.class.get('/api/')
puts "Status: #{response.code} #{response.message}"
puts "Headers: #{response.headers.to_hash}"
if response.success?
user = response.parsed_response['results'].first
name = user['name']
puts "Generated user: #{name['first']} #{name['last']}"
puts "Email: #{user['email']}"
puts "Location: #{user['location']['city']}, #{user['location']['country']}"
else
puts "Error: #{response.code} - #{response.message}"
end
end
end
api = RandomUserAPI.new
api.fetch_user
Status: 200 OK
Headers: {"date" => ["Wed, 27 Aug 2025 08:42:39 GMT"], "content-type" => ["application/json; charset=utf-8"], "transfer-encoding" => ..."]}
Generated user: Hermelinda Rosado
Email: hermelinda.rosado@example.com
Location: Santa Cruz de Rosales, Mexico
The highlighted lines show HTTParty provides the same response introspection as Net::HTTP but with simpler syntax. Compare this to the manual Net::HTTP approach: no HTTP object creation, no SSL configuration, no manual JSON parsing, and automatic response format detection. HTTParty eliminates the boilerplate while preserving access to response details when needed.
Most production APIs require authentication to access their endpoints. Ruby's HTTP libraries provide flexible approaches to handle various authentication schemes, from simple API keys to complex token-based systems.
Final thoughts
Ruby's HTTP ecosystem balances simplicity with power. Use Net::HTTP
for maximum control and zero dependencies, or HTTParty for rapid development with built-in conveniences.
Key patterns for production API consumption include proper authentication management, error handling with retries, and response processing. Ruby's object-oriented design makes these patterns natural to implement and maintain.
Start with simple implementations and add complexity as your needs grow - Ruby's flexible architecture supports both approaches equally well.
For advanced HTTP client features and performance optimization, explore the comprehensive documentation: