-
Notifications
You must be signed in to change notification settings - Fork 3
Your First RESTful Application
This framework provides a way to build services that sit inside standard HTTP Servlet containers. Due to the somewhat verbose nature of Java (and to prevent abstracting your code too much from Guice and the other environment), some amount of boilerplate code is necessary. We try to keep this to a minimum.
This page will describe the pieces necessary to build a simple application. Behind the scenes the application will use RESTEasy for the JAX-RS implementation (and, of course, Guice for dependency injection).
To build a project, first add the required modules as dependencies to your project. The following maven dependency XML can be used to pull the libraries in:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
...
<properties>
<stdlib.version>6.0.2</stdlib.version>
</properties>
...
<dependencies>
<dependency>
<groupId>com.peterphi.std.guice</groupId>
<artifactId>stdlib-guice-common</artifactId>
<version>${stdlib.version}</version>
</dependency>
<dependency>
<groupId>com.peterphi.std.guice</groupId>
<artifactId>stdlib-guice-webapp</artifactId>
<version>${stdlib.version}</version>
</dependency>
<dependency>
<groupId>com.peterphi.std</groupId>
<artifactId>stdlib</artifactId>
<version>${stdlib.version}</version>
</dependency>
<!-- Required only if using thymeleaf templating -->
<dependency>
<groupId>com.peterphi.std.guice</groupId>
<artifactId>stdlib-guice-thymeleaf</artifactId>
<version>${stdlib.version}</version>
</dependency>
<!-- Required only if using hibernate -->
<dependency>
<groupId>com.peterphi.std.guice</groupId>
<artifactId>stdlib-guice-hibernate</artifactId>
<version>${stdlib.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
</project>
With this set up, in your webapp project, set up a web.xml file to nominate the framework's filter to handle all HTTP requests (it can be assigned a subfolder if required):
src/main/webapp/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Webapp</display-name>
<filter>
<filter-name>resteasy</filter-name>
<filter-class>com.peterphi.std.guice.web.rest.resteasy.ResteasyDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>resteasy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
This ResteasyDispatcher will try to initialise your service once the webapp is loaded; if this initialisation fails then it will attempt to reinitialise every time the webapp receives an HTTP request. It loads configuration values from service.properties
in the environment (in fact, the property file loading mechanism is a bit more complicated to simplify automated deployment with configuration management tools like Puppet - full details can be found at [The Service Configuration page](Service Configuration)). This property file can contain arbitrary config values which are bound into the Guice environment (using the guice bindProperties
mechanism). A minimal example is shown below.
src/main/resources/service.properties
guice.bootstrap.class=com.me.myservice.guice.MyServiceSetup
The setup class nominated by guice.bootstrap.class
will be loaded as soon as the webapp loads; it should extend AbstractRESTGuiceSetup and implement the addModules
method, which will set up a list of guice Modules to load. The AbstractRESTGuiceSetup base class provides a level of base functionality and core REST services. An example is shown below:
public class MyServiceSetup extends AbstractRESTGuiceSetup
{
@Override
public void addModules(final List<Module> modules, final PropertyFile config)
{
// Nominate our guice module
modules.add(new MyServiceModule());
// Only needed if using Thymeleaf templating
modules.add(new ThymeleafModule());
}
@Override
public void injectorWasCreated(final Injector injector)
{
// No code necessary, provides a hook for lifecycle management (will be removed as a mandatory override in a future version)
}
}
In MyServiceModule we will register our REST services:
public class MyServiceModule extends AbstractModule
{
@Override
protected void configure()
{
RestResourceRegistry.register(MyRestService.class);
}
}
To set up additional services, simply pass them to the RestResourceRegistry.register
call. The code expects that these classes being passed are JAX-RS interfaces. We are not binding an implementation of this service in the Module because we will use the Guice @ImplementedBy
annotation on the interface (however we could certainly bind in this module with bind(MyRestService.class).to(MyRestServiceImpl.class);
).
@Path("/")
@ImplementedBy(MyRestServiceImpl.class)
public interface MyRestService
{
@Path("/")
@GET
@Provides("text/html")
@Doc("Retrieve the index page of this sample service")
public String getIndex();
}
In MyRestServiceImpl
we are running in an environment created by Guice and with method calls controlled by JAX-RS.
public class MyRestServiceImpl implements MyRestService
{
@Inject
Templater templater;
@Override
public String getIndex()
{
return "<html><body><h1>Hello, world!</h1></body></html>";
}
}
We can use a templating engine to return the page by changing the service implementation to:
public class MyRestServiceImpl implements MyRestService
{
@Inject
Templater templater;
@Override
public String getIndex()
{
return templater.template("index").process();
}
}
This will look for a resource called "WEB-INF/template/index.html" in the webapp (which should be written to "src/main/webapp/WEB-INF/template/index.html" in the project structure). For information on how to use Thymeleaf, see their documentation online.
The application we have just built has a special /list
resource, which provides an easy-to-read view of the JAX-RS service interfaces registered as well as their resources.
In this walkthrough we have shown how to build a simple RESTful webapp to expose a simple JAX-RS application which can take advantage of Guice (and optionally Thymeleaf).