Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to improve the error message readability returned from JsError.toFlatJson or JsError.toJson in Play framework 2.x?

I have a JSON REST API server built with Play framework v2.3 with scala, and I have controller's action like this for example:

  def register = Action.async(BodyParsers.parse.json) { implicit request => 
      request.body.validate[Register].fold(
        errors => Future.successful(BadRequest(JsError.toFlatJson(errors))),
        register => {
            // do something here if no error...
          }
      )
    }

For simplicity, I handle the validation error with JsError.toFlatJson (note: JsError.toFlatJson is deprecated in newer Play, the replacement is JsError.toJson).

The problem is the json result have cryptic message like:

{"obj.person.email":[{"msg":"error.email","args":[]}]}

Above json indicates the person's email is invalid.

Is there a way to convert the error json result into more readable message?

I don't want the client apps should doing the mapping/conversion of the obj.person.email or error.email. I prefer the server does it before returning the json to the client apps.

like image 650
null Avatar asked Mar 25 '15 12:03

null


1 Answers

Part of your problem can be solved by defining custom errors messages in your class' Reads combinator with orElse:

case Point(x: Int, y: Int)

object Point {
    implicit val pointReads: Reads[Point] = (
        (__ \ "x").read[Int].orElse(Reads(_ => JsError("Could not parse given x value.")))
        (__ \ "y").read[Int].orElse(Reads(_ => JsError("Could not parse given y value.")))
    )(Point.apply _)
}

Given some invalid JSON for this class you'll now get custom error messages for validation problems:

scala> val incorrectJson = Json.parse("""{"y": 1}""")
incorrectJson: play.api.libs.json.JsValue = {"y":1}

scala> val validationResult = incorrectJson.validate[Point]
validationResult: play.api.libs.json.JsResult[playground.Point] = JsError(List((/x,List(ValidationError(List(Could not read the point's x value.),WrappedArray())))))

scala> validationResult.fold(error => { println(JsError.toJson(error)) }, a => { a })
{"obj.x":[{"msg":["Could not read the point's x value."],"args":[]}]}

In order to change the obj.x identifier you'll have to post-process the returned JsValue yourself because it's derived from the implementation of JsPath.

like image 71
Gavin Schulz Avatar answered Nov 02 '22 09:11

Gavin Schulz