Ruby Libs for Making Web Calls

http ruby restclient rest

Fri Aug 08 12:10:00 -0700 2008

John Nunemaker created HTTParty, a library for making web requests. So the options for making web calls from Ruby are now:

  • Net::HTTP
  • RestClient
  • HTTParty
  • ActiveResource

Putting them side-by-side, we see that they each fill a significant niche, which makes HTTParty a welcome additon to the… erm, party. I’ve listed them in order from lowest level (least structure) to highest level (most structure).

Net::HTTP gives you very raw HTTP access. RestClient lets you do most calls in a single line and without creating any new classes, but still leaves parsing the response up to you. HTTParty requires creating one or more classes, but handles many response types for you. ActiveResource provides the most structure, including requiring a class for each resource and mandating URLs and request and response types.

I find Net::HTTP to be too low level to ever bother with anymore, now that these other options exist. I do use ActiveResource, but only for accessing Rails resources on apps that I control directly; and I’ve become increasingly annoyed with its excessively opinionated restrictions. I created RestClient to help fill this middle ground; HTTParty will help fill this gap too.

I thought the HTTParty Twitter API example was an interesting one, so here’s a version with each library.

Net::HTTP

Net::HTTP.start('twitter.com') do |http|
  http.basic_auth('username', 'password')
  res = Net::HTTP::Post.new('/statuses/update.json', 'query[status]="Sending a tweet"').request
  JSON.parse res.body
end

RestClient

JSON.parse RestClient.post('http://username:password@twitter.com/statuses/update.json', 'query[status]' => "Sending a tweet")

HTTParty

class Twitter
  include HTTParty
  base_uri 'twitter.com'

  def initialize(user, pass)
    self.class.basic_auth user, pass
  end

  def post(text)
    self.class.post('/statuses/update.json', :query => { :status => text })
  end
end

Twitter.new('username', 'password').post("Sending a tweet")

Generally I prefer the lightweight approach of not defining a custom class, especially for hitting arbitrary URLs. But if you’re making many calls to the same service, wrapping it up in a class makes sense. Here’s a RestClient example with a class, i.e. more like HTTParty or ActiveResource:

RestClient (defining a class)

class Twitter
  def initialize(username, password)
    @resource = RestClient::Resource.new 'http://twitter.com', username, password
  end

  def post(text)
    JSON.parse @resource['statuses/update.json'].post(:query => { :status => text })
  end
end

Twitter.new('username', 'password').post("Sending a tweet")

One other catch with HTTParty: it relies on ActiveSupport for parsing JSON and XML responses, introducing some heavyweight dependencies into your app, same as ActiveResource. (If you’re inside a Rails app, this is moot, since you already have these libs loaded.) It would be relatively easy to switch it to using the json and libxml gems instead; and better yet, it could include those libraries on the fly when it receives a response of that type. So if your app never receives a json or xml response, you won’t have the extra memory footprint of those libraries.