[英]Defining cross-attribute Json Validators for a case class in Play Framework 2.3.x (Scala)
I know it's possible to define Case classes that we want to match some given json against (we use JsValue.validate[T]
): 我知道可以定义要与给定json匹配的Case类(我们使用
JsValue.validate[T]
):
For example: 例如:
case class UpdateDashboardModel(id: Long,
maybeName: Option[String],
containers: Option[List[UpdateContainerModel]],
description: Option[String])
And then we must write a Reads[T]
to define how to actually turn a json object into an instance of our case class (and optionally define a few custom validators for individual attributes): 然后,我们必须编写
Reads[T]
来定义如何将json对象实际转换为我们的case类的实例(并可以选择为各个属性定义一些自定义验证器):
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 _ )
In this example, I run a simple validation for the given id -> it must exist in the database otherwise I have to throw an error. 在此示例中,我对给定的id运行简单的验证->它必须存在于数据库中,否则我将抛出错误。
Problem is, I can't seem to be able to write a validator for something that requires two attributes. 问题是,我似乎无法为需要两个属性的东西编写验证器。
For example, I would like to write a short validator that takes the id and the name attributes because I want to check whether that name is not already in use by another dashboard (if it's the current dashboard, it's ok). 例如,我想编写一个带有id 和 name属性的简短验证器,因为我想检查该名称是否尚未被另一个仪表板使用(如果是当前仪表板,则可以)。
Can anybody think of a way to do this? 有人能想到一种方法吗?
Thanks in advance. 提前致谢。
Well, it's not pretty, but I think something like this should work... Let's assume isNameAvailable
is a function that ensures that the name is not already in use by another dashboard, and returns true if name is available (false otherwise). 好吧,这不是很漂亮,但是我认为类似的事情应该可以工作...假设
isNameAvailable
是一个确保该名称尚未被其他仪表板使用的函数,如果名称可用,则返回true(否则返回false)。
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 _ )
Personally I find the tupled.filter
syntax a little strange, but this is how I have been able to overcome the issue you're having. 我个人觉得
tupled.filter
语法有点奇怪,但这就是我能够解决您遇到的问题的方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.