I managed to implement form validation with custom constraints, but now I want to do the same thing with JSON data.
How can I apply custom validation rules to a JSON par
The simplest way I can think of would use the filter
method from Reads
.
Let's say we have some User
object that will determine if the user name exists:
object User {
def findByName(name: String): Option[User] = ...
}
You could then construct your Reads
like this:
import play.api.libs.json._
import play.api.libs.functional.syntax._
import play.api.data.validation._
case class ExampleCaseClass(username: String, somethingElse: String)
object ExampleCaseClass {
implicit val exampleReads: Reads[ExampleCaseClass] = (
(JsPath \ "username").read[String].filter(ValidationError("User does not exist."))(findByName(_).isDefined) and
(JsPath \ "somethingElse").read[String]
)(ExampleCaseClass.apply _)
}
Your controller function can be simplified using a json BodyParser
and fold
:
def postNew = Action(parse.json) { implicit request =>
request.body.validate[ExampleCaseClass].fold(
error => BadRequest(JsError.toFlatJson(error)),
obj => {
// Do something with the validated object..
}
)
}
You could also create a separate Reads[String]
that will check if the user exists, and explicitly use that Reads[String]
within your Reads[ExampleCaseClass]
:
val userValidate = Reads.StringReads.filter(ValidationError("User does not exist."))(findByName(_).isDefined)
implicit val exampleReads: Reads[ExampleCaseClass] = (
(JsPath \ "username").read[String](userValidate) and
(JsPath \ "somethingElse").read[String]
)(ExampleCaseClass.apply _)