Zach's Blog

Just another WordPress.com weblog

Posts Tagged ‘stringtemplate

XHTML Resource Representations in Jersey using StringTemplate

leave a comment »

Most web services these days use XML and/or JSON as representation formats, mainly because they are simple to create and are easily parseable by other apps.  A less commonly used, but extremely useful format is XHTML.  But wait, that’s for displaying web pages right?  It sure is, but it’s also valid XML.  So if you use XHTML as a representation format, your responses are both viewable to a human in a web browser and parseable by a machine.

Being viewable in a browser is a great way to make your web service self-documenting.  If you use XHTML, instead of reading boring documentation about your web service or using curl to get real XML/JSON responses your users can just navigate around your service using their favorite browser.  The pages look nice so it’s easy to see what information is available for each resource, and they can view the page source to see how to parse it.  XHTML makes linking to other resources easy using the <a> element (remember: hypermedia as the engine of application state!).  XHTML also lets you build forms to show how to use other resources: the forms are easily usable by humans and they also show which HTTP method and parameters to use when making requests from your own app.

While you can use a tool like XStream to serialize your Java objects to XML or JSON, using XHTML will generally require hand-crafting the responses.  What you don’t want to do is build up the entire response in Java:

@GET
@Produces(MediaType.APPLICATION_XHTML_XML)
public String getUser()
{
    User user = ...;
    return "<html><body><dl><dt>First name:</dt><dd>" + user.getFirstName() +
        "</dd><dt>Last name:</dt><dd>" + user.getLastName() +
        "</dd><dt>Email:</dt><dd>" + user.getEmail() +
        "</dd></dl></body></html>";
}

That looks terrible and is going to be very hard to maintain.

What you really need to do is use some sort of template engine.  This will let you put the overall response into a plain text file with certain markers where the data will go.  I’ve found StringTemplate to be one of the best template engines.  You can read all about its great virtues on its own site, but the main idea is that there is basically no logic in the view templates.

To refactor the previous example using StringTemplate, we’d first create a User.st file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>User $user.ID$</title>
  </head>
  <body>
    <dl>
      <dt>First name:</dt> <dd id="firstName">$user.firstName$</dd>
      <dt>Last name:</dt> <dd id="lastName">$user.lastName$</dd>
      <dt>Email:</dt> <dd id="email">$user.email$</dd>
    </dl>
  </body>
</html>

This defines the overall structure of our template, providing places where the user data will get inserted.  Anything between the dollar signs is a StringTemplate expression that the engine evaluates.  So $user.firstName$ results in the getFirstName() method being called on our User object.

Then we would bind a User object to the User.st template and render it:

@GET
@Produces(MediaType.APPLICATION_XHTML_XML)
public String getUser()
{
    User user = ...;
    StringTemplateGroup group = new StringTemplateGroup("someGroup");
    StringTemplate template = group.getInstanceOf("path/to/User");
    template.setAttribute("user", user);
    return template.toString();
}

And this is what will get sent back in the response body:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>User 1234</title>
  </head>
  <body>
    <dl>
      <dt>First name:</dt> <dd id="firstName">Zach</dd>
      <dt>Last name:</dt> <dd id="lastName">Cox</dd>
      <dt>Email:</dt> <dd id="email">zach@something.com</dd>
    </dl>
  </body>
</html>

As you can see, this is just XHTML and is easily parseable.  To extract the first name, you could use an XPath expression like “//dd[@id='firstName']“.  If you view this response in a browser, it’s very easy to quickly see what information this resource provides:

User Template

We could also include links to other resources (maybe the user has a set of recipes at /user/{username}/recipes) or a simple form to change the user’s info (it would do a POST to /users/{username} and have a hidden _method=PUT field to account for browsers not support the PUT request).

Written by Zach Cox

June 26, 2009 at 11:24 am

Posted in Java

Tagged with , ,

Follow

Get every new post delivered to your Inbox.