Documentation

You are viewing the documentation for the 2.4.0 release in the 2.4.x series of releases. The latest stable release series is 3.0.x.

§String Interpolating Routing DSL

Play provides a DSL for defining embedded routers called the String Interpolating Routing DSL, or sird for short. This DSL has many uses, including embedding a light weight Play server, providing custom or more advanced routing capabilities to a regular Play application, and mocking REST services for testing.

Sird is based on a string interpolated extractor object. Just as Scala supports interpolating parameters into strings for building strings (and any object for that matter), such as s"Hello $to", the same mechanism can also be used to extract parameters out of strings, for example in case statements.

The DSL lives in the play.api.routing.sird package. Typically, you will want to import this package, as well as a few other packages:

import play.api.mvc._
import play.api.routing._
import play.api.routing.sird._

A simple example of its use is:

val router = Router.from {
  case GET(p"/hello/$to") => Action {
    Results.Ok(s"Hello $to")
  }
}

In this case, the $to parameter in the interpolated path pattern will extract a single path segment for use in the action. The GET extractor extracts requests with the GET method. It takes a RequestHeader and extracts the same RequestHeader parameter, it’s only used as a convenient filter. Other method extractors, including POST, PUT and DELETE are also supported.

Like Play’s compiled router, sird supports matching multi path segment parameters, this is done by postfixing the parameter with *:

val router = Router.from {
  case GET(p"/assets/$file*") =>
    Assets.versioned(path = "/public", file = file)
}

Regular expressions are also supported, by postfixing the parameter with a regular expression in angled brackets:

val router = Router.from {
  case GET(p"/items/$id<[0-9]+>") => Action {
    Results.Ok(s"Item $id")
  }
}

Query parameters can also be extracted, using the ? operator to do further extractions on the request, and using the q extractor:

val router = Router.from {
  case GET(p"/search" ? q"query=$query") => Action {
    Results.Ok(s"Searching for $query")
  }
}

While q extracts a required query parameter as a String, q_? or q_o if using Scala 2.10 extracts an optional query parameter as Option[String]:

val router = Router.from {
  case GET(p"/items" ? q_o"page=$page") => Action {
    val thisPage = page.getOrElse("1")
    Results.Ok(s"Showing page $thisPage")
  }
}

Likewise, q_* or q_s can be used to extract a sequence of multi valued query parameters:

val router = Router.from {
  case GET(p"/items" ? q_s"tag=$tags") => Action {
    val allTags = tags.mkString(", ")
    Results.Ok(s"Showing items tagged: $allTags")
  }
}

Multiple query parameters can be extracted using the & operator:

val router = Router.from {
  case GET(p"/items" ? q_o"page=$page"
    & q_o"per_page=$perPage") => Action {
    val thisPage = page.getOrElse("1")
    val pageLength = perPage.getOrElse("10")

    Results.Ok(s"Showing page $thisPage of length $pageLength")
  }
}

Since sird is just a regular extractor object (built by string interpolation), it can be combined with any other extractor object, including extracting its sub parameters even further. Sird provides some useful extractors for some of the most common types out of the box, namely int, long, float, double and bool:

val router = Router.from {
  case GET(p"/items/${int(id)}") => Action {
    Results.Ok(s"Item $id")
  }
}

In the above, id is of type Int. If the int extractor failed to match, then of course, the whole pattern will fail to match.

Similarly, the same extractors can be used with query string parameters, including multi value and optional query parameters. In the case of optional or multi value query parameters, the match will fail if any of the values present can’t be bound to the type, but no parameters present doesn’t cause the match to fail:

val router = Router.from {
  case GET(p"/items" ? q_o"page=${int(page)}") => Action {
    val thePage = page.getOrElse(1)
    Results.Ok(s"Items page $thePage")
  }
}

To further the point that these are just regular extractor objects, you can see here that you can use all other features of a case statement, including @ syntax and if statements:

val router = Router.from {
  case rh @ GET(p"/items/${idString @ int(id)}" ?
    q"price=${int(price)}")
    if price > 200 =>
    Action {
      Results.Ok(s"Expensive item $id")
    }
}

Next: Javascript routing