Routes

All web applications need a way to match up the incoming HTTP request with some code to execute on the server. In Scalatra, this is done using routes and actions.

If somebody makes a POST request to your application, at http://www.yourapp.org/articles, you might want to invoke code on the server which will look at the information contained in the incoming request, and use it to create a new Article object. The fact that it’s a POST request, and the request path is /articles, are route information. The code that you execute is the action.

A simple example

In Scalatra, a route is an HTTP method (GET, PUT, POST, or DELETE) paired with a URL matching pattern. If you set up your application using RESTful conventions, your controller might look something like this:

class Articles extends ScalatraServlet {
get("/articles/:id") { // <= this is a route matcher
// this is an action
// this action would show the article which has the specified :id
}
post("/articles") {
// submit/create an article
}
put("/articles/:id") {
// update the article which has the specified :id
}
delete("/articles/:id") {
// delete the article with the specified :id
}
}

Those four example routes, and the actions inside the route blocks, could be the basis of a simple blogging system. The examples just stub out the actions - in a real application, you’d replace the // comments with code to save and retrieve models, and show HTML views.

Named parameters

Route patterns may include named parameters (see below for more on parameter handling):

It’s likely that you’ll want to anchor your regex (e.g. ^/this/that) to make
sure that the matched URL pattern starts at the beginning of the incoming path.
There could be cases where you wouldn’t want this, but they’re hard to imagine.

Rails-like pattern matching

By default, route patterns parsing is based on Sinatra. Rails has a similar,
but not identical, syntax, based on Rack::Mount’s Strexp. The path pattern
parser is resolved implicitly, and may be overridden if you prefer an
alternate syntax:

No path pattern is necessary. A route may consist of solely a condition:

get(isMaintenanceMode) {
<h1>Go away!</h1>
}

Enabling support for PUT and DELETE requests

Scalatra supports all of the HTTP verbs: GET and POST, which are supported by
browser clients, but also PUT and DELETE, which are not.

Many client libraries use non-standard but simple conventions to indicate
that they would like the request to be considered as a PUT or DELETE instead of
a POST: for example, jQuery adds a X-HTTP-METHOD-OVERRIDE header to the request.

Other clients and frameworks often indicate the same thing by adding a
_method=put or _method=delete parameter to a POST body.

Scalatra will look for these conventions on incoming requests and transform
the request method automatically if you add the MethodOverride trait into your
servlet or filter:

Route order

The first matching route is invoked. Routes are matched from the bottom up, i.e. from the bottom of the Scala class defining your servlet to the top.
Watch out! This is the opposite of Sinatra.
Route definitions are executed as part of a Scala constructor; by matching
from the bottom up, routes can be overridden in child classes.

Parameter handling

Incoming HTTP request parameters become available to your actions through
two methods: multiParams and params.

multiParams

a result of merging the standard request params (query
string or post params) with the route parameters extracted from the route
matchers of the current route. The default value for an unknown param is the
empty sequence. Keys return Sequences of values.

params

a special, simplified view of multiParams, containing only the
head element for any known param, and returning the values as Strings.

A params example

As an example, let’s hit a URL with a GET like this:

/articles/52?foo=uno&bar=dos&baz=three&foo=anotherfoo

Look closely: there are two “foo” keys in there.

Assuming there’s a matching route at /articles/:id, we get the following
results inside the action:

GET and POST params, and where’s my JSON?

Both GET and POST params end up in the params bag - you shouldn’t need to read
anything off the request.body.

If you put data directly into the POST body of your request, e.g.
'{"some":"object"}' by itself as a JSON hash, then the JSON itself
becomes an empty key in the params Map.

Filters

Scalatra offers a way for you too hook into the request chain of your
application via before and after filters, which both accept a
block to yield. Filters optionally take a URL pattern to match to the request.

before

The before method will let you pass a block to be evaluated beforeeach
and every route gets processed.

In this example, we’ve set up a before filter to connect using a contrived
MyDb module, and set the contentType for all requests to text/html.

after

The after method lets you pass a block to be evaluated aftereach and
every route gets processed.

after() {
MyDb.disconnect
}

As you can see from this example, we’re asking the MyDB module to
disconnect after the request has been processed.

Pattern matching

Filters optionally take a pattern to be matched against the requested URI
during processing. Here’s a quick example you could use to run a contrived
authenticate! method before accessing any “admin” type requests.

before("/admin/*") {
basicAuth
}
after("/admin/*") {
user.logout
}

Processing order for actions, errors, and filters

Route actions, errors and filters run in the following order:

before filters.

Routes and actions.

If an exception is thrown during the before filter or route actions, it is
passed to the errorHandler function, and its result becomes the action result.

after filters.

The response is rendered.

Handlers

Handlers are top-level methods available in Scalatra to take care of common HTTP
routines.

Redirects

There is a handler for redirection:

get("/"){
redirect("/someplace/else")
}

This will return a redirect response, with HTTP status 302, pointing to
/someplace/else.

Caution:redirect is implemented as a HaltException. You probably don’t
want to catch it in an action.

Although there’s no built-in handler for permanent redirects, if you’d like to
do a 301 permanent redirect, you can do something like this: