Hi,I'm using Json.Reads API to validate a JSONThe API is very good.Some questions:- how do the validation of one field can depend on another fieldFor example:the field 'fieldA' or the field 'fieldB' must exist
- what is the difference between "andKeep" and "keepAnd"?I did not see any practical difference.
- is it possible to transform the value of one field before validating it.For example, I wand to trim() a value before checking for the length.
Do I have to use JSON transformers before using Json.Reads?
--Thanks!Yann
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
it compiles, it is not the problem.The problem is that the string is not trimmed in the second validation.
On Wed, Sep 11, 2013 at 3:01 PM, Yann Simon <yann.s...@gmail.com> wrote:
it compiles, it is not the problem.
The problem is that the string is not trimmed in the second validation.Which is quite normal. And/andKeep/keepAnd compose Reads but doesn't chain them!map is done for this (or andThen but it's limited to "Reads[JsValue] andThen Reads[A])"
(__ \ "field").read[String].map(_.trim).filterNot[String](ValidationError("mandatory"))( _.isEmpty)
2013/9/11 Pascal Voitot Dev <pascal.v...@gmail.com>
On Wed, Sep 11, 2013 at 3:01 PM, Yann Simon <yann.s...@gmail.com> wrote:
it compiles, it is not the problem.
The problem is that the string is not trimmed in the second validation.Which is quite normal. And/andKeep/keepAnd compose Reads but doesn't chain them!map is done for this (or andThen but it's limited to "Reads[JsValue] andThen Reads[A])"
(__ \ "field").read[String].map(_.trim).filterNot[String](ValidationError("mandatory"))( _.isEmpty)OK, I understand.And how can you write the example like that:(__ \ "field").read[String].map(_.trim)(notEmptyString andKeep otherValidation1 andKeep otherValidation2)?Can we use andThen for this?(__ \ "field").read[String].map(_.trim) andThen (notEmptyString andKeep otherValidation1 andKeep otherValidation2)(does not compile)In English:"first, trim the value, then check the trimmed value against some validations"
Hi Pascal, thank you for showing how to trim the values - just what I was looking for.
With no intend to hijack the thread, do you know if something similar can be done with HTML forms?
missed your mail (holidays ;))
On Wed, Sep 4, 2013 at 2:58 PM, Yann Simon <yann.s...@gmail.com> wrote:You can't validate a field depending on another one because validation is always contextual and relative. It's not aware of the rest of the Json tree.
Hi,I'm using Json.Reads API to validate a JSONThe API is very good.Some questions:- how do the validation of one field can depend on another fieldFor example:the field 'fieldA' or the field 'fieldB' must exist
But you can go around it:
For ex:__.json.pick keepAnd((__ \ "fieldA").read[Int] and (__ \ "fieldB").read[Int]).tupled.filter(ValidationError("fieldA should be > fieldB)){ case (a,b) => a > b }
2013/9/11 Pascal Voitot Dev <pascal.v...@gmail.com>
missed your mail (holidays ;))On Wed, Sep 4, 2013 at 2:58 PM, Yann Simon <yann.s...@gmail.com> wrote:You can't validate a field depending on another one because validation is always contextual and relative. It's not aware of the rest of the Json tree.
Hi,I'm using Json.Reads API to validate a JSONThe API is very good.Some questions:- how do the validation of one field can depend on another fieldFor example:the field 'fieldA' or the field 'fieldB' must exist
But you can go around it:
For ex:__.json.pick keepAnd((__ \ "fieldA").read[Int] and (__ \ "fieldB").read[Int]).tupled.filter(ValidationError("fieldA should be > fieldB)){ case (a,b) => a > b }
thanks for the info.My 2 cents: I personally find it quite complex, compared to ad-hoc constraints in forms (http://www.playframework.com/documentation/2.1.x/ScalaForms)It would be quite good to have this simplicity in json.
Hi Pascal,
Thanks for these exemple, very instructive. I hurted the same problem few days ago, and I still don't understand one point, maybe you could enlighten me__.reads[String]res4: play.api.libs.json.Reads[String]scala> __.read[String](Reads.email)res5: play.api.libs.json.Reads[String]__.read[String].map(s => s)res7: play.api.libs.json.Reads[String] // Looks like the same reader as res4 !scala> __.read[String].map(s => s)(Reads.email)<console>:14: error: play.api.libs.json.Reads[String] does not take parameters__.read[String].map(s => s)(Reads.email)Why the map(s => s) make the reader not working as expected?
What I did:def every[A](predicates: (A => Boolean)*) = (a: A) => predicates.foldLeft(true){ case(valid, predicate) => valid && predicate(a) }
val notEmpty = { s: String => !s.isEmpty}def maxLength(max: Int) = { s: String => s.length <= max }val fieldValid = every(notEmpty, maxLength(20))(__ \ "field").read[JsString].map(_.trim).filter(fieldValid)With this solution, it is not possible to return a different validation error message for each validation.
And another question:I am trying the same experience with optional fields:(__ \ "field3").readNullable[JsString].map{ case Some(JsString(s)) => Some(JsString(s.trim)) } andThen (notEmptyString keepAnd maxLengthString(5))That cannot compile:"Cannot prove that Some[play.api.libs.json.JsString] <:< play.api.libs.json.JsValue."
Do you have an idea?
2. we wanted to re-use the validation outside JSON deserialization.At the end, I wrote some little validation helpers:sealed trait ValidationResult[+A]case class ValidationSuccess[+A](result: A) extends ValidationResult[A]case class ValidationError(errorKey: String) extends ValidationResult[Nothing]/*** define a simple validation.* A => ValidationResult[A]*/trait Validation[A] extends (A => ValidationResult[A]) {self =>/*** combine 2 validations in one.* The 2nd validation is checked only the the first one is successful* @param nextStep the next validation*/def and(nextStep: A => ValidationResult[A]): Validation[A] = new Validation[A]{def apply(a: A): ValidationResult[A] = {self.apply(a) match {case e @ ValidationError(_) => ecase ValidationSuccess(value) => nextStep(value)}}}}
I am looking forward to see your next API design!