Abusing HTTParty for a Tender client
We all know how great Tender is and had a chance to play with their great API while writing a tool to send out an email every morning with any pending issues.
They’ve done some really great stuff with it, especially with their use of URI Templates.
If you haven’t played with URI Templates before, an example of their JSON with a template in it looks like:
{"site_href": "http://api.tenderapp.com/{site_permalink}"}
which, with the Addressable gem would allow us to say:
>> require 'addressable/template'
>> tmpl = Addressable::Template.new('http://api.tenderapp.com/{site_permalink}')
>> tmpl.expand('site_permalink' => 'help').to_s
=> http://api.tenderapp.com/help
To make things nice and strait forward, Tender follows the convention of using _href
as the suffix for any key that contains a template. I was able to use this along with a little magic I snuck into Hash to make my code that much prettier.
All that was required to expand the templates was a little module:
module JsonHelpers
def href(key, opts = {})
Addressable::Template.new(self["#{key}_href"]).expand(opts).to_s
end
end
which I was able to mix in to any Hash
that was returned:
# Make the JSON a litte bit more fun to work with
def self.add_json_helpers(data)
case data
when Hash
data.send(:extend, TenderSummary::JsonHelpers)
data.each { |_, value| add_json_helpers(value) }
when Array
data.each { |elem| add_json_helpers(elem) }
end
data
end
and then tell HTTParty
to use it by specifying a custom parser
:
module TenderSummary
class TenderApi
include HTTParty
headers 'Accept' => 'application/vnd.tender-v1+json'
format :json
parser Proc.new { |b| add_json_helpers(Crack::JSON.parse(b)) }
# ...
With all this done, it made it very simple to generate the URLs to the resources I wanted access to.
# assuming `site` holds the JSON returned from
# 'http://api.tenderapp.com/{site_permalink}'
discussion_url = site.href(:discussions, :state => :pending)
You can see the entire class of TenderApi
on GitHub.