Simple Flickr API methods in Ruby
This post might get a bit technical, but I felt compelled to write a short post/tutorial about web services and Ruby. While working a on a little side project, I depended heavily on some now forgotten blog posts I found through Google. I went through pretty much all Flickr libraries available for Ruby, but couldn’t find anything that suited my task. I was surprised how easy it was to do it just by myself as I only needed a specific subset of the methods offered by Flickr. I hope the following helps someone, just like the posts I found helped me.
There are many libraries in RubyGems and Rubyforge for accessing Flickr’s web services. Too bad most of them are either outdated, lack any useful documentation or just plainly suck. For example, some of them require you to edit the library sources to replace the API key, which is declared as a constant. And then there’s the little annoyance that some of the existing API libraries look like they were translated from equivalent Python code and are pretty far from anything resembling the Ruby Way and may be hard to understand by a beginner. Then there’s the chance that a given API doesn’t implement the whole set of Flickr’s API methods or just not the one you were after. One nice exception is Flickraw, but it’s not the most coder-friendly library out there unless you’re familiar with advanced methods. What I’m after here is a solution that is understandable by a Ruby newbie.
There might be many reasons for this state. It could be that it is very trivial to write your own (in fact, in many Ruby books (f.e. pretty great Ruby Cookbook) Flickr’s API is used as an example). The other reason might be that Ruby is still not widespread for these kinds of tasks. One major reason for this in turn is that it’s a magnitude easier to deploy a Perl, PHP or Python solution on your average web host. One would imagine that many Ruby on Rails-projects might want to tap into Flickr.
As I said, it’s really easy to write your own code to access Flickr. Like so easy that I tried to write my own solution, when I didn’t find a suitable library. That is not without its irony as the strength of high level scripting languages seems to be that you quickly learn not to reinvent the wheel. Anyway, in this case we get a lot for free by just using the built-in functionalities in Ruby. What I’m going to show below is based on open-uri, cgi and REXML – all part of the standard library.
require "rexml/document"
require "open-uri"
require "cgi"
Because we’re not writing a library here, we can declare the API key as a constant. In a library, you’d probably want to have something like FlickrClient.new(API_KEY).
API_KEY = "invalid" # Get your own at http://www.flickr.com/services/api/
As readers of Ruby Cookbook might notice, so far this is similar to what that book suggests. The methods in that book are a bit different and in my opinion useful just for that simple task defined in that chapter. I’ve tried to make things a bit more flexible. One way to keep things clean is to make a request-method, preferably inside a suitable class.
def request(method, arguments={})
endpoint = "http://api.flickr.com/services/rest/"
arg_map = arguments.collect {|arg,value| CGI.escape(arg)+"="+CGI.escape(value.to_s)}.join("&")
call_uri = "#{endpoint}?api_key=#{API_KEY}&method=#{method}&#{arg_map}"
response = REXML::Document.new(open(call_uri).read)
if response.root.attributes["stat"] == "ok" then
return response
elsif response.root.attributes["stat"] == "fail" then
raise "Flickr API error #{response.elements["rsp/err"].attributes["code"]}: #{response.elements["rsp/err"].attributes["msg"]}"
else
raise "Request status neither ok nor fail. Tried to fetch #{call_uri}."
end
end
method is any of the methods defined in Flickr’s API (f.e. flickr.test.echo) and arguments is a hash (f.e. {"foo"=>"bar"}). The method returns a REXML::Document for further use if the request is successful. Someone not familiar with Ruby might be wonder what the collect method does. It simply goes through the arguments array and collects the argument/value-pairs into a nice HTTP GET argument string. Notice how by using open-uri we can simplify the actual HTTP connection to look like we’re reading a file. I’m not that good parsing XML, so there might be alternative ways to simplify the REXML-things above.
After this, implementing Flickr’s various search and get methods is pretty straightforward mapping of XML into objects. For example, if you have defined a Photo class, which new method takes a photo id as an argument, you could implement photo searching (as a class method) like this.
def Photo.search(arguments={})
response = request("flickr.photos.search",arguments)
photo_ids = REXML::XPath.match(response, "//photo/attribute::id").collect { |a| Photo.new(a.value) }
end
The method above returns an array of Photo objects, which depending on your implementation of the object might do something else than just store a photo_id. (Above I couldn’t for the life of me figure out how to get REXML return an array of values, so I depended on the always useful collect, again.) Anyway, with a method similar to above you can easily make more specialized methods like Photo.search_by_something. For example, the code below takes an array of tags. Further arguments are passed on to Photo.search as is.
def Photo.search_by_tags(tags, arguments={})
arguments["tags"] = tags.join(",")
Photo.search(arguments)
end
Writing these kind of helper methods is the extra mile that makes your code more Ruby-like. Or at least more Ruby on Rails-like.
After writing a zillion search/get-methods you might appreciate the genius behind Flickraw, which builds those methods dynamically. Things get interesting again when you start to code the authentication scheme and implement uploading of photos. The above Photo.search is pretty simple, as it is not authenticated. On the other hand, just take a look at the various arguments you can send to flickr.photos.search and wonder how you could implement those in a nice way in your code. In the above snippets, all arguments are collected as a hash.
Actually, pretty much any method which modifies or adds data to Flickr is going to a bit more complicated. It’s easy to trust that Flickr sanitizes and cleans the data that you get through their web services. You’d imagine they do the necessary sanity checks on their end. But when it’s Flickr’s turn to accept data from you, it’s suddenly your job to handle user input and all the exceptions and stuff you might encounter.
What I appreciate in the above examples is that how simple is it to write a simple web service client in Ruby. Pretty much all the hard lifting is abstracted away as we depend on various libraries that make life easier.










[...] Simple Flickr API methods in Ruby By Kari Silvennoinen … easier to deploy a Perl, PHP or Python solution on your average web host. One would imagine that many Ruby on Rails-projects might want to tap into Flickr. As I said, it’s really easy to write your own code to access Flickr. … Tech IT Easy – http://techiteasy.org [...]
[...] Comment on Simple Flickr API methods in Ruby by Perl Coding School … By Perl Coding School » Blog Archive » perl… … easier to deploy a Perl, PHP or Python solution on your average web host. One would imagine that many Ruby on Rails-projects might want to tap into Flickr. As I said, it’s really easy to write your own code to access Flickr. … Comments for Tech IT Easy – http://techiteasy.org [...]