Adding RESTful APIs to Portlets

Benito Gonzalez,
Senior Software Developer

RESTful APIs, while not new, have only recently seen adoption in portlets. Why? They are often used to expose a service. In the case of portlets, there is often a more complete service that the portlet fronts. Another common use is to provide the back end of single page applications. It is this later use that is likely to drive more RESTful APIs in portlets.

Luckily, most portlets use Springframework with it's vast array of complimentary libraries. Springframework Web Services is one such library that directly supports implementing RESTful APIs.

Covering how to create a portlet is beyond the scope of this post, so we assume a refactor of adding a RESTful API.

Let's get started.

Spring 4.x and Jackson

The @RestController was introduced in Spring 4. This is a specialized version of @Controller that expects to return JSON or XML instead of redirecting to a view. Rev Spring to a 4.0 or later version in your pom.xml file.

        <spring.version>4.2.5.RELEASE</spring.version>

For marshalling POJOs into JSON, you will need Jackson. Make sure you have the dependencies in your pom.xml.

        <jackson.version>2.7.3</jackson.version>
        ...
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>

DispatcherServlet

In many portlets, there is no need for Dispather Servtlet in web.xml. The portal handles requests and dispatches them through the portlet interface. For a RESTful API, a servlet is needed in the portlet to handle direct requests. The following need to be included in web.xml:

        <servlet>
            <servlet-name>spring</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>2</load-on-startup>
        </servlet>
...
        <servlet-mapping>
            <servlet-name>spring</servlet-name>
            <url-pattern>/v1/mail/*</url-pattern>
        </servlet-mapping>

Servlet Context

If the above was needed, then the supporting context file is also likely needed. Spring takes the name, spring, and looks for a context file like WEB-INF/spring-servlet.xml. If the servlet was named api, then Spring would look for WEB-INF/api-servlet.xml. In the appropriate file, you should have the following:

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

        <context:annotation-config/>

        <bean class="... TestRestController"/>

        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" id="handlerMapping">
            <property name="alwaysUseFullPath" value="true"/>
        </bean>

        <mvc:annotation-driven/>

    </beans>

This will cause Spring to scan the specified bean/class for the controller annotations in our Java code.

Java REST Controller

Finally, it is time to work on the Java controller. We will create a simple test controller. Create a Java file in your portlet project. Location is not important. Spring is going to scan all the Java classes for the controller annotations. In the source file, include the following:

    package ...

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;

    @RestController
    @ReqestMapping("/v1/api")
    public final class TestRestController {

        @RequestMapping("test")
        public Message test(@RequestParam(value="name", defaultValue = "Me") String name) {
            Message msg = new Message();
            msg.setText("testing " + name);
            return msg;
        }

        @XmlRootElement
        public final static class Message {
            String text;

            @XmlElement
            public String getText() {return text;}

            public void setText(String text) { this.text = text; }
        }

    }

That's it for our code! In this test we are using a static inner class to demonstrate the marshaling of a POJO to JSON. Note the JAXB XML annotations. We will return to them when we test.

Testing It Out

Now deploy and test that the API responds as expected. Assuming the portlet is named MyPortlet and deployed to a local servlet container on port 8080 (e.g. Tomcat), you can check the API with the following URL:

 

    http://localhost:8080/MyPortlet/v1/api/test

 

This should display {"text":"testing me"}.

If that worked, try the following:

 

    http://localhost:8080/MyPortlet/v1/api/test?name=you

 

See the use of the parameter?

The default content type returned by the REST service is application/json. You can add a ".json" to the URL to get the same results.

What about ...

 

    http://localhost:8080/MyPortlet/v1/api/test.xml

 

    <message>
        <text>testing Me</text>
    </message>

Thanks to JAXB and the XML annotations, the response is now in XML!

Benito Gonzalez

Benito Gonzalez

Senior Software Developer
Benito Gonzalez is a Software Architect at Unicon, Inc., a leading provider of education technology consulting and digital services. Benito joined Unicon in 2015 and has over 25 years of professional IT experience. He holds a Bachelor of Science degree in Computer Science. Benito has been active in web development since 1999. Benito spent six years prior to joining Unicon as the Enterprise Web Applications Manager at University of California, Merced, where he managed several campus-wide services, such as CAS, uPortal and Sakai CLE.
Top