简体   繁体   English

如何将验证添加到Play Json中的Reads中?

[英]How do you add validation to a Reads in Play Json?

Let's say I've got a reads that creates an object from JSON with two optional fields: 假设我读取了一个包含两个可选字段的JSON创建对象:

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

I want to check to make sure that the value of field1 is one of the values in the list: 我要检查以确保field1的值是列表中的值之一:

  List("foo", "bar")

I can do that after the fact, by creating a new MyObject and mapping the values through a function to transform them, but I feel like there should be a way to do this more elegantly using JSON transformers or something. 事后,我可以通过创建一个新的MyObject并通过一个函数映射值以转换它们的方式来做到这一点,但我觉得应该有一种方法可以使用JSON转换器或其他方法更优雅地做到这一点。

Ideally, I want the Reads to read the nullable value of field1 and transform it if it is defined, without the need to post-process it. 理想情况下,我希望Reads读取field1的可为空值并在定义后对其进行转换,而无需对其进行后处理。 Is there some way of sneaking a transform in there? 有什么办法可以潜入其中吗?

You can use this approach: 您可以使用这种方法:

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))
  }
}

Usage examples: 用法示例:

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),)

Okay, after doing some more research, I came up with the following: 好吧,在进行了更多研究之后,我想到了以下几点:

In play.api.libs.json.ConstraintReads there is a function called verifying(cond: A => Boolean) that returns a Reads[A] . play.api.libs.json.ConstraintReads有一个称为verifying(cond: A => Boolean)的函数,该函数返回Reads[A] This can be passed as a parameter to JsPath.readNullable[A] like so: 可以将其作为参数传递给JsPath.readNullable[A]如下所示:

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

This will return a JsResponse, either a JsSuccess if "field1" validates, or a JsError if it doesn't validate. 这将返回JsResponse;如果“ field1”有效,则返回JsSuccess;如果无效,则返回JsError。 It actually fails on an invalid input, rather than just ignoring the input. 实际上,它在输入无效时失败,而不仅仅是忽略输入。 That's more like the behaviour I wanted. 那更像是我想要的行为。

There are a number of other constraint functions that perform similar tests on the read value, as well. 还有许多其他约束函数也对读取值执行类似的测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM