将Json Array验证为特定长度的Scala列表

时间:2015-09-07 07:10:19

标签: json scala validation playframework

我用一个案例类表示一个周数据,该案例类包含一个天数据列表,其中包含影响周数据的其他相关参数:

case class WeeksData (
  data: List[DaysData],
  otherStuffRelatedToWeeksParameters: ...
)
case class DaysData (
  stuff: ...
)

我需要从客户端验证输入Json,以便WeeksData数据参数恰好有7个元素。你会怎么建议我这样做?

到目前为止我已经

val weeksDataValidator: Reads[List[DaysData]] = ???
implicit val weeksDataWrites = Json.writes[WeeksData]
implicit val weeksDataReads: Reads[WeeksData] = (
  (JsPath \ "weeksData").read[List[DaysData]](weeksDataValidator))(WeeksData.apply _)

我知道我可以为Int写作:

val intValidator: Reads[Int] = min(0) keepAnd max(999)

那么,如何为数组/列表编写验证器以便修复所需的长度(在本例中为7)?

或者我应该将WeeksData类修改为

case class WeeksData (
  mon: DaysData,
  tue: DaysData,
  wed: DaysData,
  ...
  otherStuffRelatedToWeeksParameters: ...
)

由于

1 个答案:

答案 0 :(得分:0)

为了简短的例子,简化了模型:

case class A(weeks: List[Int])

def listReads[T](length: Int)(implicit anyListReads: Reads[List[T]]) = Reads[List[T]] { js => 
  anyListReads.reads(js).filter(JsError(ValidationError(s"Length of the list must be $length")))(_.size == length)
}

implicit val reads: Reads[A] = ((JsPath \ "weeks").read[List[Int]](listReads[Int](2))).map(A.apply _)

用法(来自REPL):

scala> Json.parse("""{ "weeks": [1, 2] }""").validate[A]
res1: play.api.libs.json.JsResult[A] = JsSuccess(A(List(1, 2)),/weeks)

scala> Json.parse("""{ "weeks": [1] }""").validate[A]
res2: play.api.libs.json.JsResult[A] = JsError(List((/weeks,List(ValidationError(List(error.minLength),WrappedArray(2))))))