What is the proper "Rails Way" to consume a RESTful web service on another domain?

Ruby on-RailsRest

Ruby on-Rails Problem Overview


I would like to write a Ruby on Rails application that consumes a RESTful web service API performs some logic on the result and then displays that data on my view. For example, let's say I wanted to write a program that did a search on search.twitter.com. Using pure ruby I might create the following method:

def run(search_term='', last_id=0)
  @results = []
  url = URI.parse("http://search.twitter.com")
  res = Net::HTTP.start(url.host, url.port) do |http|
    http.get("/search.json?q=#{search_term}&since_id=#{last_id.to_s}")
  end
  @results = JSON.parse res.body
end

I'm tempted to just drop that method into my Rails controller as a private method, but part of me thinks that there is a better, more "Rails" way to do this. Is there a best practice approach or is this really the best way?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

There is a plugin/gem called HTTParty that I've used for several projects.

http://johnnunemaker.com/httparty/

HTTParty lets you easily consume any web service and parses results into a hash for you. Then you can use the hash itself or instantiate one or more model instances with the results. I've done it both ways.

For the twitter example, your code would look like this:

class Twitter
  include HTTParty
  base_uri 'twitter.com'

  def initialize(u, p)
    @auth = {:username => u, :password => p}
  end

  # which can be :friends, :user or :public
  # options[:query] can be things like since, since_id, count, etc.
  def timeline(which=:friends, options={})
    options.merge!({:basic_auth => @auth})
    self.class.get("/statuses/#{which}_timeline.json", options)
  end

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

# usage examples.
twitter = Twitter.new('username', 'password')
twitter.post("It's an HTTParty and everyone is invited!")
twitter.timeline(:friends, :query => {:since_id => 868482746})
twitter.timeline(:friends, :query => 'since_id=868482746')

As a last point, you could use your code above also, but definitely include the code in a model as opposed to a controller.

Solution 2 - Ruby on-Rails

Restclient is a really nice solution to this problem.

require 'rest_client'
RestClient.get 'http://example.com/resource'
RestClient.get 'http://example.com/resource', {:params => {:id => 50, 'foo' => 'bar'}}

From the readme.

Solution 3 - Ruby on-Rails

if the remote RESTful web service was also created with Ruby on Rails, ActiveResource is the way to go.

Solution 4 - Ruby on-Rails

In response to your Twitter example, there is a Twitter Gem that would help to automate this for you.

Solution 5 - Ruby on-Rails

I think Faraday deserves a mention here. Really nice interface, and powerful concept of middleware.

https://github.com/lostisland/faraday

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike FarmerView Question on Stackoverflow
Solution 1 - Ruby on-RailsKyle BoonView Answer on Stackoverflow
Solution 2 - Ruby on-RailsEthan HeilmanView Answer on Stackoverflow
Solution 3 - Ruby on-RailsAdam AlexanderView Answer on Stackoverflow
Solution 4 - Ruby on-RailsAdam AlexanderView Answer on Stackoverflow
Solution 5 - Ruby on-RailsDukeView Answer on Stackoverflow