scala提取器模式用于复杂验证,但具有良好的错误输出
我正在努力在某个用例中使用提取器模式,在这个用例中它似乎非常强大 我首先输入来自web请求的Map[String,String]。这是对api的searchRequest或countRequest searchRequest有密钥scala提取器模式用于复杂验证,但具有良好的错误输出,scala,scala-2.10,Scala,Scala 2.10,我正在努力在某个用例中使用提取器模式,在这个用例中它似乎非常强大 我首先输入来自web请求的Map[String,String]。这是对api的searchRequest或countRequest searchRequest有密钥 查询(必选) fromDate(可选默认值) toDate(可选默认值) nextToken(可选) maxResults(可选默认值) countRequest有密钥 查询(必选) fromDate(可选默认值) toDate(可选默认值) bucket(可选
- 查询(必选)
- fromDate(可选默认值)
- toDate(可选默认值)
- nextToken(可选)
- maxResults(可选默认值)
- 查询(必选)
- fromDate(可选默认值)
- toDate(可选默认值)
- bucket(可选默认值)
protected case class CommonQueryRequest(
originalQuery: String,
fromDate: DateTime,
toDate: DateTime
)
case class SearchQueryRequest(
commonRequest: CommonQueryRequest,
maxResults: Int,
nextToken: Option[Long])
case class CountRequest(commonRequest: CommonQueryRequest, bucket: String)
如您所见,我正在将字符串转换为DateTimes和Int、Long等。我的问题是,我确实需要针对无效fromDate与无效toDate格式、无效maxResults与无效下一个标记(如果可用)的错误
同时,我需要保留默认值(这取决于是搜索还是计数请求)
当然,随着地图的传入,您可以告诉我搜索与计数,所以在我第一次尝试时,我添加了一个key=“type”,其值为search或count,这样我至少可以在这方面进行匹配
我是否走上了正确的道路?我认为使用匹配可能比我们现有的实现更干净,但我越走这条路,它似乎变得有点丑陋
谢谢,
迪安我建议你看看scalaz.Validation and ValidationNel。这是收集验证错误的极好方法,非常适合输入请求验证 您可以在此处了解有关验证的更多信息:。然而,在我的示例中,我使用scalaz 7.1,它可能与本文中描述的略有不同。然而,主要思想仍然是一样的 以下是您的用例的小示例:
import java.util.NoSuchElementException
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
import scala.util.Try
import scalaz.ValidationNel
import scalaz.syntax.applicative._
import scalaz.syntax.validation._
type Input = Map[String, String]
type Error = String
case class CommonQueryRequest(originalQuery: String,
fromDate: DateTime,
toDate: DateTime)
case class SearchQueryRequest(commonRequest: CommonQueryRequest,
maxResults: Int,
nextToken: Option[Long])
case class CountRequest(commonRequest: CommonQueryRequest, bucket: String)
def stringField(field: String)(input: Input): ValidationNel[Error, String] =
input.get(field) match {
case None => s"Field $field is not defined".failureNel
case Some(value) => value.successNel
}
val dateTimeFormat = DateTimeFormat.fullTime()
def dateTimeField(field: String)(input: Input): ValidationNel[Error, DateTime] =
Try(dateTimeFormat.parseDateTime(input(field))) recover {
case _: NoSuchElementException => DateTime.now()
} match {
case scala.util.Success(dt) => dt.successNel
case scala.util.Failure(err) => err.toString.failureNel
}
def intField(field: String)(input: Input): ValidationNel[Error, Int] =
Try(input(field).toInt) match {
case scala.util.Success(i) => i.successNel
case scala.util.Failure(err) => err.toString.failureNel
}
def countRequest(input: Input): ValidationNel[Error, CountRequest] =
(
stringField ("query") (input) |@|
dateTimeField("fromDate")(input) |@|
dateTimeField("toDate") (input) |@|
stringField ("bucket") (input)
) { (query, from, to, bucket) =>
CountRequest(CommonQueryRequest(query, from, to), bucket)
}
val validCountReq = Map("query" -> "a", "bucket" -> "c")
val badCountReq = Map("fromDate" -> "invalid format", "bucket" -> "c")
println(countRequest(validCountReq))
println(countRequest(badCountReq))
scalactic看起来也很酷,我可能会走这条路(虽然不确定我们是否可以使用该库,但我想我会继续前进,直到有人说不)。+1回答得很好,但出于某种原因,我们的libs中不允许使用scalaz,尽管这至少给了我一些好主意。您可以将验证代码从scalaz复制到您的项目中,并假装它根本不是scalaz。当您的项目中有50%的scalaz时,您可以安全地将其作为依赖项引入;)