These Json serializers in Play with Scala are driving me nuts.
I have read dozens of posts and the tutorials and the documentation. Tried four different ways of implementing Reads / Writes / Format overrides and all to no avail.
So I backed off the custom type and decided to go uber simple:
def suggest = Action(parse.json) {
request =>
request.body.validate[(String, String)].map {
case (suggestion, categories) => Ok("You suggested " + suggestion + " for categories " + categories)
}.recoverTotal {
e => BadRequest(JsError.toFlatJson(e))
}
}
And the error comes back as noted in the subject.
Do I really need to provide a custom Reads / Writes / Format implementation for such a basic body?
A sample input body could be:
{"suggestion":"add generics", "categories":"request;language;updates"}
What simple thing am I missing?
Play! gives you a LOT of ways to work with Json. From the looks of your code, you're going down the Tuple road. Which essentially lets you convert Json into a Tuple. You're also using 'reads' which has the downside that you don't get precise error reporting (ie: if invalid json was passed you would know its invalid... but you wouldn't necessarily know why it was invalid). If you wanted more error handling then you need to start using the 'validate' method (details here: http://www.playframework.com/documentation/2.1.1/ScalaJsonCombinators).
Another way you could go is to map Json to case classes doing something like:
import play.api.libs.json._
case class MyClass(
suggestion: String,
categories: String
)
object MyClass {
implicit val readsMyClass: Reads[MyClass] = new Reads[MyClass] {
def reads(json: JsValue): JsResult[MyClass] = {
for {
suggestion <- (json \ "suggestion").validate[String]
categories <- (json \ "categories").validate[String]
} yield MyClass(json,categories)
}
}
}
This seems like a lot of code so Play 2.1 introduced Json 'Inception' which I have yet to try (http://www.playframework.com/documentation/2.1.1/ScalaJsonInception).
Finally, if you want the Json validation but don't necessary need to marshall/unmarshall case classes, then you can try the 'coast-to-coast' method. This will keep all your json as JsObject types but still give you validation. Sample code here: https://github.com/mandubian/play2-json-demo/blob/master/json-coast-to-coast/app/controllers/Application.scala
Hope this helps.
So I added this:
implicit val rds = (
(__ \ 'suggestion).read[String] and
(__ \ 'categories).read[String]
) tupled
And that seems to work.
Curious, though, is this really the best way to do this? It seems like a LOT of code if you have many many types to serialize / deserialize.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With