19 June 2008

Listing your photo albums with the Flickr API and jQuery

Over the last couple of days, I've tidied up a few things on this site. One task was to make a list of albums appear on the left-hand navigation here, underneath ‘Photographs’, downloaded automatically from Flickr.

Once of the great things about Flickr is its very comprehensive API. But turning an API call which lists the albums (‘photosets’ in Flickr parlance) into some useful HTML takes a little bit of effort.

The first task is to construct the query URL. The URL to query all my photosets looks like this:

http://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key=xxx&user_id=99837685@N00&format=json

You need to replace ‘xxx’ with the API key which you get from Flickr. It's a free and automatic process to get an API key.

Retrieving this URL, with a valid API key, gives you a JSON response like the following:

jsonFlickrApi({
    "photosets": {
        "photoset": [ {
            "id": "72157604307419500", 
            "primary": "2372816823", 
            "secret": "c76ae35928", 
            "server": "3264",
            "farm": 4,
            "photos": "5",
            "title": { "_content": "Axis & Allies" }, 
            "description": { "_content": "A day of intense gaming ..."}
        }, ... ],
    },
    "stat":"ok"
})

In our HTML page, we can use jQuery to write some JavaScript that creates a list of albums and inserts it somewhere into the page:

$.getJSON("http://api.flickr.com/services/rest/?...&jsoncallback=?", function (data) {
    var list = $("<ul></ul>");
    $.each(data.photosets.photoset, function (i, set) {
        var link = $("<a/>").attr("title", set.description._content)
            .attr("href", "http://www.flickr.com/photos/mjryall/sets/" + set.id)
            .text(set.title._content);
        var li = $("<li/>").append(link).append(" (" + set.photos + ")");
        $(list).append(li);
    });
    $("#flickr-sets").append(list);
});

I'll explain this line by line because the code is quite dense.

Line 1 tells jQuery (the dollar sign is jQuery) to do an AJAX call to retrieve the data from Flickr and interpret the response as JSON. You need to replace ‘…’ with the actual parameters like in the URL above. Because this is a cross-site request (from my website to api.flickr.com), you need to put '&jsoncallback=?' at the end of the URL. JQuery replaces the last question mark in the URL with it's own value to retrieve the data from the remote site. This is a neat trick called JSONP.

Line 2 creates a new unordered list element using jQuery. This is the list we'll populate with the information. It isn't currently visible or attached to the document.

Line 3 iterates through the photosets, calling the provided function with each photoset and its index. So for each photoset, or album, we run through lines 4–8.

Lines 4–6 create a new anchor (link) element for the current photoset using jQuery and set some attributes on it. The title attribute of the link is set to the description of the album. The href attribute, or destination of the link, is set to the photoset URL. The link is hard-coded to my username, but you could retrieve this from the Flickr API if you wanted to. The text of the link is set to the name of the photoset.

Line 7 creates a new list item, and inserts into it the link and the text ‘(x)’, where ‘x’ is the number of photos in the album.

Line 8 adds the list item to the list we've created.

Line 10 puts the list inside the element in the page with an ID of ‘flickr-sets’. On my blog, this is an empty paragraph tag in the navigation area on the left-hand side.

So what are the neat things about this implementation? It's dynamic, always up-to-date from Flickr. The JSON result is turned into JavaScript objects by jQuery, so you can pull out data very easily. JQuery makes building up a complex HTML structure fairly simple and browser-agnostic.

What isn't so good? Well, the photosets JSON doesn't change very often, but it is downloaded from Flickr with every page view. My list of sets is 7 KB of JSON, but could easily be much more. Flickr does a search on their server to generate the list, so it takes a bit longer than just retrieving the data. On the right-hand side of my blog, I have some random photos pulled from Flickr too. Pulling back all the photos before deciding which ones to show would mean downloading 50 KB of JSON data from Flickr with every page view.

Fortunately, there's a fairly simple solution to this on my server. I set up an automated task on the server to download the contents of the JSON URLs once per day and save them in two well-known locations. All I need to do then is change the JavaScript code to use these URLs instead of the Flickr API URLs. You can see this in the JavaScript used by this page.

In the case of the photos on the right, I have an additional step. On the server, a script I wrote pulls out just a selection of random photos from the JSON file on the server. This serves up eight or ten photos in a very small JSON response instead of the full 50 KB containing all the photos that I have tagged to show on my blog.