RESTful on Play! framework

JavaRestJerseyRestletPlayframework

Java Problem Overview


We are planning a project primarily serving content to mobile apps, but need to have a website.

My question is whether is makes sense to use Jersey or Restlet to develop REST APIs for our mobile apps, and then use Play! to serve the website.

Or does it make more sense to just use Play! to do it all? If so, how to do REST with Play! framework?

Java Solutions


Solution 1 - Java

As per request, a simple REST-like approach. It works almost the same way Codemwncis' solution works but uses the Accept header for content negotiation. First the routes file:

GET     /user/{id}            Application.user
POST    /user/                Application.createUser
PUT     /user/{id}            Application.updateUser
DELETE  /user/{id}            Application.deleteUser

You don't specify any content type here. Doing so is IMHO only necessary when you want to have "special" URIs for certain resources. Like declaring a route to /users/feed/ to always return in Atom/RSS.

The Application controller looks like this:

public static void createUser(User newUser) {
    newUser.save();
    user(newUser.id);
}

public static void updateUser(Long id, User user) {
    User dbUser = User.findById(id);
    dbUser.updateDetails(user); // some model logic you would write to do a safe merge
    dbUser.save();
    user(id);
}

public static void deleteUser(Long id) {
    User.findById(id).delete();
    renderText("success");
}

public static void user(Long id)  {
    User user = User.findById(id)
    render(user);
}

As you can see I only removed the getUserJSON method and renamed the getUser method. For different content types to work you now have to create several templates. One for each desired content type. For example:

user.xml:

<users>
  <user>
    <name>${user.name}</name>
    . . .
  </user>
</users>

user.json:

{
  "name": "${user.name}",
  "id": "${user.id}",
  . . . 
}

user.html:

<html>...</html>

This approach gives browsers always the HTML view, since all browsers send a text/html content type in their Accept header. All other clients (possibly some JavaScript-based AJAX requests) can define their own desired content type. Using jQuerys ajax() method you could do the following:

$.ajax({
  url: @{Application.user(1)},
  dataType: json,
  success: function(data) {
    . . . 
  }
});

Which should get you the details about User with the ID 1 in JSON format. Play currently supports HTML, JSON and XML natively but you can easily use a different type by either following the official documentation or use the content negotiation module.

If you are using Eclipse for development I suggest use the REST client plugin which lets you test your routes and their corresponding content type.

Solution 2 - Java

This is still a popular question, but the highest voted answers are not up to date with the current version of play. Here's a working REST example with play 2.2.1:

conf/routes:

GET     /users                 controllers.UserController.getUsers
GET     /users/:id             controllers.UserController.getUser(id: Long)
POST    /users                 controllers.UserController.createUser
PUT     /users/:id             controllers.UserController.updateUser(id: Long)
DELETE  /users/:id             controllers.UserController.deleteUser(id: Long)

app/controllers/UserController.java:

public static Result getUsers()
{
    List<User> users = Database.getUsers();
    return ok(Json.toJson(users));
}

public static Result getUser(Long id)
{
    User user = Database.getUser(id);
    return user == null ? notFound() : ok(Json.toJson(user));
}

public static Result createUser()
{
    User newUser = Json.fromJson(request().body().asJson(), User.class);
    User inserted = Database.addUser(newUser);
    return created(Json.toJson(inserted));
}

public static Result updateUser(Long id)
{
    User user = Json.fromJson(request().body().asJson(), User.class);
    User updated = Database.updateUser(id, user);
    return ok(Json.toJson(updated));
}

public static Result deleteUser(Long id)
{
    Database.deleteUser(id);
    return noContent(); // http://stackoverflow.com/a/2342589/1415732
}

Solution 3 - Java

Use Play! to do it all. Writing REST services in Play is very very easy.

Firstly, the routes file makes it straightforward to write routes that conform to the REST approach.

Then, you write your actions, in the controller, for each API method you want to create.

Depending on how you want to return the result (XML, JSON etc), there are a few methods you can use. For example, using the renderJSON method, allows the results to be rendered very easily. If you want to render XML, then you can just do so in the same way as you would build an HTML document in your View.

Here is a neat example.

routes file

GET     /user/{id}            Application.getUser(format:'xml')
GET     /user/{id}/json       Application.getUserJSON
POST    /user/                Application.createUser
PUT     /user/{id}            Application.updateUser
DELETE  /user/{id}            Application.deleteUser

Application file

public static void createUser(User newUser) {
    newUser.save();
    renderText("success");
}

public static void updateUser(Long id, User user) {
    User dbUser = User.findById(id);
    dbUser.updateDetails(user); // some model logic you would write to do a safe merge
    dbUser.save();
    renderText("success");
}

public static void deleteUser(Long id) {
    // first check authority
    User.findById(id).delete();
    renderText("success");
}

public static void getUser(Long id)  {
    User user = User.findById(id)
    renderJSON(user);
}

public static void getUserJSON(Long id) {
    User user = User.findById(id)
    renderJSON(user);
}

getUser.xml file

<user>
   <name>${user.name}</name>
   <dob>${user.dob}</dob>
   .... etc etc
</user>

Solution 4 - Java

Integrating with a JAX-RS implementation is a possible alternative approach to using Play's built-in HTTP routing. For a RESTEasy example, see the RESTEasy Play! module.

This approach makes sense if you are already invested in JAX-RS, or if you need some of the advanced features REST that JAX-RS provides such as content negotiation. If not, it would be simpler to just use Play directly to serve JSON or XML in response to HTTP requests.

Solution 5 - Java

you should have a look at

http://www.lunatech-labs.com/open-source/resteasy-crud-play-module

it's a module for play that automatically build a rest interface, just like the crud module automatically builds an admin area...

Solution 6 - Java

It does seem like this approach is broken in Play version 1.2.3. If you download the source done by @seb and mentioned earlier <https://github.com/sebhoss/play-user-sample>;, the creation of a new user object using POST with a JSON object is no longer possible.

You need to have specific methods for creation done using with json and xml POSTs. Outlined here: https://groups.google.com/forum/#!topic/play-framework/huwtC3YZDlU

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGaryView Question on Stackoverflow
Solution 1 - JavasebView Answer on Stackoverflow
Solution 2 - JavaAldenView Answer on Stackoverflow
Solution 3 - JavaCodemwnciView Answer on Stackoverflow
Solution 4 - JavaPeter HiltonView Answer on Stackoverflow
Solution 5 - JavaopensasView Answer on Stackoverflow
Solution 6 - JavatchristensenView Answer on Stackoverflow