It's Time To HTTParty!

When you’re developing with Ruby, it’s pretty inevitable that at some point you come across an HTTP API that doesn’t have a gem available. While writing Hopefully Sunny I ran into just that situation with World Weather Online’s weather API. It’s often really tempting to go searching for a different API to use instead, but it’s actually not so hard to just write your own wrapper library. Let’s take a look at one of my favorite libraries for working with HTTP APIs, HTTParty, and in the process we’ll figure out how to write our own simple API wrapper libraries.

Getting Set Up

You’re using Bundler, right? If so, it’s a piece of cake to get started with HTTParty. Just add gem httparty to your Gemfile, run bundle from the command line, and you’re on your way. If you want more info about Bundler, they’ve got a great site with all sorts of helpful information about how to get up and running at http://gembundler.com.

If you’re not using Bundler, you can run gem install httparty to get HTTParty installed. You’ll want to add require 'httparty' where appropriate to include it into your scripts.

Really Basic Integration

At its core, HTTParty encapsulates HTTP. The HTTParty module exposes all of the normal HTTP request methods, like GET, POST, PUT, and DELETE. So, for example, you can make a GET request to a URL with the following code:

1
2
response =
  HTTParty.get("http://rubygems.org/api/v1/versions/httparty.json")

The URL that we’re accessing above is from the RubyGems API, and will return a bit of JSON representing the versions of the httparty gem, as an array of objects containing information about each version. Here’s a sample of what that JSON looks like:

1
2
3
4
5
6
7
8
9
10
[
  {
    "number":"0.7.8",
    "built_at":"2011-06-07T00:00:00Z",
    "prerelease":false,
    "downloads_count":22720,
    ...
  },
  ...
]

The object returned from HTTParty.get is an HTTParty::Response object containing the JSON that was returned from the site, along with its headers and other methods relating to the HTTP protocol, like the protocol version. One of the coolest features of HTTParty is that it automatically parses JSON and XML responses, based on the Content-Type of the response, so as soon as your response comes back it’s ready for you to work with it:

1
2
3
puts response[0]["number"]
 
> 0.7.8

If I’m integrating with something really simple, where really all I need is to GET or POST to a url and work with the response, this is usually the technique that I use. I went with this basic strategy when writing my World Weather Online code for Hopefully Sunny, because I really only had one API call that I needed to access with their service. That’s not normally the case, though, so HTTParty also makes it really easy to wrap your APIs in classes.

Wrapping The Entity In A Class

Let’s continue writing a library against the RubyGems API. If we’re going to look at versions we should probably also be able to look at the base details for any particular RubyGem, like its name and authors, and then it will probably be helpful to look up the versions directly from that result. We’ll wrap all of this functionality into a RemoteGem class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class RemoteGem
  include HTTParty
 
  base_uri "rubygems.org/api/v1"
 
  attr_accessor :name, :info, :version, :authors, :downloads
 
  def initialize(name, info, version, authors, downloads)
    self.name = name
    self.info = info
    self.version = version
    self.authors = authors
    self.downloads = downloads
  end
 
  # Returns the versions for this particular RemoteGem
  def versions
    response = self.class.get("/versions/#{name}.json")
    if response.success?
      response
    else
      raise response.response
    end
  end
 
  # Find a particular gem, based on its name
  def self.find(name)
    response = get("/gems/#{name}.json")
    if response.success?
      self.new(response["name"], response["info"], response["version"],
         response["authors"], response["downloads"])
    else
      # this just raises the net/http response that was raised
      raise response.response
    end
  end
end

This gives us a RemoteGem class with a find method that will let us find gems by name. Once a gem is loaded we can also get an array of its versions by calling the versions method. Here’s a quick example of using the wrapper class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
httparty = RemoteGem.find("httparty")
puts httparty
 
> <remoteGem:0x10249b0d0 @downloads=453514, @name="httparty",
    @info="Makes http fun! Also, makes consuming restful web
    services dead easy.", @authors="John Nunemaker, Sandro Turriate",
    @version="0.7.8">
 
puts httparty.versions
 
> <httparty::Response:0x102419990 @parsed_response=
    [{"built_at"=>Tue Jun 07 00:00:00 UTC 2011,
    "number"=>"0.7.8", "prerelease"=>false,
    "authors"=>"John Nunemaker, Sandro Turriate",
    "description"=>"Makes http fun! Also, makes consuming restful web
    services dead easy."...

As an aside, this is a good place to stop and remind you of the importance of naming. At first, I thought I would name the class above Gem, but that ended up being a pretty bad idea since RubyGems already defines a class named Gem. Probably the best strategy would be to put all of your classes inside of a module named for your wrapper project.

If you really wanted to get fancy you would actually write a Version class and put all of the version results from the versions HTTP request into an array of those objects.

Posting Data

How awesome is this? We now know how to wrap up an API of GET requests with classes in Ruby using HTTParty. What if we need to post something, though? We already talked about the fact that a post method is available, but how do we actually submit data with the post request? Fortunately, all of the HTTParty request methods (get, post, put, delete, head, options) support a second options parameter that will let us do all sorts of neat modifications to the request. First, let’s set some post parameters to the body of the request:

1
2
HTTParty.post("http://rubygems.org/api/v1/gems/httparty/owners",
    :query => { :email => "alan+thinkvitamin@carsonified.com" })

The query option expects a Hash of the parameters that you’re submitting. In this case we’re trying to post with the email parameter set to my email address. You can use the post method with query parameters pretty similarly to how we used get above in a wrapper class.

Headers

Headers are set in about the same way. You pass the headers option to your chosen HTTP method with a hash of the headers you would like to include. My request above wouldn’t actually have worked correctly, because it doesn’t include the Authorization header with my API key. Let’s set that now:

1
2
3
HTTParty.post("http://rubygems.org/api/v1/gems/httparty/owners",
    :query => { :email => "alan+thinkvitamin@carsonified.com" },
    :headers => { "Authorization" => "THISISMYAPIKEYNOREALLY"})

We’re posting to that same URL, but adding an Authorization header. You can also see that we can still send the query parameters as well.

Bonus Points: Package It and Share It

We’ve learned how to access HTTP APIs using HTTParty directly and how to wrap them into classes for even easier use. You can’t stop there, though. If you’ve gone through all of that hard work to wrap up an API library, you’ve got to package that library up into a gem and share it with others. This article would get ridiculously long if I covered that too, but if you’re interested in doing that I’d definitely recommend checking out the Bundler page on creating RubyGems. It’s a good start to creating gems with help from Bundler.

Now go get started on writing your own API wrappers!

Interested in learning more about Ruby and Ruby on Rails? Check out the Ruby and Ruby on Rails courses on Think Vitamin Membership!

Free Workshops

Watch one of our expert, full-length teaching videos. Choose from HTML, CSS or WordPress.

Start Learning

Treehouse

Our mission is to bring affordable Technology education to people everywhere, in order to help them achieve their dreams and change the world.

Comments

One comment on “It's Time To HTTParty!