How to create simple web services with Scalatra

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 15.5, “How to create simple Scala web services with Scalatra.”

Problem

You want to be able to build new web services with Scalatra, a lightweight Scala web framework similar to the Ruby Sinatra library.

Solution

The recommended approach to create a new Scalatra project is to use Giter8, a great tool for building SBT directories for new projects.

Assuming you have Giter8 installed, use the g8 command to create a new project with a Scalatra template:

$ g8 scalatra/scalatra-sbt

organization [com.example]: com.alvinalexander
package [com.example.app]: com.alvinalexander.app
name [My Scalatra Web App]:

scalatra_version [2.2.0]:

servlet_name [MyScalatraServlet]:

scala_version [2.10.0]:

version [0.1.0-SNAPSHOT]:

Template applied in ./my-scalatra-web-app

When Giter8 finishes, move into the new directory it created:

$ cd my-scalatra-web-app

Start SBT in that directory, and then issue the container:start command to start the Jetty server:

$ sbt
> container:start
// a lot of output here ...
[info] Started SelectChannelConnector@0.0.0.0:8080
[success] Total time: 11 s, completed May 13, 2013 4:32:08 PM
Then use the following command to enable continuous compilation:

> ~ ;copy-resources;aux-compile
1. Waiting for source changes... (press enter to interrupt)

That command is nice; it automatically recompiles your source code when it changes. The Jetty server starts on port 8080 by default. If you switch to a browser and go to the URL http://localhost:8080/, you should see some default “Hello, world” output, indicating that Scalatra is running.

The content displayed at this URL comes from a class named MyScalatraServlet, located in the project’s src/main/scala/com/alvinalexander/app directory:

package com.alvinalexander.app

import org.scalatra._
import scalate.ScalateSupport

class MyScalatraServlet extends MyScalatraWebAppStack {
  get("/") {
    <html>
      <body>
        <h1>Hello, world!</h1>
        Say <a href="hello-scalate">hello to Scalate</a>.
      </body>
    </html>
  }
}

That’s the entire servlet. If you’re used to building web services with “heavier” tools, this can be quite a shock.

The get method shown declares that it’s listening to GET requests at the / URI. If you try accessing another URL like http://localhost:8080/foo in your browser, you’ll see output like this in the browser:

Requesting "GET /foo" on servlet "" but only have:

GET /

This is because MyScalatraServlet only has one method, and it’s programmed to listen for a GET request at the / URI.

Add a new service

To demonstrate how the process of adding a new web service works, add a new method that listens to GET requests at the /hello URI. To do this, just add the following method to the servlet:

get("/hello") {
    <p>Hello, world!</p>
}

A few moments after saving this change to MyScalatraServlet, you should see some output in your SBT console. An abridged version of the output looks like this:

[info] Compiling 1 Scala source to target/scala-2.10/classes...
[success] Total time: 8 s
[info] Generating target/scala-2.10/resource_managed/main/rebel.xml.
[info] Compiling Templates in Template Directory:  src/main/webapp/WEB-INF/templates
[success] Total time: 1 s, completed May 28, 2013 1:56:36 PM
2. Waiting for source changes... (press enter to interrupt)

As a result of the ~ aux-compile command, SBT automatically recompiles your source code. Once the code is recompiled, you can go to the http://localhost:8080/hello URL in your browser, where you’ll see the new output.

Congratulations. By following the steps in this recipe, you should have a web service up and running in a matter of minutes.

Discussion

Giter8 is a tool for creating SBT project directory structures based on templates. The template used in this example is just one of many Giter8 templates. Giter8 requires SBT and another tool named Conscript. Despite these requirements, the overall installation process is simple, and is described in Recipe 18.1.

In addition to the MyScalatraServlet class, this list shows some of the most important files in your project:

project/build.scala
project/plugins.sbt
src/main/resources/logback.xml
src/main/scala/com/alvinalexander/app/MyScalatraServlet.scala
src/main/scala/com/alvinalexander/app/MyScalatraWebAppStack.scala
src/main/scala/ScalatraBootstrap.scala
src/main/webapp/WEB-INF/web.xml
src/main/webapp/WEB-INF/templates/layouts/default.jade
src/main/webapp/WEB-INF/templates/views/hello-scalate.jade
src/test/scala/com/alvinalexander/app/MyScalatraServletSpec.scala

Notice that this includes a WEB-INF/web.xml file. If you’re used to the Java web programming world, you’ll find that this is a normal web.xml file, albeit a very small one. Excluding the boilerplate XML, it has only this entry:

<listener>
    <listener-class>org.scalatra.servlet.ScalatraListener</listener-class>
</listener>

You’ll rarely need to edit this file. Recipe 15.6, “Replacing XML Servlet Mappings with Scalatra Mounts” shows one instance where you’ll need to make a small change to it, but that’s it.

As shown in the list of files, an interesting thing about the current Giter8 template for Scalatra is that it uses a project/build.scala file rather than a build.sbt file. You can find all of Scalatra’s dependencies in that file, including the use of tools like the Scalate template engine, specs2, Logback, and Jetty.