Project structure

Paths

The recommended way of structuring a Scalatra project is as follows. It’s what you get when you generate a new project using sbt new:

build.sbt               <= dependencies and project config are set in here

project
|_build.properties      <= specifies what version of sbt to use
|_plugins.sbt           <= sbt plugins can be added here

src
|_ main
|  |_ resources
|     |_ logback.xml
|  |_ scala
|  |  |   |_ScalatraBootstrap.scala     <= mount servlets in here
|  |  |_org
|  |      |_ yourdomain
|  |         |_ projectname
|  |            |_ MyScalatraServlet.scala
|  |_ twirl
|  |  |_layouts
|  |    |_default.scala.html
|  |  |_views
|  |    |_hello.scala.html
|  |_ webapp
|     |_ WEB-INF
|        |_ web.xml
|_ test
   |_ scala
      |_ org
         |_ yourdomain
            |_ projectname
               |_ MyScalatraServletTests.scala

The basic structure should be reasonably familiar to anybody who’s seen a Rails, Sinatra, or Padrino application. Your views go in the views folder, layouts (which wrap views) go in the layouts folder.

The Scalatra template project puts your Scala application code into a series of namespaced directories: in the example above, org.yourdomain.projectname. This is entirely optional. The Scala style guide suggests doing it this way, but the language doesn’t do anything to enforce it. If you want to, you can put all of your Scala code in the same directory for easier navigation.

Serving static files

Static files can be served out of the webapp folder, which acts as the ROOT directory. As with any servlet based application, the contents of this directory are all public, with the exception of files in the WEB-INF directory.

An example structure may help in understanding this.

src
|_ main
   |_ scala
   |  |_ Web.scala
   |_ webapp
      |_ WEB-INF
      |  |_ web.xml
      |- stylesheets
      |  |_ default.css
      |- images
         |_ foo.jpg

In this application, the only publicly accessible files will be at stylesheets/default.css and images/foo.jpg. Everything else will be protected by the web application container.

ScalatraServlet vs. ScalatraFilter

There are two base classes you can inherit from in order to make a Scalatra application: ScalatraServlet and ScalatraFilter.

class YourServlet extends ScalatraServlet {
  // your class here
}

vs.

class YourFilter extends ScalatraFilter {
  // your class here
}

The main difference is the default behavior when a route is not found. A ScalatraFilter will delegate to the next filter or servlet in the chain (as configured by web.xml), whereas a ScalatraServlet will return a 404 response.

Another difference is that ScalatraFilter matches routes relative to the WAR’s context path. ScalatraServlet matches routes relative to the servlet path. This allows you to mount multiple servlets in different namespaces in the same WAR.

Use ScalatraFilter if:

  • You are migrating a legacy application inside the same URL space
  • You want to serve static content from the WAR rather than a dedicated web server

Use ScalatraServlet if:

  • You want to match routes with a prefix deeper than the context path.
  • You’re not sure which to use!

Scalatra’s sbt dependencies

Scalatra uses sbt, or sbt, as a build system.

The build.sbt file defines the libraries which your application will depend on, so that sbt can download them for you and build your Scalatra project.

Here’s an example Scalatra build.sbt file:

val ScalatraVersion = "3.0.0"

organization := "com.example"

name := "My Scalatra Web App"

version := "0.1.0-SNAPSHOT"

scalaVersion := "2.13.12"

libraryDependencies ++= Seq(
  "org.scalatra" %% "scalatra-jakarta" % ScalatraVersion,
  "org.scalatra" %% "scalatra-scalatest-jakarta" % ScalatraVersion % "test",
  "ch.qos.logback" % "logback-classic" % "1.4.11" % "runtime",
  "org.eclipse.jetty" % "jetty-webapp" % "11.0.15" % "container",
  "jakarta.servlet" % "jakarta.servlet-api" % "5.0.0" % "provided"
)

enablePlugins(SbtTwirl)
enablePlugins(JettyPlugin)
If you want to add any additional libraries to your project, add them to the libraryDependencies section. Doing that and running sbt again will download the dependency jar libraries and make them available to your application. If you don't know what the dependency details are, you can find out on https://search.maven.org.

The default dependencies are:

scalatra
This is the core Scalatra module, and is required to run the framework.
scalatra-scalatest
This integrates the scalatest testing libraries. It is placed in the test scope, so it's not deployed with your app in production.
logback-classic
Basic logging functionality, courtesy of Logback. It's placed in the runtime scope so it's not bundled with your application. This allows the particular logging implementation (or no logging implementation at all), to be provided at runtime.
jetty-webapp
This is the embedded servlet container used by the web plugin. Your application should be portable to any servlet container supporting at least the 3.0 specification.
javax.servlet
Required for building your app. It is placed in the provided configuration so that it is not bundled with your application. Your servlet container will provide this at deployment time.