0
votes

I am trying to parse a request in Scala

For example, I have this case class

case class User(
  id: Option[Long] = None,
  name: Option[String] = None,
  email: Option[String] = None,
  firstname: Option[String] = None,
  lastname: Option[String] = None,
  isActive: Boolean = true
)

object User {
  implicit val User = Json.format[User]
}

I have two endpoints one for create and one for update

In the create endpoint I only want to send name and email. In the update endpoint the id will be in the path and all the other fields are optional or have a default value.

The controllers receive the requests and parse the data like this

def post: Action[JsValue] = Action.async(parse.json) { implicit request =>
  request.body.validate[User].fold(
  ...
}

The problem is that when the controller validates the json body, it does not add the optional fields with the default values.

I tried adding something like this

object User {
  implicit def jsonFormat = Json.using[Json.WithDefaultValues].format[User]
}

But it did not change anything

2
You need to write a custom JSON parser (in Play JSON a Reads) and put the default values in there. - Lasf
an advise when using Option[type] it will automatically return None if no value or not found so default value None is useless. - Rex
play json doesn't support something like that yet instead you do Custom JSON serializer as first comment . - Rex

2 Answers

1
votes

You can try something like this.

case class User(
  id: Option[Long],
  name: Option[String],
  email: Option[String],
  firstname: Option[String],
  lastname: Option[String],
  isActive: Boolean)

object User {
  val userReads: Reads[User] = Reads {
    case v: JsObject => JsSuccess(User(
      (v \ "id").asOpt[Long],
      (v \ "name").asOpt[String],
      (v \ "email").asOpt[String],
      (v \ "firstname").asOpt[String],
      (v \ "lastname").asOpt[String],
      (v \ "isActive").asOpt[Boolean].getOrElse(true)
    ))

    case _ => JsError(JsonValidationError("Value User is not valid JSON Object."))
  }

  val userWrites: Writes[User] = new Writes[User] {
    override def writes(v: User): JsValue = Json.obj(
      "id" -> v.id,
      "name" -> v.name,
      "email" -> v.email,
      "firstname" -> v.firstname,
      "lastname" -> v.lastname,
      "isActive" -> v.isActive
    )
  }

  implicit val user: Format[User] = Format(userReads, userWrites)
}

Usage:

  val js: JsValue = Json.parse("""{
    "id": 1,
    "firstname": "rex",
    "lastname": "ards"
  }""")

  println(js.as[User])

Let me know if it helps :)..

0
votes

The answer of @Rex works for Play earlier versions, however for Play 2.6

object User {
  implicit def jsonFormat = Json.using[Json.WithDefaultValues].format[User]
}