我知道可以定义我们要匹配一些给定的JSON的案例类(我们使用JsValue.validate[T]
):
例如:
case class UpdateDashboardModel(id: Long,
maybeName: Option[String],
containers: Option[List[UpdateContainerModel]],
description: Option[String])
然后,我们必须编写一个Reads[T]
来定义如何将JSON对象实际上将JSON对象变成我们的案例类的实例(并且可选为单个属性定义一些自定义验证器):
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 和 name 属性另一个仪表板尚未使用名称(如果是当前仪表板,则可以)。
任何人都可以想到一种方法吗?
预先感谢。
好吧,这不是很漂亮,但是我认为这样的事情应该起作用...让我们假设isNameAvailable
是一个确保名称尚未在另一个仪表板中使用并返回的函数如果名称可用(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 _ )
我个人发现tupled.filter
语法有些奇怪,但这就是我能够克服您所遇到的问题的方式。