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.
Contents
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:
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:
[
{
"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:
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.
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:
httparty = RemoteGem.find("httparty")
puts httparty
>
puts httparty.versions
> 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:
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:
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.
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!