Better REST API with JSP

Run REST APIs with JSP.

Accepting API request in JSP

We all love JSP because its simple. It helps us easily modify the server response, without recompilation and re-deployment. But there is no easy way of handling API requests in JSP.

JSP is a view technology, it is used to display server response. API requests are handled by the servlet and forwarded to JSP for API response.

But wait thats what we don't want.

If the servlet handles API requests, changing the Java code wouldn't be as easy as changing the JSP.

Java code in JSP

Does that mean we move our Java code to scriplets in JSP. A lot of developers around the world have done that over last decade. Balusc keeps telling everyone not to do scriplets. And all those who do scriptlets in JSP, have a lot of unmaintainable code. How to avoid Java code in JSP

I'm not saying they don't work but jsp scriptlets get messy and they won't give you a good stack trace when handling errors.

It is hand to identify the line number of the error if written in scriplets.

Disadvantages of scriplets

  1. Maintainability: complex interleaving of code, tags, sections and lack of formatting
  2. Reusability: Scriplets are not packaged classes with methods. They are just a script spread around the jsp page. Making them less usable than jsp tags. Prefer jstl and other tag libraries instead of writing code.
  3. Complexity: Once you write some code in jsp. You will write more of it. And it will grow and become more complex.

Design REST API with JSP?

We want a mechanism that allows us to

  1. Handle API requests efficiently
  2. Write maintainable and reusable code without scriplets for our APIs

The answer is Tag Libraries

JSTL provides a good number of tags for formatting, SQL operations, functions, and logical operations. Maintaining a JSP with tag libraries and JSTL is easier than maintaining java code. Using JSTL to Enhance JSP Functionality. JSP custom tag development allows organizing commonly used operations into tags. This helps us to maintain domain-specific tags and reuse them across the JSP pages.

Here the domain is REST APIs so we need a set of rest specific tag library

Mason

Mason is a jsp tag library that provides a set of tags to handle API requests. Mason is just a tag library. It can work with your existing webapp.

What does mason provide

  1. Set of JSP tags specific to do REST better.
  2. API error handling
  3. Parameter validation tags
  4. JSTL tags to do external api calls. Here's an example
<jsp:directive.page pageEncoding="UTF-8" trimDirectiveWhitespaces="true"/>
<%@taglib uri="mtg-mason.tld" prefix="m" %>

<m:resource>

    <m:request method="GET">
        <m:execute className="com.example.RequestHandler" var="getCustomer" 
                   param="${mtgReq}" output="true"/>
    </m:request>

</m:resource>

If you save this file with customer.jsp, you can access it at

http://localhost:8080/rest/v1.0/customer

You don't need to add the .jsp extension in the url.

Mason provides an execute tag to invoke code. You can return any JAXB compliant object from the class and it will be converted to json/xml depending on the Accept header

package com.example;

import com.metamug.entity.Request;
import com.metamug.entity.Response;
import com.metamug.exec.RequestProcessable;
import com.example.entity.Customer;
import java.util.Map;
import javax.sql.DataSource;

/**
 *
 * @author anishhirlekar
 */
public class RequestHandler implements RequestProcessable {

    @Override
    public Response process(Request request, DataSource ds, Map<String, Object> args) throws Exception {

        Customer customer = new Customer();
        customer.setName("John Doe.");
        customer.setId(8);
        customer.setContact("+1 943 322 4292", "john.doe@gmail.com");

        Response response = new Response();
        // set your model object as payload here
        response.setPayload(customer);
        return response;
    }

}

Maven Dependency

You need to add the following dependency to your pom.xml to run mason tag library.

<dependency>
    <groupId>com.metamug</groupId>
    <artifactId>mason</artifactId>
    <version>3.3</version>
</dependency>

If your project isn't a maven project, you can add mason jar from github releases to your lib folder. There is a mason sample project with all the jar libraries.

web.xml configuration

Add the mason filter in the web.xml so that it can handle the API requests coming to the jsp

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

    <filter>
        <filter-name>Router</filter-name>
        <filter-class>com.metamug.mason.Router</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>Router</filter-name>
        <url-pattern>/rest/*</url-pattern>
    </filter-mapping>

</web-app>

Download the Github Project

We have added a github maven project that demonstrates the above code.

Download Fork