Tapestry - Part II: Simple WEB API using Tapestry

Introduction

In this blog we will show you how to extend your Tapestry projects with a simple API. If you have a big project and need complex calls to expose your API functions, then this approach is not for you. Instead, if you have a couple of functions you would like to expose, this is a quick and simple approach to get it done.

Prerequisites

  • This tutorial uses Eclipse with Maven
  • This tutorial builds on previous blog

We consider a setup where a request to \\example.com\api should be replied with a JSON stream, where stream is just fancy way of saying text file. To do this in Java there are a few very good frameworks:

The last one is the easiest complete-integration framework for REST API that will work with Tapestry that we could find. However, if your have very simple requirements even the out-of-the-box frameworks might not be worth configuring. The alternative is to parse arguments during the rendering of a page and respond with XML or JSON. In this example we’ll show how to create an API for our hello-world application, which we build in our previous blog.

Setup

Grab the code hello_tapestry from the previous blog and use it as starting point. Import that project into Eclipse and run it with the following configuration:

run configuration - main

and

run configuration - JRE

If everything is configured properly, you will get the basic hello-world page:

final result

(If you are running a JDK < 1.8 you should also add -XX:MaxPermSize=256M to JRE config.).

If you now enter the url in your browser http://localhost:8080/hello/index/urltest in your browser, you will see the following page

urltest

So any arguments for a page can be added as http://base url/application name/ page/parameter1/parameter2/. This is pretty nice as it already has the general shape you would expect in an API request. We now just need to return JSON instead of HTML.

Adding API Pages

The first step is to create a url or page for our API to work from. For this we add an Api.java and Api.tml files. These files are needed to create a valid page in the Tapestry framework. For now just leave the class empty like so

package nl.uglyduckling.hello.pages;

public class Api {

}

and create a placeholder tml page

<html t:type="layout" title="Hello API"
      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">

	<p>placeholder</p>    
    
</html>

The url http://localhost:8080/hello/api should now result in the placeholder.

placeholderNote that Tapestry is cleaver enough to figure out that you want a page and not to use “api” as a name. However if you now use “api” in the index you will also get the placeholder page and not “hello api”. You can prevent this from happening by checking the text field for correct names. Later, in a different blog, we will show how you can give the user a meaningful warning like: “API is a reserved word in the Hello application and can’t be used as a name.”

Render JSON

The next step is to add some Java code to return JSON text instead of HTML. To do so we must change how the page behaves when it’s activated using the On Activate method. This method returns a stream response. The default is HTML, but you can in principal return any kind. To return JSON stream do the following

StreamResponse onActivate(String userName) 
{
JSONObject json = getResult(userName);
return new TextStreamResponse("application/json", json.toCompactString()); 
}

The Tapestry JSON object can be created as follows

JSONObject getResult(String userName) {
	JSONObject json = new JSONObject();
	json.put("result", "Hello " + userName);
	json.put("version", tapestryVersion);
	json.put("timestamp", new Date().toString());
	return json;
}

Putting everything together we get the API class

package nl.uglyduckling.hello.pages;

import java.util.Date;

import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.util.TextStreamResponse;

public class Api {

	@Property
	@Inject
	@Symbol(SymbolConstants.TAPESTRY_VERSION)
	private String tapestryVersion;

	StreamResponse onActivate(String userName) 
	{
		JSONObject json = getResult(userName);

		return new TextStreamResponse("application/json", json.toCompactString()); 
	}

	private JSONObject getResult(String userName) {
		JSONObject json = new JSONObject();

		json.put("result", "Hello " + userName);
		json.put("version", tapestryVersion);
		json.put("timestamp", new Date().toString());
		return json;
	}
}

Now the url http://localhost:8080/hello/api/fred will result in

api result fred

Code

Code is available here : hello_tapestry_api

Next Steps

The variables should be checked as the input can now contain any string including “api”. This might cause unexpected response. The layout is very basic in example. Later we will show you how to improve the layout using some css and the tml files.

Leave a Reply

Your email address will not be published. Required fields are marked *