In Rails, I was able to do something similar to the following:
respond_to do |format|
format.xml { ... }
format.json { ... }
end
and the appropriate block would be executed based on what the client supplied in the Accept header.
How can I do the same thing in Play 2.0 (Scala)?
I'd look to do something that looks roughly like this:
try {
Resources.delete(id)
Ok("done")
}
catch {
case e: ClientReportableException =>
?? match {
case "application/xml" => Ok(<error>{e.message}</error>)
case "application/json" => Ok(...)
}
}
Is there a Play idiom for this, or do I just fetch the value of the Accept header from the request?
In Play 2.1 you can write the following:
request match {
case Accepts.Xml() => Ok(<error>{e.message}</error>)
case Accepts.Json() => Ok(…)
}
The cases statements are tried in the order they are written, so if your client sets the HTTP Accept
header to */*
the first one will match (in this example case Accepts.Xml()
). So, you usually want to write the Accepts.Html()
case first because browsers set the Accept
header to */*
.
(Note: you may also be interested in this answer for a similar question in Java)
I have just released a Play! 2.0 module for content negotiation called mimerender (http://github.com/martinblech/play-mimerender).
The idea is that you have to define a mapping from your domain classes to different representations:
val m = mapping(
"text/html" -> { s: String => views.html.index(s) },
"application/xml" -> { s: String => <message>{s}</message> },
"application/json" -> { s: String => toJson(Map("message" -> toJson(s))) },
"text/plain" -> identity[String]_
)
Once you have done that once, you can reuse that mapping throughout all your controllers:
object Application extends Controller {
def index = Action { implicit request =>
m.status(200)("Hello, world!")
}
}
Please note it's a very early release and has only been tested on Play 2.0.4