Adam @ Heroku
a tornado of razorblades

Rest Client

Posted by Adam Wiggins on March 09, 2008 at 08:03 PM

REST is part of the Ruby Way. Which is why I'm surprised that every time I go to access a RESTful resource, I find myself writing some sort of ad-hoc rest client. Net::HTTP is too low level - you've got to write at least three or four fairly dense lines of code even for a relatively simple GET or PUT.

I was banking on ActiveResource being the defacto solution starting with Rails 2, but I was a bit disappointed when it was finally released. Its purpose is fairly narrow - accessing resources that are database-recordish and which operate completely in a certain XML format. But further, it doesn't (as near as I can tell) support nested resources, which cuts out about 70% of what I might want to use it for.

The only other thing I can find is this, which monkey patches open-uri to handle other kinds of verbs. Fine, but still a bit too low level.

While I was toying with Sinatra the other day, I realized that what I wanted was just the client-side equivalent of its controller syntax. So I threw together rest-client.

require 'rest_client'

RestClient.get 'http://gemtacular.com/gems'

RestClient.post 'http://myphotosite.com/users/adam/photos', File.read('pic.jpg'), :content_type => 'image/jpg'

RestClient.destroy 'http://heroku.com/apps/myapp'

The middle one - post (or put) with a payload an non-xml content-type - is the one that interests me the most, and that I find hardest to do with other libraries. Particularly for a one-off on the command line. I'll usually hobble together a curl command with a bunch of obscure switches that I can never remember. But now, I've just added require 'rest_client' to my .rush/env.rb, so at the rush command line I can instantly access any REST resource on the web with an easy-to-remember one-liner.

I also threw together a test server at rest-test.heroku.com, to try out all the different verbs. It just echoes back the verb, resource you requested (wildcard routing will match anything), and info about the payload. Here's a session from my rush shell:

rush> RestClient.get "http://rest-test.heroku.com/some/resource"
GET http://rest-test.heroku.com/some/resource
rush> RestClient.put "http://rest-test.heroku.com/some/resource", home['pic.jpg'].contents, :content_type => 'image/jpg'
PUT http://rest-test.heroku.com/some/resource with a 70335 byte payload, content type image/jpg
rush> RestClient.delete "http://rest-test.heroku.com/some/resource"
DELETE http://rest-test.heroku.com/some/resource

gem install rest-client if you'd like to give it a try. RDocs here.

Hierarchy: previous, next

Comments

There are 6 comments on this post. Post yours →

Dan Kubb

I agree with your comments about Net::HTTP being too low level, and ActiveResource being too tightly coupled to the "Rails Way" of doing things.

The only suggestion I would make that would (IMHO) be even cleaner is to make it so that you create the Resource object using the URI, and then call methods on the resource.

Here's an example (please excuse the formatting if this comes out messed up):

resource = Resource.new 'http://www.example.com/users/adam/photos' resource.post File.read('pic.jpg'), :content_type => 'image/jpg'

pic_file = resource.get

resource.destroy

Great suggestion, Dan. I'll see if I can add something like that in the next version.

I am new to web programming - but I have been kicking around IT as a sysadmin for a dozen years - so I at least have an idea of what you're talking about. But ..

What would I do with this? Any example of how I can use this for (say) an inventory database?

Shamika

Can u please explain how to implement PUT request from NET::HTTP and also from Rest_client.. I just want to see the difference... Thanks

@Shamika -

RestClient.put 'http://rest-test.heroku.com/uri', :foo => 'bar'

vs.

Net::HTTP.start('rest-test.heroku.com', 80) do |http| http.request Net::HTTP::Put.new('/uri', 'foo=bar&') end

Hiya,

This is a great little tool, thank you for putting it together. I'm trying to use it to access some third party software, which returns an html file (or xml) which contains some data I wish to use.

I ran the following code:

def index resource = RestClient::Resource.new('http://.../startupexchange/') response = resource.post({'cmd' => 'list_claims'}, :accept => 'xml') puts response end

This works fine at the command line, and response is correctly output from the 'puts' into my logger. However I can't seem to access the data in response within my program.

For example, when I try to display it in a view using:

I get some gobbledygook reference, which I can't seem to decode: #

There doesn't seem to be any documentation on what ActionController::CgiResponse does, or what this reference is. Do I need to use a method to display it? Can anyone help me with this? Whats going on?

Antony

Post a comment

Required fields in bold.