Quick starting Scalatra or In which I discover Scalatra and sbt
Over the weekend, I was researching various frameworks for implementing a REST API. Although I had already started the implementation using Tornado, I wanted to see what else was out there.
And am I glad I looked. I discovered Scalatra which seems to be exactly what I was looking for; a lightweight, sinatra-esque way to map URLs to actions that easily lends itself to testing. I especially like the uber-readable way the tests are written.
Who wouldn’t want to write tests like this?
// taken from http://github.com/alandipert/step class MyScalatraServletTests extends FunSuite with ShouldMatchers with ScalatraTests { // `MyScalatraServlet` is your app which extends ScalatraServlet route(classOf[MyScalatraServlet], "/*") test("simple get") { get("/path/to/something") { status should equal (200) body should include ("hi!") } } }
I cloned the repo, ran the examples and decided my search had ended.
However, while running the example was easy enough, I wasn’t sure of how to get started with an actual app. It looked especially cryptic since I haven’t ever used maven or sbt. I even considered bailing on scalatra for the well-known shores of tornadoweb. But, since I recently started working with Java at work, I decided to stick it out.
I’m glad I did because sbt is a pleasure to use, especially if you take the time to RTFM.
Anyway, here are the basic steps to help cut down the 0 to 60 time when starting scalatra
Pre-reqs:
Install java, I have java 1.6.
Setup sbt as per these instructions.
Good, now we are ready to start.
Create a new sbt project “HelloScalatra”
mkdir HelloScalatra cd HelloScalatra sbt # fill out the other inputs as you want but make sure you enter 2.8.0 as scala version.
Create a project definition for sbt and save it under project/build. Here’s a barebones one, refer to the docs if you want more info on creating sbt build configs.
// save as project/build/HelloScalatraBuild.scala import sbt._ class HelloScalatraBuild(info: ProjectInfo) extends DefaultWebProject(info) { // scalatra val sonatypeNexusSnapshots = "Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" val sonatypeNexusReleases = "Sonatype Nexus Releases" at "https://oss.sonatype.org/content/repositories/releases" val scalatra = "org.scalatra" %% "scalatra" % "2.0.0-SNAPSHOT" // jetty val jetty6 = "org.mortbay.jetty" % "jetty" % "6.1.22" % "test" val servletApi = "org.mortbay.jetty" % "servlet-api" % "2.5-20081211" % "provided" }
Tell sbt to account for the new dependencies:
#from project root
sbt updateWe have the basic dependencies taken care of, so let’s create our class that will serve requests. Create “HelloScalatra.scala” under src/main/scala/com/helloscalatra with the following content:
// save as src/main/scala/com/helloscalatra/HelloScalatra.scala package com.helloscalatra import org.scalatra._ class HelloScalatra extends ScalatraServlet with UrlSupport { before { contentType = "text/html" } get("/") { <html> <head> <title> My first scalatra webapp</title> </head> <body> <h1> Hello Scalatra </h1> </body> </html> } protected def contextPath = request.getContextPath }
The last thing we need to do is setup web.xml to tell jetty what to do:
// save as src/main/webapp/WEB-INF/web.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> <servlet> <servlet-name>HelloScalatra</servlet-name> <servlet-class>com.helloscalatra.HelloScalatra</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloScalatra</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Great! We should be good to go ![]()
Go to project root and startup the sbt console:
sbt
and start jetty:
>jetty-runTADA!
Navigate over to localhost:8080 to see the webapp in action.