Skip to main content

Extend Project Zero and WebSphere sMash's scripting platform with Flickr APIs

Open Flickr APIs let you incorporate elements into your Project Zero apps

Dan Jemiolo (danjemiolo@us.ibm.com), Advisory Software Engineer, IBM, Software Group
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.

Summary:  The Flickr photo sharing service is one of today's most popular Web applications. It provides a robust hosting service with slick social networking capabilities that make uploading, organizing, and finding photos very simple. That's all very cool, but from a developer's perspective, the most interesting thing about Flickr is its public API for reading and writing photo data. You can send API requests over HTTP using any programming language you wish, and many open source projects have sprung up to encapsulate this API for various languages. In this article, you'll learn how to "Zero-ize" the Flickr API by providing a Groovy binding that is easily reusable in your Project Zero applications. When you're done, you'll be able to read and write photo data from your Groovy scripts in just a few lines of code.

Date:  04 Dec 2007
Level:  Intermediate
Activity:  2312 views

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.

Before you get started

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.

Introduction

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.

The Project Zero community
Take a stroll around the Project Zero Web site and see how Project Zero provides a powerful but radically simple development and execution platform for modern Web applications. The active community discusses project development, provides help to developers, and wants to hear your ideas!

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.

Creating sample projects

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.

Invoking Flickr APIs

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:

  1. The URI format for Flickr API calls.
  2. The value of your Flickr API key.
  3. 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.

Creating photo URLs

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.

Creating custom shortcuts

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.

The FlickrBindings class

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
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.

Conclusion

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.



Download

DescriptionNameSizeDownload method
Sample app with Flickr integration/test fileswa-pz-flickrapi.zip8.4KB HTTP

Information about download methods


Resources

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

About the author

Dan Jemiolo

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)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, WebSphere
ArticleID=272822
ArticleTitle=Extend Project Zero and WebSphere sMash's scripting platform with Flickr APIs
publish-date=12042007
author1-email=danjemiolo@us.ibm.com
author1-email-cc=ruterbo@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers