如何验证Play Framework中的可选查询参数?

时间:2016-09-05 11:17:45

标签: scala playframework

所以我有一个看起来像这样的路由文件:

GET     /myRes                 controllers.MyController.get(ids: Option[String], elems: Option[String])

一切都很好。用户可以通过以下方式获取内容:

/myRes
/myRes?ids=X
/myRes?elems=Y
/myRes?ids=X&elems=Y

但是,他们也可以通过以下方式查询界面:

/myRes?id=X

这是有问题的,因为在这种情况下,用户获得的结果与查询/myRes时的结果相同,这几乎肯定不是他们预期的结果。这已经给API的开发人员带来了很多混乱/错误。是否有一种优雅的方法来捕获传递给控制器​​的错误/未指定的查询参数,并为此类查询返回硬错误?

编辑:将标题更改为更具描述性的内容。我的问题基本上是验证查询参数以捕获传递给API的任何无效/正确的查询参数。

3 个答案:

答案 0 :(得分:0)

我通常在get方法

上传递它
GET    /getSomething        Controllers.Application.getData()

GET    /getSomething/:id         Controllers.Application.getData(id:Integer)

GET    /getSomething/:id/:name          Controllers.Application.getData(id:Integer, name :String)

答案 1 :(得分:0)

可以在宏注释的帮助下完成,如下所示:

import scala.reflect.macros.whitebox.Context
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.annotation.compileTimeOnly
import play.api.mvc._

@compileTimeOnly("respond 400 bad request in case of unexpected params")
class StrictParams extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro StrictParamsMacro.impl
}

object StrictParamsMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    annottees.map(_.tree).toList match {
      case q"def $name(..$params) = $action { ..$body }" :: Nil =>
        val supportedParamNames = params.map(ab => ab.name.toString).toSet
        c.Expr[Any](
          q"""def $name(..$params) = { req: Request[_] =>
            val unsupportedParams = req.queryString.keySet -- $supportedParamNames
            if (unsupportedParams.nonEmpty) {
              BadRequest(unsupportedParams.mkString("Unsupported Params: ", ", ", ""))
            } else {
              $body
            }
          }"""
        )
    }
  }
}

然后你可以这样注释你的动作方法:

@StrictParams
def get(ids: Option[String], elems: Option[String]) = Action {
  ...
}

答案 2 :(得分:0)

您可以定义QueryStringBindable[A]以将Map个查询字符串参数绑定到类型A的实例。 见the corresponding documentation。 尚未完全探索它,但实现QueryStringBindable[Option[A]]似乎并不太难。

如果您想禁止混淆参数(例如,允许ids但不允许id),您可以检查参数Map中的意外密钥,并在需要时返回错误消息(尽管我建议接受id密钥以匹配用户期望的行为。