Brian Kessler
Brian Kessler

Reputation: 2327

Using Play framework with Scala, how can I humanize a Json Validation message?

Currently have the following implicit Reads val:

 implicit val abridgedProductReads: Reads[Product] =
(
    (JsPath \ "ean"        ).read[Long]   and
    (JsPath \ "name"       ).read[String](minLength[String](5)) and
    (JsPath \ "description").read[Option[String]]
  )(abridgedProductApply _)

and the following for writing validation errors:

      implicit val JsPathWrites          = Writes[JsPath]         (path  => JsString(path.toString))
  implicit val ValidationErrorWrites = Writes[ValidationError](error => JsString(error.message))

  implicit val jsonValidateErrorWrites =
  (
      (JsPath \ "path"  ).write[JsPath] and
      (JsPath \ "errors").write[Seq[ValidationError]]
      tupled
  )

When I submit a name which is too short, I get a Json message like:

[{"path":"/name","errors":"error.minLength"}]

Which I am currently using the following CoffeeScript:

extractError = (message) ->
    errorObj = $.parseJSON(message)
    error = "Unextracted"
    try error = errorObj[0].path + " has error: " + errorObj[0].errors
    catch e then error = message
    error

to present to user as:

/name has error: error.minLength

But I'd like to customize this to make it friendlier (e.g. "Name must be at least five characters") without making any assumption on the client side that this will be the only error presented. In the future, I might add more fields and more validation rules.

Ideally, I'd like Play to be serving user friendly errors, rather than write the CoffeeScript to try to interpret the errors it is receiving.

What would be the best way to do this?

Upvotes: 0

Views: 520

Answers (1)

sarveshseri
sarveshseri

Reputation: 13985

Looks like you want to define your custom validation constraint.

def customMinLength[M]( m: Int )
                      (
                       implicit reads: Reads[M],
                       p: M => scala.collection.TraversableLike[_, M]
                      ) =
  filterNot[M]( ValidationError(
    "Well.... you see... I want to tell you in a very humanized way that your string is shorter than what it should be. For your information its length should be at least " + m.toString,
    m
  ) )( _.size < m )

implicit val abridgedProductReads: Reads[Product] = (
  (JsPath \ "ean"        ).read[Long]   and
  (JsPath \ "name"       ).read[String](customMinLength[String](5)) and
  (JsPath \ "description").read[Option[String]]
)(abridgedProductApply _)

Upvotes: 1

Related Questions