Play2 - 验证路线的动态部分

Play2 - validation of dynamic part of route(s)

我正在构建一个 API,它采用可变路径参数或路线的动态部分,正如播放文档所指定的那样。

我想验证一下,以便给客户一个正确的回应。

我有以下路线设置

GET /:dynamic/all controller.method(dynamic: String)

该方法的 dynamic 参数在 API 中用于多种方法,因此我想获得某种全局 validation/whitelist 可接受的字符串。 (例如:"hello"/"hi" 会被接受,"noooway" 不会被接受,我会 return 一个 404 not found 作为回应。

我希望我的控制器方法不包含任何验证,这样就可以了:

def method(dynamic: String): Action[AnyContent] = Action.async { _ =>
    //I already know "dynamic" is valid here.
    Future.successful(Ok(Json.toJson(Map("status" -> "OK"))))
}

而不是:(请原谅我的 javaisc-psuedo-code)

def method(dynamic: String): Action[AnyContent] = Action.async { _ =>
    val valid = Helper.validate(dynamic)
    if (!valid) return some result/response else 
    Future.successful(Ok(Json.toJson(Map("status" -> "OK"))))
}

Play 允许您通过不同的方式做到这一点。

1. PathBindable

你可以为任何类型T实现一个PathBindable[T],这样你从请求路径中提取的值就不是简单的String而是一个T .

如果您准备更改 dynamic 的类型(这是有道理的,因为它不应该只是任何字符串,而是一个有效字符串),您可以执行以下操作:

case class Validated(str: String) {
  assert(Helper.validate(str))
}

object Validated {
  implicit val pathBindable = new PathBindable[Validated] {
    val string = implicitly[PathBindable[String]]
    override def bind(key: String, value: String): Either[String, Validated] = 
      string.bind(key, value).                                           // bind as if it were a string
        right.filter(Helper.validate).getOrElse(Left("Invalid input")).  // filter using your validation function, and give error message
        right.map(Validated(_))                                          // encapsulate in your new type

    override def unbind(key: String, value: Validated): String =
      string.unbind(key, value.str)  //unbind as if it were a string
  }
}

请注意,您需要为反向路由实现 unbind(获取给定操作调用的路径)。

现在,您只需将路由器和控制器中的 String 替换为 your.package.Validated

GET    /:dynamic/all    controller.method(dynamic: your.package.Validated)

注意:如果你想使用你的class的简单名称,你需要在你的build.sbt中导入它:

(project in file(".").
  enablePlugins(PlayScala).
  settings(routesImport += "your.package.Validated") 

2。动作组合

您还可以实施一个操作过滤器,以便在需要验证您的输入时使用:

case class ValidatedAction(input: String) extends ActionFilter[Request] {
  override protected def filter[A](request: Request[A]): Future[Option[Result]] = Future.successful{
    if (Helper.validate(input)) None else Some(BadRequest("Invalid input"))
  }
}

def method(dynamic: String) = (Action andThen ValidatedAction(dynamic)).async {
  Future.successful(Ok)
}

只有filter方法returns None才会执行async块内的代码,否则会return指定的Result(这里,BadRequest("Invalid input").