# Fully Customized Json Validators for the Play 2 Framework: Explanation and Example

Last updated:

Play's Json Library is, in my opinion, one of the best features of the Play 2 Framework. So much so that I always use it even in apps where I don't use Play at all.

The usual pattern is to create a couple of Case Classes, Readers and Writers to convert your models to/from Json format.

To convert to/from json, you need case classes, readers and writers

You probably also use the validate[T] method to validate a given JsValue against a case class; it is very handy because, in case validation fails, you get the error messages all nicely formatted for you, and you can output that:

def myControllerAction() = Action(parse.json){ request =>
// using parse.json the request body
// will be a JsValue
request.body.validate[MyCaseClass] match{
case success: JsSuccess[MyCaseClass] => {
//process the request
}
}
}


You can add a couple of extra filters to your Readers and Writers to validate each individual field but you are a little bit constrained as to what you can do.

case Class User(name:String,age:Int)

// names must be alphanumeric
def validName(name:String) = name.matches("""(\d|\w|_)+""")

// ages must be positive
def positiveInt(i:Int) => i > 0

object User{
)
}


What if you want to allow users whose name is "john" and have negative age?

To write a fully customized extractor, (for instance, what if you want to allow users whose name is "john" to have negative age?) you can use the following approach, gaining full control of how JsSuccess and JsError are returned, as well as the JsPath that will be indicated as having been the source of that error.

This is perfect to have your model validations return properly structured error messages that can be easily parsed on the frontend.

implicit object UserReads extends Reads[(String, Int)] {
def reads(json: JsValue): JsResult[(String, Int)] = json match {
case jsval: JsValue => {

val maybeName = (jsval \ "name").asOpt[String]
val maybeAge = (jsval \ "age" ).asOpt[Int]

maybeName match {
case Some(name) => {
maybeAge match {
case Some(age) => {
// let's pretend this function is defined somewhere
if(customValidate(user,age))  JsSuccess((name, age))
}
case None => JsError(Seq(JsPath() \ "age" -> Seq(ValidationError("error.path.missing"))))
}
}
case None => JsError(Seq(JsPath() \ "name" -> Seq(ValidationError("error.path.missing"))))
}
}
case _ => JsError(Seq(JsPath() -> Seq(ValidationError("error.expected.jsobject"))))
}
}


## Validate Against a Trait

Suppose you want to verify that some json object is a valid Car. But Car is not a class, but a trait that classes can extend.

It's also possible to validate against a trait; view a working example here

In this example, we have a Car trait and two concrete elements, a case object called MercedesBenz and a case class NormalCar(model: String) and we want to consider some json valid if it validates against either of the two objects.

import play.api.data.validation.ValidationError
import play.api.libs.json._

// the trait and extending classes/objects
sealed trait Car
case object MercedesBenz extends Car
case class NormalCar(model: String) extends Car

// the reader for the trait
// as in the other example, you need to define
def reads(json: JsValue): JsResult[Car] = json match {
// a car can be a single json string
case JsString(s) => if (s == "mercedes") JsSuccess(MercedesBenz) else JsError(Seq(JsPath() -> Seq(ValidationError("error.invalid"))))
// or a json object with a "model" attribute
case JsObject(obj) => obj.get("model") match {
case Some(model) => model match {
case JsString(str) => JsSuccess(NormalCar(str))
case _ => JsError(Seq(JsPath() \ "model" -> Seq(ValidationError("error.expected.jsstring"))))
}
case None => JsError(Seq(JsPath() -> Seq(ValidationError("error.expected.car"))))
}
case _ => JsError(Seq(JsPath() -> Seq(ValidationError("error.invalid"))))
}
}