Spring MVC, REST, and HATEOAS
- by SingleShot
I'm struggling with the correct way to implement Spring MVC 3.x RESTful services with HATEOAS. Consider the following constraints:
I don't want my domain entities polluted with web/rest constructs.
I don't want my controllers polluted with view constructs.
I want to support multiple views.
Currently I have a nicely put together MVC app without HATEOAS. Domain entities are pure POJOs without any view or web/rest concepts embedded. For example:
class User {
public String getName() {...}
public String setName(String name) {...}
...
}
My controllers are also simple. They provide routing and status, and delegate to Spring's view resolution framework. Note my application supports JSON, XML, and HTML, yet no domain entities or controllers have embedded view information:
@Controller
@RequestMapping("/users")
class UserController {
@RequestMapping
public ModelAndView getAllUsers() {
List<User> users = userRepository.findAll();
return new ModelAndView("users/index", "users", users);
}
@RequestMapping("/{id}")
public ModelAndView getUser(@PathVariable Long id) {
User user = userRepository.findById(id);
return new ModelAndView("users/show", "user", user);
}
}
So, now my issue - I'm not sure of a clean way to support HATEOAS. Here's an example. Let's say when the client asks for a User in JSON format, it comes out like this:
{
firstName: "John",
lastName: "Smith"
}
Let's also say that when I support HATEOAS, I want the JSON to contain a simple "self" link that the client can then use to refresh the object, delete it, or something else. It might also have a "friends" link indicating how to get the user's list of friends:
{
firstName: "John",
lastName: "Smith",
links: [
{
rel: "self",
ref: "http://myserver/users/1"
},
{
rel: "friends",
ref: "http://myserver/users/1/friends"
}
]
}
Somehow I want to attach links to my object. I feel the right place to do this is in the controller layer as the controllers all know the correct URLs. Additionally, since I support multiple views, I feel like the right thing to do is somehow decorate my domain entities in the controller before they are converted to JSON/XML/whatever in Spring's view resolution framework. One way to do this might be to wrap the POJO in question with a generic Resource class that contains a list of links. Some view tweaking would be required to crunch it into the format I want, but its doable. Unfortunately nested resources could not be wrapped in this way. Other things that come to mind include adding links to the ModelAndView, and then customizing each of Spring's out-of-the-box view resolvers to stuff links into the generated JSON/XML/etc. What I don't want is to be constantly hand-crafting JSON/XML/etc. to accommodate various links as they come and go during the course of development.
Thoughts?