如何在Play Json中为Reads添加验证?

时间:2015-08-26 14:36:54

标签: json scala playframework

假设我有一个从JSON创建一个带有两个可选字段的对象的读取:

implicit val rd: Reads[MyObject] = (
  (__ \ "field1").readNullable[String] and
  (__ \ "field2").readNullable[String]
)(MyObject.apply _)

我想检查以确保field1的值是列表中的值之一:

  List("foo", "bar")

事实上,我可以通过创建一个新的MyObject并通过函数映射值来转换它们来做到这一点,但我觉得应该有一种方法可以更优雅地使用JSON转换器或其他东西。

理想情况下,我希望Reads读取field1的可空值,并在定义时对其进行转换,而无需对其进行后处理。有没有办法在那里偷偷改变?

2 个答案:

答案 0 :(得分:2)

您可以使用此方法:

case class MyObject(a: Option[String], b: Option[String])

val allowedValues = Seq("foo", "bar")

implicit val reads: Reads[MyObject] = new Reads[MyObject] { 
  override def reads(json: JsValue): JsResult[MyObject] = { 
    val a = (json \ "a").asOpt[String].filter(allowedValues.contains)
    val b = (json \ "b").asOpt[String]
    JsSuccess(MyObject(a, b))
  }
}

用法示例:

scala> Json.parse(""" { "a": "bar", "b": "whatever"} """).validate[MyObject]
res2: play.api.libs.json.JsResult[MyObject] = JsSuccess(MyObject(Some(bar),Some(whatever)),)

scala> Json.parse(""" { "a": "other", "b": "whatever"} """).validate[MyObject]
res3: play.api.libs.json.JsResult[MyObject] = JsSuccess(MyObject(None,Some(whatever)),)

scala> Json.parse(""" {} """).validate[MyObject]
res4: play.api.libs.json.JsResult[MyObject] = JsSuccess(MyObject(None,None),)

答案 1 :(得分:0)

好的,在做了一些研究后,我想出了以下内容:

play.api.libs.json.ConstraintReads中,有一个名为verifying(cond: A => Boolean)的函数返回Reads[A]。这可以作为参数传递给JsPath.readNullable[A],如下所示:

implicit val rd: Reads[MyObject] = (
  (__ \ "field1").readNullable[String](verifying(allowedValues.contains)) and
  (__ \ "field2").readNullable[String]
)(MyObject.apply _)

这将返回一个JsResponse,如果“field1”验证,则返回JsSuccess;如果不验证,则返回JsError。它实际上失败了输入无效,而不是忽略输入。这更像是我想要的行为。

还有许多其他约束函数也对读取值执行类似的测试。