6
votes

Hello I'm having trouble with a JSON body parser. My problem is the following I have a case class with some optional parameters (Option[T]) and a parameter with a default value which I do not want to be typed as Option[T].

However when parsing a JSON body having the field with the default value omitted I get an error

play.api.libs.JsError
/count error path missing

Here is my controller code :

object MyController extends Controller{


  implicit val itemWrites = Json.writes[Item]
  implicit val itemReads = Json.reads[Item]
  implicit val itemFormats = Json.format[Item]

  def add = DBAction(parse.json){ implicit rs =>

    val item =  rs.request.body.validate[Item]
}

Here is my case class :

case class Item( id:Option[Int], name:String, description:Option[String], count:Int=0)

Any chance I can achieve the same behavior as Option[T] with the default value field?

Thanks

I'm using :

  • Scala 2.10
  • Play Framework 2.2.1
  • Play-Slick plugin 0.5.0.8
2

2 Answers

4
votes

Almost. You can define a default value with an Option like this:

case class Item( description:Option[String] = Some("String"))

If you definitely do not want an option, you can have a look here:

Defaults for missing properties in play 2 JSON formats

1
votes

One workaround would be to write an apply method that takes in the default value of count as an option and handles the construction (can't name it apply as we need an unambiguous name when building our Reads):

object Item{
  def applyOpt(id:Option[Int], name:String, description:Option[String], count:Option[Int]): Item = count.map{c =>
    Item(id, name, description, c)
  }.getOrElse{
    Item(id, name, description)
  }
}

Then you could use readNullable for the default value, which will pass an Option[Int] to applyOpt:

import play.api.libs.json._
import play.api.libs.functional.syntax._


implicit val itemReads: Reads[Item] = (
  (__ \ "id").readNullable[Int] and
  (__ \ "name").read[String] and
  (__ \ "description").readNullable[String] and
  (__ \ "count").readNullable[Int]
)(Item.applyOpt _)

Certainly not ideal, especially if you have several default fields, but a quick workaround that avoids having to deal with macros or reflection.