Groovy: RESTful Services

September 26, 2014 in Java Articles

Written by Ken Kousen


(or The Reason the Internet Was Invented, or Cat Pictures for the Win)

In this article, I'll use Groovy to access a publicly available RESTful web service, parse the downloaded data, and build a GUI to hold the resulting images. The code will demonstrate the Groovy JDK, maps, the collect method, I/O processing, and the builder pattern, all to achieve its ultimate goal: looking at cat pictures.

A Flickering Light In The Darkness

There are many so-called RESTful web services available to the general public. Despite the name, however, most only support GET requests. This isn't terribly surprising, since POST, PUT, and DELETE would require some kind of transaction, and security, and all sorts of protection against the sort of damage reminiscent of YouTube comments[1].

Examples of that sort of services include Open Weather Map (http://openweathermap.org/api), Currency Exchange Rates (http://openexchangerates.org), the Bing[2] Maps REST services (http://msdn.microsoft.com/en-us/library/ff701713.aspx), the Google Maps Geocoder (https://developers.google.com/maps/documentation/geocoding/). Each supports HTTP GET requests only.

NOTE If a RESTful web service only supports GET requests, does that make it a GETful service? If so, and it's also stateless, does that make it a FORGETful web service? Thank you, thank you. Try the veal, and please remember to tip your wait staff.

 

Believe it or not, Flickr used to be the definitive site for image sharing, and some people still use it. Access requires a key, which means you need to register with Yahoo!, another web site that used to matter long, long ago when the web was shiny and new.

Why use it here? It's available, it's free, and, most important of all, it's got cat pictures.

Feeling Groovy

Groovy is one of the new family of languages that compiles to bytecodes for the Java Virtual Machine. It's simpler than Java, yet much more powerful, and has an easy learning curve for existing Java developers. It's cool in its own right, and also forms the basis of interesting projects like Gradle.

Hey, I even wrote a Java/Groovy integration book about it.

Now on to the Groovy. Let's assume you register and receive your special key. Save it in a file called flickr_key.txt, so you can access it this way:

String key = new File('flickr_key.txt').text

Accessing a property (like text here) in Groovy is the same as invoking the corresponding getter or setter method. Here, the Groovy JDK adds the getText method to File, which returns the contents of the file.

The base URL for the web service is:

String endPoint = 'https://api.flickr.com/services/rest?'

I included the “?” because I want to append the generated query string to the end point to get the complete URL.

The Flickr API uses a query string with a lot of parameters. Here I add them to a Groovy map.

def params = [method: 'flickr.photos.search', api_key: key,
    format: 'json', tags: 'cat', nojsoncallback: 1,
    media: 'photos', per_page: 6]

I'm calling the flickr.photos.search method with the api_key. I want JSON data back, but not as a JSON callback, and I want photo data using the cat tag. It's not terribly complicated, but there are a lot of parameters.

The cool part is that a Groovy map like this can be converted to a query string using a very common idiom. Thecollect method applied to a map generates a list by applying a closure to each element of the original list. Therefore I can generate the query string thusly:

def qs = params.collect { k,v -> "$k=$v" }.join('&')

The two-argument closure takes each key/value pair and returns a string where the key equals the value. Then thejoin method applied to the list creates a string whose entries are separated by ampersands.

That means the whole URL is defined by "$endPoint$qs". I can then use the toURL method from the Groovy JDK to convert the string to a URL[3], and the text parameter invokes getText, returning the total response.

I can now use the cool JsonOutput.prettyPrint(txt) method to format the output and write it to a file.

File f = new File('cats.json')
if (f) f.delete()
f << jsonTxt
println JsonOutput.prettyPrint(jsonTxt)

Here's a sample from that output.

{
    "photos": {
        "page": 1,
        "pages": 882777,
        "perpage": 6,
        "total": "5296661",
        "photo": [
            {
                "id": "15077663928",
                "owner": "125421155@N06",
                "secret": "dc605f2671",
                "server": "3837",
                "farm": 4,
                "title": "Mornings with bb kitty",
                "ispublic": 1,
                "isfriend": 0,
                "isfamily": 0
            },
            { ... },
            { ... },
            { ... },
            { ... },
            { ... }
        ]
    },
    "stat": "ok"
}

From JSON to Cat Pictures

Each photo block has the components necessary to assemble the URL to retrieve it, which is way more complicated than it needs to be but is still doable. Here's the code for that part.

def json = new JsonSlurper().parseText(jsonTxt)
def urls = json.photos.photo.collect { p ->
    "http://farm${p.farm}.staticflickr.com/${p.server}/${p.id}_${p.secret}.jpg"
}

The JsonSlurper has a parseText method that converts the received JSON string into a Groovy map. Then walking the map by calling json.photos.photo gets all the photo objects, and the collect block converts each of them into a URL.

All that remains is to access all the photo URLs and populate a simple GUI with them. One simple way to do that is to use Groovy's SwingBuilder class.

new SwingBuilder().edt {
    frame(title:'Cat pictures', visible: true, pack: true,
        defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE,
        layout:new GridLayout(0, 2)) {
        urls[0..5].each { String url ->
            label(icon:new ImageIcon(url.toURL()))
        }
    }
}

The SwingBuilder has an edt method, which builds the UI on the event dispatch thread. The frame “method” instantiates a JFrame with the given title, makes it visible, and packs it as small as possible. The GUI uses aGridLayout to make two columns of equally-spaced elements, each of which is a JLabel that contains an ImageIconwith the individual photo URLs.

The result is a display of the most recent six pictures tagged cat in Flickr, which can result in almost anything[4].

Here's a sample view:

Cat Pictures

NOTE Don't ask me about the monkey. I have no idea what that's about either.

 

So what have we learned?

  1. Groovy maps can be converted to query strings using a closure and the join method
  2. The Groovy JDK adds methods to Java library classes that you wished were there all along
  3. Groovy builders can make Swing programming almost, but not quite, pretty cool
  4. I can haz kitteh pics

The entire script from this article is part of a GitHub repository called IntroGroovy. You'll need to add your own Flickr key, but after that, go for it. Just don't be surprised, apparently, if you get monkeys or tractors mixed in with your cat pictures.

I suppose now I should go and re-implement the whole thing in <a href=”http://lolcode.org”>LOLCODE</a>.


1. Okay, that's a little harsh. Nothing could be as awful as YouTube comments. Or perhaps the correct response to that is, “I didn't know YouTube supported comments.” If that's your answer, I SO wish I was you.

2. Come on, stop laughing. I get it: “if you don't remember what Bing is, just Google it”. Ha ha.

3. What did you expect toURL to convert the string into, a tomato? That would be pretty cool, actually. Now I wish I had that method. Of course, Groovy is an open source project…?

4. Usually it's cats, but once I got a bunch of tractors, which confused me until I realized they were manufactured by Caterpillar.

 

Respectfully submitted by Ken Kousen <[email protected]>, who teaches this stuff

Accelebrate offers private Groovy training for groups.


Written by Ken Kousen

Ken Kousen

Ken Kousen is an independent consultant and trainer specializing in Spring, Hibernate, Groovy, and Grails. He is a regular speaker at conferences and the Author of "Modern Java Recipes" (O'Reilly Media), "Gradle Recipes for Android" (O'Reilly Media), and "Making Java Groovy" (Manning).
  


Learn faster

Our live, instructor-led lectures are far more effective than pre-recorded classes

Satisfaction guarantee

If your team is not 100% satisfied with your training, we do what's necessary to make it right

Learn online from anywhere

Whether you are at home or in the office, we make learning interactive and engaging

Multiple Payment Options

We accept check, ACH/EFT, major credit cards, and most purchase orders



Recent Training Locations

Alabama

Birmingham

Huntsville

Montgomery

Alaska

Anchorage

Arizona

Phoenix

Tucson

Arkansas

Fayetteville

Little Rock

California

Los Angeles

Oakland

Orange County

Sacramento

San Diego

San Francisco

San Jose

Colorado

Boulder

Colorado Springs

Denver

Connecticut

Hartford

DC

Washington

Florida

Fort Lauderdale

Jacksonville

Miami

Orlando

Tampa

Georgia

Atlanta

Augusta

Savannah

Hawaii

Honolulu

Idaho

Boise

Illinois

Chicago

Indiana

Indianapolis

Iowa

Cedar Rapids

Des Moines

Kansas

Wichita

Kentucky

Lexington

Louisville

Louisiana

New Orleans

Maine

Portland

Maryland

Annapolis

Baltimore

Frederick

Hagerstown

Massachusetts

Boston

Cambridge

Springfield

Michigan

Ann Arbor

Detroit

Grand Rapids

Minnesota

Minneapolis

Saint Paul

Mississippi

Jackson

Missouri

Kansas City

St. Louis

Nebraska

Lincoln

Omaha

Nevada

Las Vegas

Reno

New Jersey

Princeton

New Mexico

Albuquerque

New York

Albany

Buffalo

New York City

White Plains

North Carolina

Charlotte

Durham

Raleigh

Ohio

Akron

Canton

Cincinnati

Cleveland

Columbus

Dayton

Oklahoma

Oklahoma City

Tulsa

Oregon

Portland

Pennsylvania

Philadelphia

Pittsburgh

Rhode Island

Providence

South Carolina

Charleston

Columbia

Greenville

Tennessee

Knoxville

Memphis

Nashville

Texas

Austin

Dallas

El Paso

Houston

San Antonio

Utah

Salt Lake City

Virginia

Alexandria

Arlington

Norfolk

Richmond

Washington

Seattle

Tacoma

West Virginia

Charleston

Wisconsin

Madison

Milwaukee

Alberta

Calgary

Edmonton

British Columbia

Vancouver

Manitoba

Winnipeg

Nova Scotia

Halifax

Ontario

Ottawa

Toronto

Quebec

Montreal

Puerto Rico

San Juan