播放JSON组合器验证至少指定了一个字段

时间:2015-08-19 09:17:21

标签: json scala playframework-2.4

我有一个场景,将json解析为像这样的案例类

implicit val userRead: Reads[User] = (
    (__ \ "name").read[String] ~
      (__ \ "email").readNullable[String] ~
      (__ \ "phone").readNullable[String] ~
      Reads.pure(None)
    )(User.apply _)

我不需要emailphone,但至少有一个必须可用。

在我的case类定义中,我可以使用

来防止它们都是空的
case class User(name: String, email: Option[String], phone: Option[String], id: Option[Long] = None) {
  require(email.nonEmpty || phone.nonEmpty, "must have at least an email or phone number")
}

但是,执行此操作会生成异常,并且响应500状态,此时由于用户输入而应该是400错误。

我当然可以在我的控制器中手动执行验证,但我想知道是否有更简洁的方法来执行此操作。

2 个答案:

答案 0 :(得分:1)

我只能建议手动编写自己的“读取”

case class A(i: Option[Int], j: Option[Int])

implicit val reads: Reads[A] = new Reads[A] { 
  override def reads(json: JsValue): JsResult[A] = { 
    (for {
      i <- (json \ "i").validateOpt[Int] 
      j <-  (json \ "j").validateOpt[Int]
     } yield A(i, j))
       .filter(JsError("both values can't be empty"))(a ⇒ a.j.nonEmpty || a.i.nonEmpty)  
    } 
  }

并测试:

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


scala> Json.parse("""{} """).validate[A]
res5: play.api.libs.json.JsResult[A] = JsError(List((,List(ValidationError(List(from and to in range can't be both empty),WrappedArray())))))

答案 1 :(得分:0)

您只需在现有代码(.filter(ValidationError("must have at least an email or phone number"))(u => u.email.isDefined || u.phone.isDefined))中添加少量内容即可实现:

case class User(name: String, email: Option[String], phone: Option[String], id: Option[Long] = None)

implicit val userRead: Reads[User] = (
    (__ \ "name").read[String] ~
    (__ \ "email").readNullable[String] ~
    (__ \ "phone").readNullable[String] ~
    Reads.pure(None)
  )(User.apply _).filter(ValidationError("must have at least an email or phone number"))(u => u.email.isDefined || u.phone.isDefined)

现在,证明它可行:

scala> Json.parse("""{ "name" : "foobar"} """).validate[User]
res3: play.api.libs.json.JsResult[User] = JsError(List((,List(ValidationError(List(must have at least an email or phone number),WrappedArray())))))

scala> Json.parse("""{ "name" : "foobar", "email":"test"} """).validate[User]
res4: play.api.libs.json.JsResult[User] = JsSuccess(User(foobar,Some(test),None,None),)

scala> Json.parse("""{ "name" : "foobar", "phone":"test"} """).validate[User]
res5: play.api.libs.json.JsResult[User] = JsSuccess(User(foobar,None,Some(test),None),)