6
votes

I am implementing a web api using the scala 2.0.2 play framework. I would like to extract and validate a number of get parameters. And for this I am using a play "form" which allows me to define optional fields.

Problem: For those optional fields, I need to define a default value if the parameter is not passed. The code is intended to parse correctly these three use cases:

  • /test?top=abc (error, abc is not an integer)
  • /test?top=123 (valid, top is 123)
  • /test (valid, top is 42 (default value))

I have come up with the following code:

def test = Action {
  implicit request =>

  case class CData(top:Int)

  val p = Form(
    mapping(
      "top" -> optional(number)
    )((top) => CData($top.getOrElse(42))) ((cdata:CData) => Some(Some(cdata.top)))
  ).bindFromRequest()

  Ok("all done.")
}

The code works, but it's definitely not elegant. There is a lot of boiler plate going on just to set up a default value for a missing request parameter.

Can anyone suggest a cleaner and more coincise solution?

2

2 Answers

12
votes

in Play 2.1

val p = Form(
    mapping(
      "top" -> default(number,42)
    )(CData.apply)(CData.unapply)
  ).bindFromRequest()

will do what you want.

9
votes

This is router job to validate query string parameters. Just define your parameter in the routes file:

GET /test controllers.Application.test(top: Int ?= 42)

And add top as a parameter to your controller method:

def test(top: Int) = Action {
  // Use top here
  val data = CData(top)
}

Then, Play do all the validating work for you. Note how default value specified using ?= syntax.

You should use forms only for POST requests.

Update:

If you wish to manually check parameters, then you could define helper method:

def getQueryParam(key: String, default: String)(implicit request: RequestHeader) =
  request.queryString.get(key).flatMap(_.headOption).getOrElse(default)

And use it inside your controller methods:

def test = Action { implicit request =>
  val top = getQueryParam("top", "42")
  ...

But by doing this you lose type checking. Of course you can define helpers for each type, i.e. getIntParam, getStringParam and so on, but Play already contains safe router implementation, designed to solve such kind of problems. I advice you to use routing mechanism instead of manual checking.