在 Play Framework 2.3.x (Scala) 中为案例 class 定义交叉属性 Json 验证器
Defining cross-attribute Json Validators for a case class in Play Framework 2.3.x (Scala)
我知道可以定义我们想要匹配给定 json 的案例 classes(我们使用 JsValue.validate[T]
):
例如:
case class UpdateDashboardModel(id: Long,
maybeName: Option[String],
containers: Option[List[UpdateContainerModel]],
description: Option[String])
然后我们必须编写一个 Reads[T]
来定义如何将一个 json 对象实际转换为我们案例的一个实例 class(并可选择地为个人定义一些自定义验证器属性):
val exists: Reads[Long] =
Reads.LongReads.filter(ValidationError("Dashboard does not exist"))(long => Dashboard.findById(long).isDefined)
implicit val reads: Reads[UpdateDashboardModel] = (
(JsPath \ "id").read[Long](exists) and
(JsPath \ "name").readNullable[String] and
(JsPath \ "containers").readNullable[List[UpdateContainerModel]] and
(JsPath \ "description").readNullable[String]) (UpdateDashboardModel.apply _ )
在此示例中,我 运行 对给定的 id 进行了简单验证 -> 它必须存在于数据库中,否则我必须抛出错误。
问题是,我似乎无法为需要 两个 属性的东西编写验证程序。
例如,我想编写一个简短的验证器,它采用 id and name 属性,因为我想检查该名称是否尚未被另一个仪表板使用(如果它是当前仪表板,则可以)。
有人能想办法做到这一点吗?
提前致谢。
好吧,它不是很漂亮,但我认为这样的事情应该可行...让我们假设 isNameAvailable
是一个确保该名称尚未被另一个仪表板使用的函数,并且 returns 如果名称可用则为真(否则为假)。
import play.api.data.validation.ValidationError
implicit val reads: Reads[UpdateDashboardModel] = (
(JsPath \ "id").read[Long](exists) and
(
(JsPath \ "id").read[Long] and
(JsPath \ "name").readNullable[String]
).tupled.filter(
ValidationError("Name is already in use")
)
{ case (id, name) => isNameAvailable(name, id) }.map(t => t._2) and
(JsPath \ "containers").readNullable[List[UpdateContainerModel]] and
(JsPath \ "description").readNullable[String]) (UpdateDashboardModel.apply _ )
就我个人而言,我发现 tupled.filter
语法有点奇怪,但这就是我能够克服您遇到的问题的方法。
我知道可以定义我们想要匹配给定 json 的案例 classes(我们使用 JsValue.validate[T]
):
例如:
case class UpdateDashboardModel(id: Long,
maybeName: Option[String],
containers: Option[List[UpdateContainerModel]],
description: Option[String])
然后我们必须编写一个 Reads[T]
来定义如何将一个 json 对象实际转换为我们案例的一个实例 class(并可选择地为个人定义一些自定义验证器属性):
val exists: Reads[Long] =
Reads.LongReads.filter(ValidationError("Dashboard does not exist"))(long => Dashboard.findById(long).isDefined)
implicit val reads: Reads[UpdateDashboardModel] = (
(JsPath \ "id").read[Long](exists) and
(JsPath \ "name").readNullable[String] and
(JsPath \ "containers").readNullable[List[UpdateContainerModel]] and
(JsPath \ "description").readNullable[String]) (UpdateDashboardModel.apply _ )
在此示例中,我 运行 对给定的 id 进行了简单验证 -> 它必须存在于数据库中,否则我必须抛出错误。
问题是,我似乎无法为需要 两个 属性的东西编写验证程序。
例如,我想编写一个简短的验证器,它采用 id and name 属性,因为我想检查该名称是否尚未被另一个仪表板使用(如果它是当前仪表板,则可以)。
有人能想办法做到这一点吗?
提前致谢。
好吧,它不是很漂亮,但我认为这样的事情应该可行...让我们假设 isNameAvailable
是一个确保该名称尚未被另一个仪表板使用的函数,并且 returns 如果名称可用则为真(否则为假)。
import play.api.data.validation.ValidationError
implicit val reads: Reads[UpdateDashboardModel] = (
(JsPath \ "id").read[Long](exists) and
(
(JsPath \ "id").read[Long] and
(JsPath \ "name").readNullable[String]
).tupled.filter(
ValidationError("Name is already in use")
)
{ case (id, name) => isNameAvailable(name, id) }.map(t => t._2) and
(JsPath \ "containers").readNullable[List[UpdateContainerModel]] and
(JsPath \ "description").readNullable[String]) (UpdateDashboardModel.apply _ )
就我个人而言,我发现 tupled.filter
语法有点奇怪,但这就是我能够克服您遇到的问题的方法。