thundr-rest

A thundr module for simple creation of RESTful services

License

License

GroupId

GroupId

com.threewks.thundr
ArtifactId

ArtifactId

thundr-rest
Last Version

Last Version

1.0.0
Release Date

Release Date

Type

Type

jar
Description

Description

thundr-rest
A thundr module for simple creation of RESTful services
Project Organization

Project Organization

3wks
Source Code Management

Source Code Management

https://github.com/kuhnza/thundr-rest

Download thundr-rest

How to add to project

<!-- https://jarcasting.com/artifacts/com.threewks.thundr/thundr-rest/ -->
<dependency>
    <groupId>com.threewks.thundr</groupId>
    <artifactId>thundr-rest</artifactId>
    <version>1.0.0</version>
</dependency>
// https://jarcasting.com/artifacts/com.threewks.thundr/thundr-rest/
implementation 'com.threewks.thundr:thundr-rest:1.0.0'
// https://jarcasting.com/artifacts/com.threewks.thundr/thundr-rest/
implementation ("com.threewks.thundr:thundr-rest:1.0.0")
'com.threewks.thundr:thundr-rest:jar:1.0.0'
<dependency org="com.threewks.thundr" name="thundr-rest" rev="1.0.0">
  <artifact name="thundr-rest" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.threewks.thundr', module='thundr-rest', version='1.0.0')
)
libraryDependencies += "com.threewks.thundr" % "thundr-rest" % "1.0.0"
[com.threewks.thundr/thundr-rest "1.0.0"]

Dependencies

compile (4)

Group / Artifact Type Version
com.threewks.thundr : thundr jar 1.0.0
com.google.guava : guava jar 16.0.1
org.apache.commons : commons-io jar 1.3.2
net.sf.json-lib : json-lib jar 2.4

provided (1)

Group / Artifact Type Version
javax.servlet : servlet-api jar 2.5

runtime (1)

Group / Artifact Type Version
xom : xom jar 1.1

test (3)

Group / Artifact Type Version
junit : junit jar 4.11
org.hamcrest : hamcrest-all jar 1.3
org.mockito : mockito-all jar 1.9.5

Project Modules

There are no modules declared in this project.

Thundr REST

Thundr REST is a thundr module which makes creating RESTful endpoints within a thundr app relatively painless. thundr-rest neatly separates the data (i.e. your object) being returned from the serialization format (e.g. JSON, XML etc.).

Build Status

Quick start

Add the thundr-rest module to your module.properties. Be sure to add it after your application module like so:

myapp=
com.threewks.thundr.rest=

Then annotate your controller method with @Rest and make sure it returns a RestView like so:

class MyController {
  @Rest
  public RestView get(Integer id) {
    MyModel model = MyModelRepository.get(id);
    return new RestView(model);
  }
}

From here configure your routes as normal.

Serialization formats

Both JSON and XML serialization formats are baked in. The default format when none is specified is JSON.

An example of changing the format via the GET parameter format:

curl http://localhost:8080/myapp/mymodel?format=xml

Formats can also be chosen by including an Accept header in the request with a recognised content type:

GET /myapp/mymodel HTTP/1.1
Host: localhost:8080
Accept: application/xml

Note: JSONP is also supported when the format is json by including the callback parameter.

Why use it?

Lets say you've been given the task of creating up a RESTful API to fetch model objects from your repository by ID. Your endpoint must support JSON and XML formats. In your thundr controllers you would ordinarily return specific view types such as the following:

class MyController {
  public JsonView get(Integer id) {
    MyModel model = MyModelRepository.get(id);
    return new JsonView(model);
  }
}

The obvious issue here is that in order to supply another serialization format (e.g. XML) you must add another method which returns a different View type.

Another potential issue is parameterising the serialization format within a request. In the model above the only real solution is to create separate routes using unique extensions such as .json or .xml to specify the desired format. For example:

MyController.java

class MyController {
  public JsonView getJson(Integer id) {
    MyModel model = MyModelRepository.get(id);
    return new JsonView(model);
  }

  public XmlView getXml(Integer id) {
    MyModel model = MyModelRepository.get(id);
    return new XmlView(model);
  }
}

routes.json

{
  "/mymodel/{id}.json": { "GET": "myapp.controller.MyController.getJson",
  "/mymodel/{id}.xml": { "GET": "myapp.controller.MyController.getXml"
}

This isn't very DRY and also has some shortcomings from a REST standpoint such as:

  1. It doesn't support selecting format via Accept headers (i.e. content negotiation).
  2. Requires checking for a callback parameter on every JSON controller method if you wish to support JSONP.
  3. Exceptions thrown will be rendered using the container's default error templates.

thundr-rest solves this by separating the serialization method from the controller and delegating decisions about which format to render to the underlying RestViewResolver.

How it works

thundr-rest uses main two constructs to address the shortcomings above:

  1. The @Rest annotation, and;
  2. The RestView controller return type.

The @Rest annotation

The @Rest annotation applies the RestActionInterceptor to the controller method. Among other things ActionInterceptors have the ability to catch exceptions thrown in controller methods and do something with them other than simply letting them bubble up to the container's top level exception handler.

In our case the RestActionInterceptor catches exceptions and wraps them in a RestView which will be serialised according to the requested format.

The RestView

The RestView return type conveys no information about how the data should be serialized. You simply set your output object and optionally a HTTP status code and a character encoding and that's all. For example:

new RestView(myData, HttpServletResponse.SC_CREATED, "UTF-8")

The RestViewResolver (which is automatically registered in the thundr injection context when you include the module) then handles all the details about how the data should be serialized and returned to the user.

Serializers

JsonSerializer

The JSON serializer uses the Google GSON library under the hood. This means you can modify the output of the JSON serializer using GSON annotations on your data objects that you insert in to the RestView.

XmlSerializer

The XML serializer uses JAXB to serialize data objects. Similar to the JSON serializer this means that you can modify the serializer by using JAXB annotations on your data objects.

Configuring additonal serializers

In the event that you wish to support additional serialization formats it's easy to add your own. Say you wanted to make your endpoints browsable using HTML. In your application InjectionConfiguration#configure method add the following:

// 1. Get a reference to the view resolver registry from the injectionContext
ViewResolverRegistry viewResolverRegistry = injectionContext.get(ViewResolverRegistry.class);
// 2. Find the RestViewResolver inside the registry by passing a dummy RestView
RestViewResolver restViewResolver = (RestViewResolver) viewResolverRegistry.findViewResolver(new RestView(null));
// 3. Add our custom serializer where HtmlSerializer is a custom class that implements com.threewks.thundr.rest.serializer.Serializer
restViewResolver.addSerializer("text/html", new HtmlSerializer());

Now when the Accept header contains "text/html" or the format parameter is "html" your custom serializer will be used.


thundr-rest - Copyright © 2013 3wks

Versions

Version
1.0.0
0.0.5
0.0.4
0.0.3