2

JsValue has two methods

def validate[A](implicit rds: Reads[A]): JsResult[A] - Tries to convert the node into a JsResult[T] (Success or Error).

def validateOpt[A](implicit rds: Reads[A]): JsResult[Option[A]] - I suppose it also does the same thing.

In which situation would validateOpt be used? In my opinion, if JsResult fails then I'll get the error in JsError. So what is the point of having an additional layer of Option in JsSuccess as JsSuccess will always contain value after successful conversion of JsValue into the type A?

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184

1 Answers1

6

validateOpt should be used when a null JSON value or missing JSON path is not considered an error. For example, say we have the following model

case class Person(
  name: String
  employer: Option[String]
)

where employer field is optional as it is perfectly reasonable for a person not to be employed, whilst they always have a name. Then deserialising the following JSON

{
  "name": "Picard"
}

should succeed even though employer path is missing. Thus manually defining Reads[Person] would make use of validateOpt like so

  implicit val personRead: Reads[Person] = Reads { json =>
    for {
      name     <- (json \ "name").validate[String]
      employer <- (json \ "employer").validateOpt[String]
    } yield Person(name, employer)
  }

Also contrast deserialisation of null, for example

  val raw = "null"
  val json = Json.parse(raw)
  println(json.validate[String])
  println(json.validateOpt[String])

should output

JsError(List((,List(JsonValidationError(List(error.expected.jsstring),WrappedArray())))))
JsSuccess(None,)

where we see validateOpt resulted in success.

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • I understand the answer but I am struggling with some other scenario. Could you please look at https://stackoverflow.com/questions/55881709/unable-to-understand-why-validateopt-will-return-none-instead-of-jserror – Manu Chadha Apr 27 '19 at 14:47