Chapter 6. Building web applications in functional style

This chapter covers

  • Building Scala projects with SBT (Simple Build Tool)
  • Introduction to the Scalaz HTTP module
  • Creating a web application in Scala called weKanban

This second part of the book switches focus to more real-world applications of the Scala programming language, and what could be more practical than building a web application in Scala? There are already web frameworks like Lift (http://liftweb.net) and Playframework (www.playframework.org) that Scala developers can use to build web applications. But this chapter introduces you to an interesting library called Scalaz (http://code.google.com/p/scalaz/). (The source code for Scalaz is hosted at http://github.com/scalaz/scalaz.) This simple library will allow you to focus on building a web application in functional style without worrying about the complexity of a full-stack web framework.

There are quite a few similarities between web applications and functional programming. Think of a web application as a collection of functions that takes an HTTP request and produces an HTTP response. Each URL endpoint is mapped to a function that knows how to handle the request. Because you’re building in functional programming style, the web application state (like user sessions) is explicitly specified in each request. The benefit of thinking in this style is that you can build web applications by composing functions or using higher-order combinators. Frameworks built using this strategy usually are stateless and scalable. In this chapter you’ll learn to use functional programming to build a web application.

You’re also quickly reaching a point where you have to start thinking about a build tool to compile and run Scala applications. Even though you could use almost any existing build tool for Scala applications, the de facto standard is SBT (introduced in chapter 1). This chapter will explore this tool and will show you how to configure and build Scala web projects using SBT. Get yourself a nice coffee and a sandwich before diving in to build your first web application in Scala.

6.1. Building weKanban: a simple web-based Kanban board

You’re going to build a simple web-based Kanban[1] board. The word Kanban is derived from the Japanese language and it means “card-signal.” In Kanban, the card-signaling is used to trigger action for new work. This mechanism is also known as a pull system because new work is pulled in only when there’s available capacity to handle the work.

1 “Kanban,” http://en.wikipedia.org/wiki/Kanban.

The essential idea behind the Kanban system is limiting the work in progress.[2] Stop starting and start finishing is an important mantra aimed at reducing the amount of work in progress and, ultimately, waste. Thanks to Agile software development methodology, the card wall (or notice board or whiteboard with index cards) has become popular, and you’ll use it to visualize the work in progress for user stories and backlog, and to determine who is working on what. But card walls aren’t necessarily a Kanban system unless there’s an explicit limit on work in progress and a signaling system to pull new work.

2 David J. Anderson, Kanban: Successful Evolutionary Change for Your Technology Business, Blue Hole Press, April 7, 2010.

The Kanban board you’ll build (figure 6.1) has this limit in place for the ready, dev, and test phases. In figure 6.1 the number 3 at the top of the ready phase means that you can’t have more than three stories in the ready state; similarly, you can have 2 stories at the most in the dev phase.

Figure 6.1. Kanban board with four phases.

According to figure 6.1, you can move one more story from the ready phase to the dev phase. A pair of developers looking for new work can select a card from the ready phase and move that card to the dev phase. Once the development work is done, the card moves to the test phase where, in this stage, a tester, business analyst, or other members of the team will verify the work against the user story. When the story is approved or verified, it’s moved to the deploy phase, which means it’s ready for production deployment. This is how a card (work) flows through the system.

You’ll name your Kanban application weKanban, and here are the user stories you’ll implement:

As a customer, I want to create a new user story so I can add stories to the ready phase.

As a developer, I want to move cards (stories) from one phase to another so I can signal progress.

In this chapter and the next, you’ll implement these stories and build a full, working web application in Scala. But first you’ll learn about SBT so you can compile and test your application.

6.2. Building Scala applications using Simple Build Tool

SBT[3] is a build tool for Scala and Java projects. It is entirely written in Scala, and you can write Scala code or use SBT’s built-in DSL to configure your project and its dependencies. The benefit of using Scala for configuring your build definition is that you have the full power and type-safety of the language. This situation is quite different from Maven (http://maven.apache.org) or Ant (http://ant.apache.org), where the project build configuration is written in XML.

3 Install, features, and getting started, SBT 0.12.1, http://scala-sbt.org.

SBT provides support for continuous compilation and testing, meaning SBT will compile and run your tests automatically whenever there’s a change in project source files. You’re going to use this feature to your advantage to autodeploy changes to the web server.

The following few sections introduce you to SBT, starting with installing to your environment. Then you’ll explore the basics of SBT and learn how SBT projects are structured. I focus on creating and building web projects with SBT for your weKanban application. Because SBT is configured using Scala code, you’ll see examples of how that works and gradually build a project definition for your weKanban application, including creating new tasks. Let’s start with setting up SBT for your environment. Follow along!

6.2.1. Setting up SBT

The easiest way to get up and running with SBT is to download[4] the latest version of the SBT .jar file from the website and create the script file, depending upon your OS.

4 SBT download, http://mng.bz/1E7x.

Unix

Create a file called sbt with the following line:

java -Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled
-XX:MaxPermSize=384M -jar `dirname $0`/sbt-launch.jar "$@"

To run SBT from any directory, put the sbt file in the ~/bin folder along with the downloaded .jar file and configure it in the PATH variable. You might have to set the permission to make the file executable using the following command:

Chmod u+x ~/bin/sbt

The CMSClassUnloadingEnabled flag allows the garbage collector (GC) to remove classes that are no longer used from PermGen memory.

Windows

Create a batch file, sbt.bat, with the following lines:

Set SCRIPT_DIR=%~dp0
Java –Xmx512M –jar "%SCRIPT_DIR%sbt-launch.jar" %*

Put the downloaded .jar file and the batch file in the same directory and alter your path so that it’s accessible from any directory.

Mac

For Mac users it’s simple—use either Homebrew or MacPorts to install SBT:

brew install sbt

sudo port install sbt

You don’t have to download a .jar file. If you’re behind an HTTP proxy, you can set that by passing the http.proxyUser and http.proxyPassword properties:

java -Dhttp.proxyUser=username -Dhttp.proxyPassword=mypassword -Xmx512M
    -jar `dirname $0`/sbt-launch.jar "$@"

SBT will pick up the HTTP proxy settings from the http.proxy environment variable. SBT needs access to the internet to download the dependencies from external repositories (more on this in the next section). It’s also at times useful to have the encoding of the terminal set to UTF-8 so that you can work with Unicode method names inside the SBT console (REPL).

To verify that your setup is working properly, type sbt in the command prompt and click Enter. If the setup is working, you’ll see the sbt prompt and something similar to the following line as an output:

[info] Set current project to default-afcdbe (in build file:/Users/n/mybook/
     code/chap06/test/)
>

You can start SBT on any empty folder and you don’t need a project structure to get up and running. In this case SBT created a new project called default-afcdbe under the /Users/n/mybook/code/chap06/test/ folder. In your case the project name and the location could be different. To make sure you’re in an SBT prompt, type in the following command to print the version of SBT you’re using:

> sbt-version
[info] 0.12.0

If you see an output, you know your installation is working correctly. SBT 0.7+ versions used to prompt you to create a New Project if one is not already defined. The definition of the project has changed in SBT 0.11+ so that any folder can be a root folder of the project. The benefit of the new approach is that now you can use SBT to build your Scala scripts without worrying about creating full-blown projects. Any folder with one Scala file can be treated as an SBT project. For now type exit to exit the SBT prompt. The next section explores the project structure and fundamentals of SBT.

6.2.2. Understanding the basics of SBT

It’s important to understand the basics of SBT before you start using it. SBT is a feature-rich build tool, and I can’t cover all its possible features. The goal of this section is make you aware of the basics so you can set up your Scala projects to use SBT. For more details on SBT, go to http://scala-sbt.org.

There are three ways to configure projects with SBT:

  • Use the .sbt file to configure the build definition of the project.
  • Use the .scala file for the build definition. This allows you to write Scala code to configure the build.
  • Use both .sbt and .scala files to configure the project.

The first option is the easiest way to get started with SBT. It’s a DSL to declare the build definition for the project. For a more complex build, you need to use .scala build files. That’s why it’s common to see both .sbt and .scala build files in typical Scala projects. Later I’ll explain when to use the .scala version of the build file. For now let’s start your journey with SBT with a simple build file.

Building the First SBT Build File

SBT works purely by convention. It looks for Scala source files in the base directory, inside the src/main/scala and src/main/java folders. The minimum requirement for a valid SBT project is a source file under the base directory. Let’s create a simple Hello world! program to play with SBT. The following snippet creates an empty folder called test and creates a hello world application:

$ mkdir test
$ cd test
$ echo 'object HW { def main(args: Array[String]): Unit = println("Hello
     world!") }' > hw.scala

Now fire up SBT to compile and run the application. Once in the SBT prompt, you can invoke the compile task to compile the source code. And once the source code is compiled, invoke the run task to run the hello world example. You should get output like the following:

> run
[info] Running HW
Hello world!
[success] Total time: 0 s, completed ...

SBT is smart enough to pick the source file from the base directory of the project, and the run task looks for classes in the classpath that define the main method. All the compiled classes are generated under the target directory. To see all the available SBT tasks, invoke the tasks task from the SBT prompt.

By default, SBT will use the Scala version that shipped with SBT to compile the source code of the project. In this case it is 2.10.2.

> scala-version
[info] 2.10.0
[info] Reapplying settings ...
[info] Set current project to default-afcdbe...

You can easily change the default Scala version to some other version by using the set command. The following commands will change the name and version of the project from within the SBT prompt:

> set name := "Testing SBT"
[info] Reapplying settings...
[info] Set current project to Testing SBT
> set version := "1.0"
[info] Reapplying settings...
[info] Set current project to Testing SBT

Each time you call set, it changes the settings of the project. To learn more about SBT settings, check the “Settings in SBT” sidebar; but in short: scalaVersion, name, and version are predefined keys in SBT that contain String type values associated with the build. The type of each of these keys is SettingKey[T], where T is the type of the value it can accept.

Settings in SBT

Settings are the way SBT stores the build definition. A build definition defines a list of Setting[T] where Setting[T] is a transformation affecting SBT’s key value pair. A Setting is created assigning value to SettingKey. There are three kinds of keys in the SBT:

  • SettingKey[T] is a key with a value computed only once. Examples are name or scalaVersion.
  • TaskKey[T] is a key with a value that has to be recomputed each time. TaskKey is used to create tasks. Examples are compile and package.
  • InputTask[T] is a task key which takes command-line arguments as input.

All predefined keys are defined in the sbt.Keys object.

To persist these changes in the settings, invoke the session save task from the SBT prompt. This will take the settings changes and save them into the build.sbt file under the base directory:

$ cat build.sbt

scalaVersion := "2.10.0"

name := "Testing SBT"

version := "1.0"
$

Congratulations! You’ve created your first SBT build configuration file. Each line in the build file is an expression, and each needs to be separated by a blank line—otherwise, SBT can’t distinguish them. The expressions in the build file create a list of settings for SBT. A build definition in SBT is nothing but a list of settings represented by Setting[T] (refer to the sidebar “Settings in SBT”). When all the settings are evaluated, SBT creates an immutable Map of key value pairs. And that’s your build definition. The following expression will create a Setting[String] setting:

name := "Testing SBT"

Here := is a method call on a key called name. You could have written that preceding line like this as well:

name.:=("Testing SBT")

All the available keys are defined in the sbt.Keys object, and it’s automatically imported for you in the build.sbt file. You can also specify import statements inside build.sbt, but they should go at the top of the file. The build.sbt file is a great place to configure build settings. For example, you can enable unchecked and deprecation warnings for the Scala compiler by adding -unchecked and -deprecation values to the scalacOptions key:

scalacOptions ++= Seq("-unchecked", "-deprecation")

The ++= method lets you append multiple values to scalacOptions. One more important thing to note here is that SBT build files are type-safe. The type of key determines the type of the value. For example, organizationHomePage lets you set the homepage of the organization, and it expects Option[URL] as a value:

> set organizationHomepage := "22"
<set>:1: error: type mismatch;
 found   : java.lang.String("22")
 required: Option[java.net.URL]
organizationHomepage := "22"

Some argue about the benefits of type-safe build tools, but I say if type-safety is good for your code then surely it’s also good for build files. In any medium or large project, you will write a considerable amount of code for your build system, and SBT can provide type-safety for faster feedback. In the next section you’ll learn to build a more formal project structure for SBT.

Building a Project Structure for SBT

If you’ve used SBT 0.7+ before, you might be a little surprised to know that SBT doesn’t create a Maven-style project structure for you. But don’t worry, because now you have multiple ways to create your project structure. You can use the following snippet to create all the folders typically found in an SBT project:

$ mkdir -p src/{main,test}/{scala,java,resources} lib project

This will create all the folders you need for a typical Scala application. As a second option, you can use an SBT plug-in to create a new project. An SBT plug-in extends the build definition by adding new tasks and settings. Since the plug-in creates new SBT projects it makes sense to add it as a global plug-in. Global plug-ins are automatically added to all SBT projects; adding a plug-in to a project confines it to that project. To add a global plug-in create the following files:

$ touch <home-directory>/.sbt/plugins.sbt
$ touch <home-directory>/.sbt/build.sbt

You’re going to use the np plug-in (https://github.com/softprops/np) to generate the new project. To use it, add the following lines to the plugins.sbt:

addSbtPlugin("me.lessis" % "np" % "0.2.0")

resolvers += Resolver.url("sbt-plugin-releases",
  url("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(
    Resolver.ivyStylePatterns)

The resolvers key tells SBT of the locations to find the dependencies. The += lets you append new resolvers to existing ones. The addSbtPlugin function adds a new plug-in to the SBT build system. Now add the following line to the build.sbt file:

seq(npSettings: _*)

The plug-in provides npSettings and by adding the above line to build.sbt this setting will be available to all the SBT projects. We’ll explore SBT settings in detail shortly. Now to create a new project just execute the following commands:

$ mkdir <your project name>
$ cd <your project name>
$ sbt np

The np plug-in also generates a default build.sbt file that you can modify to add your settings.

The third option is to use giter8 (https://github.com/n8han/giter8). It’s a command-line tool to generate files and directories from templates published in Github. This is slowly becoming a standard way of creating projects in Scala. Once giter8 is installed, you can choose a template to generate the project structure.

Note

You don’t have to go to the SBT prompt to execute SBT tasks—you can execute them from the command line. For example, the sbt compile run command will execute both compile and run.

It doesn’t matter how you’ve created the project structure; the structure should look familiar if you’ve used the Maven build tool previously because SBT uses the Maven project directory structure (figure 6.2). In fact, if you use Maven with a Scala plug-in (http://scala-tools.org/mvnsites/maven-scala-plugin/) to create a project, you’ll end up with almost the same project directory structure as SBT. If your project has Java source files along with Scala source files, you need to have a folder called java under src/main and src/test.

Figure 6.2. SBT project structure

Figure 6.2 shows a complete SBT project with all the possible build configurations. You’ve already seen build.sbt in action. It’s a simple build configuration that allows you to set various build-related settings and dependencies. You haven’t configured dependencies yet but you’ll learn how to shortly.

Note

The convention is to name the build files build, like build.sbt or build.scala, but you can use any name. This also means you can have multiple .sbt and .scala build files in one project.

The build.scala file gives you the full power of SBT. Instead of using the DSL, you can write Scala code to configure your build using build.scala. In the old SBT world, this was the only way to configure build. But in the “new” SBT it’s recommended that you start with the simple build definition (build.sbt file) and only when needed create the build.scala file. For your weKanban project, you’ll use both of them together.

The build.properties file allows you to set the version of SBT used to build the project. For example, the contents of my build.properties are as follows:

sbt.version=0.12.0

This sets the version of SBT used by the project. The project/plugins.sbt is typically used to configure SBT plug-ins for the project. Please note that you don’t need the build.scala and plugin.sbt files to build projects with SBT. Only add them to the project when the need arises. The target folder is used to store generated classes, .jars, and other artifacts produced by the build.

Note

Always start with the .sbt file and only add the .scala file when needed. The rule of thumb is to define all the settings in the .sbt file and use .scala files when you need to factor out a val or object or method definition. For multiproject setup, the build.scala file is used to define common settings and tasks for multiple projects.

SBT project structure is recursive. The project directory is another project inside your project that knows how to build your project. And the project/project knows how to build the parent project. The .scala build configuration is an SBT project.

Adding Dependencies and Custom Tasks

There are two ways you can manage dependencies with SBT: manual and automatic. To manually manage dependencies, copy the .jar files you want to the lib folder. SBT will put these .jar files on the classpath when compiling, running, and testing. The downside is now you’re responsible for managing those .jars, updating them, or adding them. The most common and recommended way to manage dependencies in SBT projects is to allow SBT to do it for you. In automatic dependencies management, you specify the dependency in your build definition file, and SBT handles the rest. For example, the following build.sbt file adds a jetty server as a dependency:

libraryDependencies += "org.eclipse.jetty" % "jetty-server" %
     "7.3.0v20110203"

The libraryDependencies is setting a key to add dependencies to the project so that SBT can handle them automatically. This key holds the sequence of all the dependencies for a given project. The following is how you define dependency in SBT:

groupID % artifactID % version

This way of referring to dependencies is exactly how dependencies are resolved in Maven using Project Object Model (POM) files. Any dependency can be uniquely found using the three properties in the preceding code.

Note

If you use %% after groupID, SBT will add the Scala version of the project to the artifact ID.

SBT uses a set of resolvers to locate project dependencies and download them. In SBT, a resolver is mapped to a URL that hosts dependencies (like Maven repositories). By default, SBT uses Maven2 and Typesafe ivy releases[5] to resolve dependencies. You can also easily add new resolvers to the list of existing resolvers using the resolvers key.

5 Index of ivy-releases, http://repo.typesafe.com/typesafe/ivy-releases.

Using SBT on existing Maven Scala projects

Because SBT follows Maven project structure and uses Maven dependencies, setting up SBT for a Maven project is easy. SBT can read the dependencies defined in the POM file if you use the externalPom() method in your build file. Note you still have to specify the repositories.

Alternatively, you can create a project definition file configured to use a local Maven repository:

resolvers += "Local Maven Repository" at
"file://"+Path.userHome+"/.m2/repository"

SBT automatically picks up the build configuration changes, but you can also explicitly run the reload and update tasks to recompile and resolve dependencies.

Note

SBT uses Apache Ivy to implement and manage dependencies. Apache Ivy is a dependency manager with flexibility and configurability.

You can also declare dependencies for a specific configuration (scope) by specifying an additional value after the version in the dependency declaration. The following line declares the dependency to specs (unit testing framework for Scala) but only for a test configuration:

libraryDependencies += "org.scala-tools.testing" % "specs" % "1.6.2" % "test"

Now this dependency is only available for classes under src/main/test. Here’s how the build.sbt looks after all the changes:

scalaVersion := "2.10.0"

name := "Testing SBT"

version := "1.0"

scalacOptions ++= Seq("-unchecked", "-deprecation")

libraryDependencies ++= Seq(
"org.eclipse.jetty" % "jetty-server" % "7.0.0.RC2",
"org.scala-tools.testing" % "specs" % "1.6.2" % "test")

Another common thing you can do with SBT is create custom tasks for the project. For custom tasks, the .scala build definition file is used because the .sbt build file doesn’t support it. To create custom tasks follow these steps:

1.  Create a TaskKey.

2.  Provide a value for the TaskKey.

3.  Put the task in the .scala build file under project.

TaskKey is similar to SettingKey, but it’s used to define tasks. The main difference is the value of SettingKey is evaluated only once, but the value of TaskKey is evaluated every time the key is accessed. It makes sense because you want to execute the task over and over again. But both SettingKey and TaskKey produce settings (key-value pairs) for the build. The following shows a simple Build.scala file that defines a hello world task:

If the name of the project is example, the Build.scala file should go under the example/project folder. creates a new TaskKey by passing the name and the description of the task. The name part will be used to invoke the task from the SBT prompt. defines the task by assigning a closure that implements the task, and this creates a setting that you can use in your project.

The build definition of the project should extend sbt.Build, and it gives access to default build settings. Each build definition should also define one or more projects. In this case you have only one project, but multiproject builds will declare all the subprojects here. Multiproject build definitions are beyond the scope of this book, but you can always check out http://scala-sbt.org for details. Because you want to add the hello task to the project, you set it by calling the settings method on the project. Now you have a new task available for the project:

> reload
[info] Loading project definition from ...
[info] Set current project to Testing SBT ...
> hello
Hello World
[success] Total time: 0 s, ...

Debugging project definition in interactive mode

Depending on the size of the Scala project you’re working on, the build definition could become quite big. To troubleshoot any problems with a project definition, SBT provides a task called console-project. If you execute this build command inside the SBT console, SBT will load the Scala interpreter with your build definition. If you run console-project it will load all your build and plug-in definitions from your project and make them accessible. If you run the console-project task on your example project, you can access its settings and run tasks:

scala> get(name)
res2: String = Testing SBT
scala> get(scalaVersion)
res3: String = 2.10.0
scala> runTask(hello, currentState)
Hello World
res11: (sbt.State, Unit) = (sbt.State@4fae46d5,())

runTask runs any task defined in the build. In this case, you have the hello task. The currentState tracks SBT commands.

Similarly, you can launch the Scala interpreter with your project classes using the console build command.

You should have all the basics you need to know about SBT to use it to build a web application. In the next section, you’ll build the weKanban project structure and learn how to build web applications using SBT.

6.2.3. Setting up the weKanban project with SBT

To set up the weKanban project, first create the project structure as shown in figure 6.3. This structure will look similar to the structure in figure 6.2 with additional folders for web projects. As you build the project, you’ll fill up these folders and build files.

Figure 6.3. WeKanban project structure

Start by setting the SBT version you’re going to use for the weKanban project in the project/ build.properties file:

sbt.version=0.12.0

The only purpose of the build.properties file is to set the value of the sbt.version key. In this case, it’s set to version 0.12.0. SBT will automatically download the version specified in the properties file if it’s not available locally. Next, add project-related build information inside the build.sbt file:

name := "weKanban"

organization := "scalainaction"

version := "0.1"
scalaVersion := "2.10.0"

scalacOptions ++= Seq("-unchecked", "-deprecation")

Remember to separate each setting expression with an empty new line so that SBT can parse each expression .sbt file. When SBT loads a .sbt file, it creates a Seq[Setting[T]] of all the expressions defined in the .sbt file.

To add web support for your project, you’ll use the SBT web plug-in (https://github.com/siasia/xsbt-web-plugin) that uses the Jetty web server (http://jetty.codehaus.org/jetty/). This plug-in adds tasks to the SBT build to start and stop the web server. Add the following line to the project/plugins.sbt file:

libraryDependencies <+= sbtVersion {v =>
  "com.github.siasia" %% "xsbt-web-plugin" % (v+"-0.2.11.1")
}

This adds the web plug-in as a dependency to the project. Adding the plug-in is nothing more than adding a library dependency to the build definition. The <+= method allows you to compute a new list element from other keys. Here the sbtVersion key is used to determine the exact version number for the plug-in. In fact, the apply method of the sbtVersion is used to compute the version of the plug-in:

libraryDependencies <+= sbtVersion.apply {v =>
  "com.github.siasia" %% "xsbt-web-plugin" % (v+"-0.2.11.1")
}

Before using the plug-in to start and stop the project, you have to add Jetty dependencies to the build definition inside build.sbt:

libraryDependencies ++= Seq(
  "org.eclipse.jetty" % "jetty-servlet" % "7.3.0.v20110203" % "container",
  "org.eclipse.jetty" % "jetty-webapp" % "7.3.0.v20110203" % "test,
     container",
  "org.eclipse.jetty" % "jetty-server" % "7.3.0.v20110203" % "container"
)

Note that the Jetty dependencies are added into the container scope. Additionally, jetty-web is added into test scope. The scope (http://scala-sbt.org) allows SBT keys to have values in more than one context. Think of scope as a name-spacing mechanism that allows a key to have different values in different scopes. For example, in a multiproject build, you could have the sbtVersion key value set to a different version of Scala for each project. This is useful for plug-ins because scoping allows plug-ins to create tasks that don’t conflict with other task names. To include all the tasks from the plug-in to your project, you have to import the settings from the plug-in project into your build.sbt file as follows:

seq(com.github.siasia.WebPlugin.webSettings :_*)

If everything goes well in your SBT prompt, you should see additional tasks under the container scope (you might have to invoke the reload task):

> container:
apps                   classpath-types        configuration
configuration-files    configuration-xml      custom-configuration
discovered-contexts    full-classpath         managed-classpath       port
reload                 start
state                  stop                   streams                 this-
project-ref       update

To start the web server, run the container:start task, and it will start the Jetty server at port number 8080. Because SBT forks a new process to run the Jetty server, you can execute other build actions in the SBT console while the server is running. In http://localhost:8080/ you should see the directory listing of the webapp folder. At this point you’re done with your build setup. You’ll add more dependencies when you need them. Now let’s switch gears and talk about Scalaz, a framework for building web applications in Scala.

6.3. Introducing the Scalaz HTTP module

Scalaz (pronounced “Scala-zed”) is a library written in the Scala programming language. The idea behind Scalaz is to provide general functions that aren’t provided by the standard Scala API. This section introduces you to the HTTP module that comes with the core Scalaz distribution. And while you’re using the HTTP module, I’ll touch on some of the Scalaz core APIs that are used by the Scalaz HTTP module. Let me first introduce you to the Scalaz HTTP module and how you’ll use it for your weKanban application.

6.3.1. How the Scalaz HTTP library works

In a nutshell, the Scalaz HTTP library is a wrapper over Java Servlet APIs. What the Scalaz HTTP library exposes is a way to write functions that transforms an HTTP request into a response. This exactly matches what was discussed in section 6.1, where I talked about mapping HTTP URLs to functions that take requests and return responses. The following is an example of what a web Application trait looks like in Scalaz:

trait Application[IN[_], OUT[_]] {
  def apply(implicit req: Request[IN]): Response[OUT]
}

The Application trait defines a single apply method that takes an instance of request and returns an instance of response. The easiest way to implement this method would be to create a factory method that takes a function to transform request to response. Here’s how that would look:

object Application {
  def application[IN[_], OUT[_]](f: Request[IN] => Response[OUT])
        = new Application[IN,OUT] {
        def apply(implicit req: Request[IN]) = f(req)
  }
}

The application method creates a new instance of the Application trait by passing the function that takes a request and returns an instance of response. The type parameters used by the Application trait look quite different than what you saw in section 4.1—they’re called higher-kinded types in Scala. Think of higher-kinded types as a way to specify a type of a parameter type (type of types). I know this is little confusing, so let’s break it down a bit.

Another example of higher-kinded types

You’ve already seen an application for higher-kinded types in the Scalaz library, so now let’s study an example to understand why higher-kinded types are so powerful. You’ve learned that higher-kinded types are nothing but a group of types, and when you have to write a function that could operate on a group of types, higher-kinded types are a common way to implement it. How would you implement a sum function that could operate on various types of Scala collections? One way would be to implement sum for all the collection types:

def sumList(xs: List[Int]): Int = xs.foldLeft(0)(_ + _)
def sumArray(xs: Array[Int]): Int = xs.foldLeft(0)(_ + _)

This isn’t an effective way to implement a sum function, but if you create an abstraction for all the collections as a type, then you could write a generic sum function that works with that type. Let me show you what I mean here. First make your sum function work with all types that implement the + function. To achieve that, create a trait called Summable that’s parameterized for type A:

trait Summable[A] {
  def plus(a1: A, a2: A): A
  def init: A
}

Now for each type that supports the + function, I’ll implement this trait. The following is the implementation for Int and String types:

object IntSummable extends Summable[Int] {
  def plus(a1: Int, a2: Int): Int = a1 + a2
  def init: Int = 0
}
object StringSummable extends Summable[String] {
  def plus(a1: String, a2: String): String = a1 + a2
  def init: String = ""
}

Similarly you can implement this for other types. Now, to implement the logic to sum all the elements of a collection, use the foldLeft function, but this time you’ll create a trait to abstract the foldLeft function for any higher-kinded type:

trait Foldable[F[_]] {
  def foldLeft[A](xs: F[A], m: Summable[A]) : A
}

Note that you’re using the Summable trait created a minute ago. Now, for each type of Scala collection, implement this trait:

object ListFoldLeft extends Foldable[List] {
  def foldLeft[A](xs:List[A],m:Summable[A]) =
     xs.foldLeft(m.init)(m.plus)
}
object ArrayFoldLeft extends Foldable[Array] {
  def foldLeft[A](xs:Array[A],m:Summable[A]) =
     xs.foldLeft(m.init)(m.plus)
}

Using these traits you’ll implement your generic sum function. Your generic sum function will take three parameters: the collection, the appropriate implementation of the Foldable trait, and the Summable trait for a given type:

def sum[F[_], A](xs: F[A], f: Foldable[F], m: Summable[A]): A =
     f.foldLeft(xs, m)

Here you’re parameterizing the sum function for the type of collection and the type of the objects the collection holds. Now to sum the list of integers and array of strings, you can use the previous sum function as follows:

sum(List(1, 2, 3), ListFoldLeft, IntSummable)
sum(Array("one", "two", "three"), ArrayFoldLeft, StringSummable)

Admittedly, a sum function like that is a little verbose and not as clean as invoking sum(List(1, 2, 3)) and sum(Array("one", "two", "three")), but let’s defer this for the next chapter, where you’ll see how you can improve your sum function. In a smaller context, this approach might look like a lot of work, but in a large context this is a powerful way to create abstractions, and you’ll see some real-world examples of it in the next chapter.

Both request and response objects need to talk to the input stream and output stream to read and write HTTP parameters. But wouldn’t it be nice if we could think of this input or output stream as a collection? The request and response would have a collection of bytes, and we could use all the collection API methods. Scalaz allows exactly that, using type parameters. Out of the box, you can parameterize Request or Response using scala.collection.Stream or scala.collection.Iterator. Here’s one way to use the application method:

Application.application { req: Request[Stream] =>
  new Response[Stream] {
  ...
  }
}

The advantage of this is that now you can use all the collection methods to read and write without worrying too much about the input and output stream. And because Scala Stream is a nonstrict collection (see section 4.5), you only read from the input stream when you need it. Why do you need a higher-kinded type again? Because Stream is a collection and has its own parameter type, you have to say Stream of something. In this case it’s Stream of bytes. The IN[_] and OUT[_] type parameters will get evaluated to Stream[Byte] and Stream[Byte] during runtime. You’ll shortly see this Application trait in action.

Note

The conversion from inputStream to Request[Stream] happens through a class called scalaz.http.InputStreamer defined in the Scalaz HTTP module. This class in turn uses the Scalaz core library to convert inputStream to Scala Stream.

To deploy your web application in Jetty or any Java web container, you have to conform to the Java Servlet API. I mentioned earlier that Scalaz provides a wrapper around Java servlets, so you don’t have to worry about that too much. Figure 6.4 shows how HTTP requests are handled in Scalaz when deployed in a web container.

Figure 6.4. The way HTTP requests are handled by Scalaz

Like a standard Java web application, Scalaz is configured using web.xml. Typically you map all the URLs to any of the subclasses of scalaz.http.servlet.ScalazServlet. In this application you’ll use scalaz.http.servlet.StreamStreamServlet. Usually this servlet is configured with the name of the application class (similar to the Application trait we saw earlier) that will handle all the request and response. You have to write this application class for your weKanban application. The main responsibility of the servlet class is to instantiate the application class and transform between the HTTP servlet request and servlet response to Scalaz’s scalaz.http.request.Request and scalaz.http.response.Response objects.

When the web server (we’re using Jetty) receives an HTTP request (see figure 6.4) it calls the service method of ScalazServlet. Inside the service method it transforms the HTTP servlet request to the Scalaz Request object and then invokes the application method of the Application trait configured in web.xml. Once the application method returns the Scalaz response, it transforms that response object back to the HTTP servlet response so that the web server can send the response back to the caller. With this new knowledge, let’s move on and configure Scalaz to your SBT build. After this, you’ll be ready to implement stories for your weKanban application.

Servlet lifecycle

The lifecycle of the servlet is controlled by the web container (in this case, Jetty) in which the servlet is deployed. When the container receives a request that maps to a servlet, the container performs the following steps:

  • If the instance of the servlet doesn’t exist, it creates one.
  • Initializes the servlet instance by calling the init method. You can override this init method to initialize anything you need before serving any request. You can also pass parameters to this init method. ScalazServlet overrides this init method to initialize the application class from the init parameter.
  • Servlet’s service method is invoked by passing a request and response object. Typically servlet-based frameworks override this service method to invoke framework-specific classes. In the case of ScalazServlet, the service method transforms the HTTP request and response to Scalaz-specific request and response instances and invokes the application class to handle the request. Each Scalaz-based web application will provide the implementation of this application. (You’ll see this class shortly.)

6.3.2. Configuring Scalaz with SBT

In order to configure Scalaz with SBT, Scalaz must be added as a dependency to your WeKanbanProjectDefinition.scala file. The following listing shows how it will look like after adding the Scalaz dependency.

Listing 6.1. build.sbt with Scalaz dependencies
name := "weKanban"

organization := "scalainaction"

version := "0.1"

scalaVersion := "2.10.0"

scalacOptions ++= Seq("-unchecked", "-deprecation")

libraryDependencies ++= Seq(
  "org.scalaz" %% "scalaz-core" % "6.0.3",
  "org.scalaz" %% "scalaz-http" % "6.0.3",
  "org.eclipse.jetty" % "jetty-servlet" % "7.3.0.v20110203" % "container",
  "org.eclipse.jetty" % "jetty-webapp" % "7.3.0.v20110203" % "test,
     container",
  "org.eclipse.jetty" % "jetty-server" % "7.3.0.v20110203" % "container"
)

seq(com.github.siasia.WebPlugin.webSettings :_*)

After adding Scalaz dependencies, if you reload and update your project from the SBT console, SBT will download the necessary Scalaz .jar files from the Scala snapshot repository. SBT will automatically look for dependencies that are compatible with the version of Scala your project is configured for. In the preceding project definition, notice that for scalaz-core and scalaz-http I’m using double %% rather than single %. This tells SBT to look for dependencies matching the Scala version of the project. If multiple Scala versions are configured, it will download dependencies for each configured version. Ideally you should use this pattern for declaring dependencies, but not all libraries in the Maven repository support the naming convention required by SBT to make the pattern work.

In the previous section you learned about Scalaz and how it works in the Java web server environment, but you haven’t configured one. Let’s do that right now. Start by creating web.xml. I’m not going to explain the entire web.xml file here, only the parts that are interesting for our purposes. The two most important things you need to configure in the web.xml file are the Scalaz servlet and the application class. The following listing shows what web.xml would look like.

Listing 6.2. Configuring web.xml for weKanban

Here you’re using StreamStreamServlet as your servlet class. This servlet will create both a request and response of type scala.collection.Stream (discussed in the previous section). The application class you’re going to use is com.kanban.application.WeKanbanApplication. When the Scalaz servlet is initialized, the application class that’s passed as an init-param will be instantiated. Let’s save this web.xml in the src/webapp/WEB-INF folder per the Java servlet convention.

Before you start the application, you have to create the missing application class WeKanbanApplication.

6.3.3. Building your first web page using Scalaz

Your application class needs to extend the scalaz.http.servlet.StreamStreamServletApplication trait. This trait declares an abstract value of type scalaz.http.servlet.ServletApplication, which needs to be implemented, and then you’re done with the setup.

What if I want to roll out my own servlet?

It’s somewhat easy to create a servlet that extends ScalazServlet. The only thing you have to do is provide parameter type values for the request, response, and type of application class you’re going to use. For example, the StreamStreamServlet you’re using looks like the following in the Scalaz codebase:

final class StreamStreamServlet extends
    ScalazServlet[Stream,Stream,StreamStreamServletApplication]
     (classOf[StreamStreamServletApplication])

Because StreamStreamServletApplication is used for the application class, you have to extend that for your application class. The only requirement for the application class or trait is to provide a method or value called application that is of type ServletApplication.

The only abstract method defined in the ServletApplication trait is this:

def application(implicit servlet: HttpServlet,
    servletRequest: HttpServletRequest,
    request: Request[IN]) : Response[OUT]

This application method isn’t that much different from the one I started this discussion with (section 6.4.1). Because you’re using a servlet to handle the HTTP request and response, Scalaz is providing access to the underlying HttpServlet and HttpServletRequest. But for this application we’ll stick to Scalaz Request.

The only thing that will look new to you is the implicit keyword before the servlet parameter. The beauty of declaring the implicit parameter[6] is that, if such a method misses its arguments for implicit parameters, the compiler will automatically provide such an argument by looking up the implicit value matching the type of the argument in the enclosing scope. Implicits are a powerful concept in Scala. Chapter 7 looks into implicit in detail.

6 David R. MacIver, “An Introduction to Implicit Arguments,” March 3, 2008, http://mng.bz/TqwD.

I think you’re ready to implement your Scalaz application class. Here’s how it looks right now:

final class WeKanbanApplication extends StreamStreamServletApplication {

  val application = new ServletApplication[Stream, Stream] {

    def application(implicit servlet: HttpServlet,
        servletRequest: HttpServletRequest,
        request: Request[Stream]) = {
    }
  }
}

You’re extending the StreamStreamServletApplication to create your application class because it’s enforced by the Scalaz servlet you’re using to handle all the HTTP request and response. The only abstract value you have to implement is application, and the preceding code does that by providing an implementation of the application method. Right now the method isn’t doing anything. The quickest way to verify your configuration and setup is to add a static HTML file that you’ll load using your application class. This way you’ll know that your environment is working properly.

To load any static resource from the web context (in this case, src/main/webapp), Scalaz provides a useful method called resource. Using this method, you can load any existing resource requested:

HttpServlet.resource(x => OK << x.toStream, NotFound.xhtml)

Here the resource method will try to load the resource from the filesystem relative to your web context path and, if found, invoke the first parameter passed to it. The first parameter is a function that takes Iterator[Byte] and returns a Response[Stream]. You can invoke the resource method in the following way as well:

def found(x: Iterator[Byte]) : Response[Stream] = OK << x.toStream

resource(found, NotFound.xhtml)

OK (scalaz.http.response.OK) is one of the case classes created for HTTP status code, and it corresponds to status code 200. Now when you invoke the << method on a Scalaz status code object, it converts that to an empty Scalaz Response object. Once it’s converted to a Response object, << appends the stream to the body of the response. With OK << x.toStream, you create a Scalaz Response object with the contents of the requested resource. Similarly, NotFound is a case class representing HTTP status code 404; when calling the xhtml method, it implicitly gets converted to a Scalaz Response object with an HTTP header value for a content-type of "application/xhtml+xml." This is a good example of how you can use higher-order functions and combine functions to create nice APIs like the preceding example. Chapter 4 talks about higher-order functions and functional compositions at length. After putting all these pieces together, your application looks like the following listing.

Listing 6.3. WeKanban application so far
package com.kanban.application

import scalaz._
import Scalaz._
import scalaz.http._
import response._
import request._
import servlet._
import HttpServlet._
import Slinky._

final class WeKanbanApplication extends StreamStreamServletApplication {
  val application = new ServletApplication[Stream, Stream] {
    def application(implicit servlet: HttpServlet, servletRequest:
     HttpServletRequest, request: Request[Stream]) = {
      def found(x: Iterator[Byte]) : Response[Stream] = OK << x.toStream
      HttpServlet.resource(found, NotFound.xhtml)
    }
  }
}

WeKanbanApplication is the application class that you created by extending the StreamStreamServletApplication trait. To create a valid Scalaz application class, you have extended this trait.

The StreamStreamServletApplication trait defines a single abstract value called application of type ServletApplication that you’ve overridden with the new ServletApplication.

The ServletApplication trait also defines an abstract method called application that takes servlet, HTTP request, and Scalaz request as parameters. This method is the core of the Scalaz-based web application and is invoked for each HTTP request that’s mapped to ScalazServlet.

So far, your application can only handle static content (you’ll change this little fact in the next chapter), and to load static content you’re using the Scalaz library method called resource that takes two parameters. The first parameter to the method is the function Iterator[Byte] => A (here A is Stream) that looks for the static content for the path specified in the request and loads the content as bytes. In the nested found function, you’re transforming the Iterator of bytes to a Scalaz response. The second parameter is another function that gets called when no static content is found. NotFound is a status case class defined in Scalaz that represents the 404 HTTP status code, and xhtml will create a 404 Scalaz response.

Let’s create a simple index.html file under src/main/webapp as a placeholder for your weKanban application, as follows:

<html>
    <body>
      <h1>weKanban board will come shortly</h1>
    </body>
</html>

Now go into your SBT console (you can always start the SBT console by typing sbt under the project folder) and run the jetty-run build action. This will start the Jetty server in the background, and your application should be deployed automatically provided all the steps have been followed properly. Point your browser at http://localhost:8080/index.html, and you’ll see the placeholder page.

Go ahead and pat yourself on the back, because you’re done with the Scalaz and SBT setup and are ready to implement your weKanban application.

6.4. Summary

This chapter was your first step in building a medium-sized Scala application. For the first time you moved outside the RPEL to build a Scala application. You used SBT. You learned how to work with it, configure it, and manage dependencies, which is important when it comes to building large Scala applications. You used Scalaz’s HTTP module to build your web application. You also learned how functional programming concepts could be used in web applications. And you saw how Scalaz is using Scala’s higher-order functions and pattern matching to expose nice APIs.

This chapter has provided enough background for you to work with various Scala tools to build your next application. In this chapter, you spent most of your time laying the groundwork for your weKanban application, and you haven’t finished any of the stories you started with. To complete any of the stories mentioned in section 6.2, you have to figure out a way to talk to persistence storage. The next chapter explores some of the tools available for talking to databases from Scala and completing your application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset