RESTful on Play! framework
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?
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.
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
}