Editor's note: IBM® WebSphere® sMash and IBM WebSphere sMash Developer Edition are based on the highly acclaimed Project Zero incubator project. Project Zero is the development community for WebSphere sMash and will continue to offer developers a cost-free platform for developing applications with the latest builds, the latest features, and the support of the community.
This article assumes that you have downloaded Project Zero and either completed the introductory tutorial or written a simple application yourself. You should also read the overview of Flickr's REST API provided in the Resources section; the overview includes instructions for obtaining a Flickr API key, which you will need to test the code provided in this article.
The Flickr photo sharing service is one of today's most popular Web applications, and it includes a public API that lets developers access its photo data using HTTP requests. Flickr's API is RESTful and fairly easy to understand, but some tedious steps are still required to make requests and read the responses. This article shows you how you can remove that tedium and make communication between Zero and Flickr as simple as a few lines of code. This article also explores some of the more interesting extension points of Project Zero.
Encapsulating Flickr APIs with Groovy
The Flickr API for reading and writing photo data is based on messages sent over HTTP and data structures formatted in XML or JSON. This article uses JSON because its data structures -- simple maps and lists -- are easier to manipulate from a Groovy perspective. In this section, you'll see how to use Zero's global context and Groovy scripting to create some simple wrapper methods for Flickr's API.
To complete our "Zero-ization" of the Flickr API, you need to create two Zero projects: one for the Groovy code that interacts with Flickr and one that uses the Groovy code to do something useful. Call the first project zero.services.flickr and the second project flickr.test. If you would like to skip ahead, you can download the completed sample projects from the Resources section. If you want to code for yourself, start by creating the two sample projects with the Zero command line interface shown in Listing 1:
Listing 1. Creating test projects
$ zero create zero.services.flickr
$ zero create flickr.test
|
Edit the Ivy file for flickr.test and add a dependency on zero.services.flickr. Open /config/ivy.xml and add the following line of XML code shown in Listing 2:
Listing 2. Adding Ivy dependencies
<dependency name="zero.services.flickr" org="zero" rev="1.0+"/>
|
The zero.services.flickr project does not require additional libraries or dependencies because the Flickr API is built on HTTP and JSON; you will be using the HTTP and JSON libraries included in Zero Core to communicate with Flickr and create URLs to actual image files.
Every Flickr request requires a method name and a set of parameters (the set may be empty). Responses come back as JSON objects that have a status property (set to ok or fail) in addition to the data that was requested. You can take advantage of the fact that JSON objects are represented in Groovy as simple maps and lists and create a very simple API for sending requests and reading responses. Let's start with a use case: You would like for your users to make Flickr requests in just three or four lines of code, as in Listing 3:
Listing 3. Prototype #1 for "Zero-ized" Flickr API
def method = "flickr.photosets.getPhotos";
def params = [
photoset_id: 1234567890,
per_page: 25
];
def response = invokeMethod("flickr.groovy", "flickr");
|
This code is nice, but it could be improved by leveraging Zero's global context. Storing request and response data in the global context makes it easier for developers to split up request and response processing across scripts or files; for example, a server-side script may make API calls to one or more services while the response data is rendered by a client-side template. Listing 4 shows how to accommodate this use case:
Listing 4. Prototype #2 for "Zero-ized" Flickr API
request.flickr.method = "flickr.photosets.getPhotos";
request.flickr.params = [
photoset_id: 1234567890,
per_page: 25
];
invokeMethod("flickr.groovy", "flickr"); // uses GC for I/O
def response = request.flickr.response[];
|
Now that the design is in place, it's time to write some code. In the
zero.services.flickr project, create a Groovy script at /app/scripts/flickr.groovy. The first method to add to this file will be the flickr() method from Listings 3 and 4. To implement this method, you need to be aware of three things:
- The URI format for Flickr API calls.
- The value of your Flickr API key.
- Zero's Connection API for outbound HTTP requests.
The URI format for Flickr API calls is covered in the Flickr API documentation (see Resources); it boils down to creating a URI with query parameters for each of the request parameters provided by the user. You must also include your API key, which means that a convention is needed for providing the API key (lest users hardcode their API keys in their scripts). Listing 5 shows the code required to build up the request URI:
Listing 5. Building the Flickr request URI
def uri = "http://api.flickr.com/services/rest/?format=json&nojsoncallback=1";
uri += "&api_key=${config.flickr.key[]}";
uri += "&method=${request.flickr.method[]}";
request.flickr.params[].each() {
uri += "&${it.key}=${it.value}";
}
|
Note in Listing 5 that we've hardcoded the base Flickr URI and used JSON data
structures — those are not expected to change. Also note that we're reading the API key from a global context property named config.flickr.key; we will require that our users set this value in their applications' configuration files to encourage good programming practices. The final thing to notice about the code in Listing 5 is how Groovy's syntactical sugar simplifies the process of converting JSON objects (maps) into valid URIs. By using embedded variables and the each() method for iterating over the map, we created a fairly complicated URI in just five lines of very readable code.
Once you have the URI, you just have to send the request using Zero's Connection API. Fortunately, this API has a number of convenience
methods for invoking RESTful services. The code in Listing 6 makes an HTTP GET request and parses the response as JSON:
Listing 6. Processing the Flickr request
def response = Connection.doGET(uri);
def json = response.getResponseBodyAsString();
request.flickr.response = JSONObject.parse(json);
|
For this project, we will assume that all operations are GETs (reads); the code provided can be easily extended to include the use of POSTs (writes), but that is beyond the scope of this article.
The entire flickr() method is made up of the code in Listings 5 and 6 and can be seen in the sample project download that accompanies this article. You should refer to the flickr.groovy file in the download if you have any trouble piecing together the two listings into a working function.
Invoking methods is only part of the work that your users will need to do to incorporate Flickr data into their applications. Once they have the metadata for one or more photos, your users will need to create a URL to the actual image file(s) being shared by Flickr users. The image file URLs are not included in the JSON response data — you have to piece them together using the formatting instructions provided by Flickr (see Resources); because these URLs are very long and include a lot of variables, some convenience methods should be provided for constructing the URLs from Flickr's JSON responses.
Listing 7 shows two simple methods that take one of Flickr's photo data structures (used by all methods that return photo metadata) and create URLs for its image files. Hosted photos actually have a few image files, and our code accounts for this; users can take the photo data returned by Flickr and pass it to our thumbnail() and original() methods to see the thumbnail and original images, respectively. You can find the code for Listing 7 included in the same file as our flickr() method (/app/scripts/flickr.groovy):
Listing 7. Configuring the Flickr API key
def original(photo)
{
def server = "http://farm${photo.farm}.static.flickr.com/${photo.server}";
def name = "${photo.id}_${photo.originalsecret}_o.${photo.originalformat}";
return "${server}/${name}";
}
def thumbnail(photo)
{
def server = "http://farm${photo.farm}.static.flickr.com/${photo.server}";
def name = "${photo.id}_${photo.secret}_t.jpg";
return "${server}/${name}";
}
|
Global context shortcuts in Groovy
The code so far is useful, but one thing that is not as pretty as it could be is
the use of invokeMethod() in our user code. The invokeMethod() method is available to all Groovy scripts running on the Zero platform and provides a quick-and-dirty way to invoke code in another script; it's fine for code that will only be reused once or twice, but for a library such as this, invocation should be more natural. It would be best if the code in Listing 4 could be updated to invoke the flickr() method directly, as in Listing 8:
Listing 8. Prototype #3 for "Zero-ized" Flickr API
request.flickr.method = "flickr.photosets.getPhotos";
request.flickr.params = [
photoset_id: 1234567890,
per_page: 25
];
flickr();
def response = request.flickr.response[];
|
Zero Core already does this for a number of its commonly used APIs, including render(), listFiles(), and getRequestedUri(). These commonly used methods are called bindings. What you may not know is that Zero Core lets you extend the default Groovy bindings with your own methods so that you can easily invoke them from anywhere in your application. In this section, you'll learn how to create Groovy bindings for Flickr methods and increase their usability.
Adding your own Groovy bindings involves writing a class that implements the
zero.core.groovysupport.bindings.BindingHandler
interface and then registering the class in your application's zero.config file.
The BindingsHandler interface only has one method
—
addVariables()
— which allows you to
map binding names (like flickr()) to their actual implementations. Listing 9 shows how you would configure your BindingsHandler class in zero.config:
Listing 9. Adding Groovy bindings to Zero Core
[/config/bindings/.groovy[]]
my.bindings.handler.ClassName
|
If you are providing method bindings (like we are), you can make life a bit easier for yourself by having your class extend from zero.core.groovysupport.bindings.InvokeBindings
— this will let you forward all your method invocations to invokeMethod() and let it handle the execution of Groovy code. With this system, you get all the benefits of prettier method calls without having to load and execute Groovy scripts yourself. The configuration file will not change regardless of how you implement the interface.
To make these three Flickr methods readily available to other Groovy script
writers, a class called FlickrBindings has been
created, which maps the method names to calls to invokeMethod(), including the user-provided parameters. Listing 10
shows the code for this class. If you're coding as we go, you should add the class
in Listing 10 to the zero.services.flickr sample project:
Listing 10. The
FlickrBindings class
package zero.services.flickr;
import java.io.FileNotFoundException;
import java.util.Map;
import org.codehaus.groovy.runtime.MethodClosure;
import zero.core.groovysupport.bindings.InvokeBindings;
import zero.json.java.JSONObject;
public class FlickrBindings extends InvokeBindings
{
private static final String _SCRIPT = "flickr.groovy";
private static final String _FLICKR = "flickr";
private static final String _ORIGINAL = "original";
private static final String _THUMBNAIL = "thumbnail";
public void addVariables(Map<String, Object> variables)
{
super.addVariables(variables);
variables.put(_FLICKR, new MethodClosure(this, _FLICKR));
variables.put(_ORIGINAL, new MethodClosure(this, _ORIGINAL));
variables.put(_THUMBNAIL, new MethodClosure(this, _THUMBNAIL));
}
public void flickr()
throws FileNotFoundException, NoSuchMethodException
{
invokeMethod(_SCRIPT, _FLICKR, null);
}
public String original(JSONObject photo)
throws FileNotFoundException, NoSuchMethodException
{
Object gstring = invokeMethod(_SCRIPT, _ORIGINAL, new Object[]{ photo });
return gstring.toString();
}
public String thumbnail(JSONObject photo)
throws FileNotFoundException, NoSuchMethodException
{
Object gstring = invokeMethod(_SCRIPT, _THUMBNAIL, new Object[]{ photo });
return gstring.toString();
}
}
|
Note the following two items in this class. The first is the use of the Groovy runtime's MethodClosure class to map method names to method invocations; all this class does is call the named method on the given object and return the result to the calling script. The second thing to note is that Groovy methods that return strings may also return Groovy Strings (or "GStrings"), which are strings that contain embedded variables; we encounter this scenario with the original() and thumbnail() methods. To prevent casting exceptions in cases where the user is expecting a string and gets a GString instead, we use the toString() method on the method return values before passing them on. Calling toString() ensures that all the GString's variables are resolved and the desired string is created.
With the class complete, all you have to do is register it via zero.config. Open the /config/zero.config file in the zero.services.flickr project and add the following lines shown in Listing 11:
Listing 11. Adding Groovy bindings to Zero Core
[/config/bindings/.groovy[]]
zero.services.flickr.FlickrBindings
|
Any application that includes zero.services.flickr as a dependency will now be able to call your Flickr methods from any of their Groovy scripts. In the next section, you'll put these methods to use to create a Flickr-based widget that you can use in your own Web sites.
Photo collages with Groovy and Flickr
Up until now, you have written a lot of code, but you haven't really put it to the test to see if it really does make life easier for authors of Flickr-based services and widgets. Now you'll use your code to create a very common user interface component: the photo collage. Figure 1 shows a screenshot of the type of photo collage we want to create. You have probably seen similar photo collections on blogs and other sites focused on Web 2.0 technology or social networking. Using the Groovy library you wrote in the last two sections, you will create this widget in just a few lines of code.
Figure 1. Screenshot of photo collage
The easiest way to create the collage shown in Figure 1 is to use a Groovy
template that searches for a collection of photos and then builds an HTML table
using the set of photos returned by Flickr. In more concrete terms, you will need to use the flickr() method to find the photo records, the thumbnail() method to build the collage, and the original() method to create hyperlinks from the collage to the original images on Flickr. Listing 12 shows the Groovy code required to build the collage table; you can copy it into a larger template file as part of a complete user interface for your application. If you want to test the widget right away, it is included in the flickr.test sample project, under /public/index.gt. Just run the application and visit http://localhost:8080 in your favorite browser to see the widget in action.
Listing 12. Configuring the Flickr API key
<table border='0' cellpadding='0' cellspacing='10'>
<%
def set = "72157602828759420"; // flickr photo set ID
def length = 4; // size of the photo display box
for (page in 1..length) {
//
// set name-value pairs as specified by flickr API
//
request.flickr.method = "flickr.photosets.getPhotos";
request.flickr.params = [
photoset_id: set,
per_page: length,
page: page,
extras: "original_format"
];
flickr(); // send request to flickr
def response = request.flickr.response[];
println "<tr>";
response.photoset.photo.each() { // build the photo display box
println "<td>";
println "<a href='${original(it)}'><img border='0' src='${thumbnail(it)}'></a>";
println "</td>";
}
println "</tr>";
}
%>
</table>
|
The first two lines of code in Listing 12 provide the Flickr photo set ID and the size of the collage box, respectively; you can change these values to affect what photos are displayed and how large the box is (if you don't have your own photo set to test with, you can use the one in Listing 12, which contains photos of the Project Zero team!). One other point of interest is that you don't get all of the photo data at the same time; you read it in pages so that you can start to render some of the photos while others are still being discovered. If you were to get all of the photos at once and then create the table cells, the initial pause at load time would be longer before the collage finally popped up.
Before you can run this code for yourself, you do need to set your Flickr API key
in your application's zero.config file. This article began by pointing you to the
Flickr site for instructions on obtaining your own API key, and hopefully you have it by now. Listing 13 shows how to set the config.flickr.key property discussed in previous sections using your personal API key:
Listing 13. Configuring the Flickr API key
[/config/flickr]
key=1234567890
|
With your API key in place, you're free to read and write Flickr data using our custom Groovy bindings.
Flickr provides a very useful and flexible API to developers who want to incorporate elements of the site into their own applications, but you can make things even simpler using Groovy scripting and the Project Zero platform. Additionally, the techniques in this article can be applied to other popular sites that combine social networking and data sharing (YouTube, Blogger, and so on.). As long as Web sites continue to expose their shared data with RESTful APIs and portable data formats, you'll always be able to incorporate them into the Zero programming model.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample app with Flickr integration/test files | wa-pz-flickrapi.zip | 8.4KB | HTTP |
Information about download methods
Learn
-
Learn about Flickr's RESTful APIs and obtain a Flickr API key.
-
Learn about Flickr's URL patterns in order to create links to hosted image files.
- Join the
Project Zero community and see what all the buzz is about!
-
Browse the developerWorks Web development zone to find tools, code, and resources to get you started developing Web 2.0 applications today.
-
The developerWorks Ajax resource center is packed with information for all skill levels to help you build Ajax into your applications and dramatically improve your user's Web experience.
Get products and technologies
-
Download Project Zero and start applying the best practices covered in this article.
Discuss
-
Participate in the projectzero.org discussion forum.

Dan Jemiolo is an Advisory Software Engineer on IBM's Project Zero team in Research Triangle Park, NC. He is currently working on reusable components for the Zero platform and its service catalog. His previous work includes the design and development of Apache Muse 2.0 and participation in OASIS Web services standards bodies. Dan came to IBM three years ago after earning his Master of Science degree in Computer Science from Rensselaer Polytechnic Institute.
Comments (Undergoing maintenance)





