【问题标题】:Play2 - validation of dynamic part of route(s)Play2 - 验证路线的动态部分
【发布时间】:2017-10-30 14:43:08
【问题描述】:

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

我想对此进行验证,以便为客户提供适当的响应。

我有以下路线设置

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

该方法的 dynamic 参数在 API 中用于多种方法,因此我想获得某种可接受字符串的全局验证/白名单。 (例如:"hello"/"hi" 将被接受,"noooway" 将不被接受,我将返回 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"))))
}

【问题讨论】:

    标签: scala validation routes playframework-2.0


    【解决方案1】:

    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)
    

    注意:如果你想使用你的类的简单名称,你需要在你的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方法返回None时,async块内的代码才会被执行,否则,它将返回指定的Result(这里是BadRequest("Invalid input")

    【讨论】:

    • 啊,是的 - 非常感谢。我完全忘记了使用ActionFilter 来进行这种验证。这对我来说似乎是一个很好的解决方案。还支持PathBindable 解决方案。我很确定我迟早也会需要它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多