所以我有一个看起来像这样的路由文件:
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的任何无效/正确的查询参数。
答案 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
密钥以匹配用户期望的行为。