How to build a REST api with Spray and Akka

Spray is a library written on top of Akka and Scala that allows to quickly create REST interfaces. It is becoming more and more popular in the Scala community because it is easy to use and performant thanks to this asynchronous, actor-based model. This article describes how to efficiently exploit Spray to create a simple REST api.

All the code produced in this tutorial, together with a quick guide on how to run and use the application, can be found here.

Update: I wrote some follow ups on this article:
1) In this article, I used the default Spray facilities for (de)serializing objects from and to JSON. In this follow-up article, I’m showing how to make (de)serialization in Spray simpler by using the json4s library.
2) Also, this article doesn’t always respect the REST protocol or the spray way of completing an endpoint. In the following article, I explain how to build a REST CRUD application in Spray, making full advantage of the Spray’s tool kit.

Our Goal

For this tutorial we want to build a REST interface to manage quizzes. In particular we would like our interface to do the following:
– Create a quiz
– Delete a quiz
– Get a random question
– Get a question by id
– Answer a question

In the following sections we will analyse how to achieve these requirements. In particular, we will focus on how to create and delete a quiz entity. The described pattern can be re-used to achieve all the other requirements: describing all the requirements one by one would not bring any extra value to the tutorial itself. Please, have a look at the GitHub repository for the complete code of this tutorial and examples on how to use the application.

Project Metadata

First we need to set up our project. Let’s add some metadata: its name and version, its organization, what scala and SBT versions we intend to use.

// file build.sbt
name := "quiz-management-service"

version := "0.1"

organization := "com.danielasfregola"

scalaVersion := "2.11.5"
// file project/build.properties
sbt.version=0.13.6

Plugins

Next step: make our life a lot easier! By importing the following plugins, we just need to run the sbt assembly command to assembly our code: it will compile the code, run all the tests and produce an executable java jar.

// file project/plugins.sbt
resolvers += Classpaths.typesafeResolver

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.0.0-M4")

addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.3.9")
// file build.sbt
enablePlugins(JavaServerAppPackaging)
...

// Assembly settings
mainClass in Global := Some("com.danielasfregola.quiz.management.Main")

jarName in assembly := "quiz-management-server.jar"

To compile, test and assembly the code:

cd quiz-management-service/spray-akka
sbt assembly

The produced jar will be called “quiz-management-server.jar” and it will be use the main class located in the package “com.danielasfregola.quiz.management”. To run our service (by default on http://localhost:5000), we just need to type the following command:

java -jar target/scala-2.11/quiz-management-service.jar

Spray Dependencies

Almost there with the boring part! We now have to include the spray libraries that we are going to use:

// file build.sbt
resolvers ++= Seq("Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/",
"Spray Repository" at "http://repo.spray.io")

libraryDependencies ++= {
    val akkaVersion = "2.3.9"
    val sprayVersion = "1.3.2"
    Seq(
        "com.typesafe.akka" %% "akka-actor" % akkaVersion,
        "io.spray" %% "spray-can" % sprayVersion,
        "io.spray" %% "spray-routing" % sprayVersion,
        "io.spray" %% "spray-json" % "1.3.1",
        "com.typesafe.akka" %% "akka-slf4j" % akkaVersion,
        "ch.qos.logback" % "logback-classic" % "1.1.2",
        "com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test",
        "io.spray" %% "spray-testkit" % sprayVersion % "test",
        "org.specs2" %% "specs2" % "2.3.13" % "test"
    )
}

Main Class

The first thing to do in our Main class is to load our system configurations. Then, we create our actor system called “quiz-management-service” that contains our http interface — remember that Spray is actor-based! Finally, our actor system is bound to an HTTP port.

package com.danielasfregola.quiz.management

import akka.actor._
import akka.io.IO
import akka.pattern.ask
import akka.util.Timeout
import com.typesafe.config.ConfigFactory
import spray.can.Http

import scala.concurrent.duration._

object Main extends App {
    val config = ConfigFactory.load()
    val host = config.getString("http.host")
    val port = config.getInt("http.port")
    
    implicit val system = ActorSystem("quiz-management-service")
    
    val api = system.actorOf(Props(new RestInterface()), "httpInterface")
    
    implicit val executionContext = system.dispatcher
    implicit val timeout = Timeout(10 seconds)
    
    IO(Http).ask(Http.Bind(listener = api, interface = host, port = port))
    .mapTo[Http.Event]
    .map {
        case Http.Bound(address) =>
            println(s"REST interface bound to $address")
        case Http.CommandFailed(cmd) =>
            println("REST interface could not bind to " +
            s"$host:$port, ${cmd.failureMessage}")
        system.shutdown()
    }
}

Rest Interface Class

The Rest interface class is an HttpServiceActor: every time it receives an HTTP request, it tries to match it to a routing defined in our RestApi trait. When a matching is found, the action defined is executed and the result sent to a Responder actor. The Responder actor is responsible for sending back a meaningful HTTP response with an appropriate status code and body. Every time we receive a valid HTTP request, we create an instance of the Responder actor and then kill it once the request has been completed.

package com.danielasfregola.quiz.management

import akka.actor._
import akka.util.Timeout
import spray.http.StatusCodes
import spray.httpx.SprayJsonSupport._
import spray.routing._

import scala.concurrent.duration._
import scala.language.postfixOps

class RestInterface extends HttpServiceActor
with RestApi {

    def receive = runRoute(routes)
}

trait RestApi extends HttpService with ActorLogging { actor: Actor =>

    implicit val timeout = Timeout(10 seconds)
    
    var quizzes = Vector[Quiz]()
    
    def routes: Route = ???
}

class Responder(requestContext:RequestContext) extends Actor with ActorLogging {

    def receive = ???
    
    private def killYourself = self ! PoisonPill

}

For the purposes of this tutorial, we will store all the data in a vector: this is not an ideal solution for a production system, but it allows this article to focus on how Spray works. In a more realistic context, we should delegate actions to other classes — or even better actors! — and store the data in a persistent data storage (e.g.: database).

How to create and delete a quiz

Our interface needs to provide the functionalities of creating and deleting a quiz entity. This can be translated in the following REST calls:
– POST to URI /quizzes with JSON body: {"id": "my_quiz_id", "question": "my_question", "correctAnswer": "my_answer"}
– DELETE to URI /quizzes/my_quiz_id with no body

First, we need to define what a Quiz is and the messages that we can send to the Responder actor. This can easily be achieved by using case classes and objects:

// file src/main/scala/com/danielasfregola/quiz/management/QuizProtocol.scala
...
// entity: quiz
case class Quiz(id: String, question: String, correctAnswer: String)

// message: quiz has been created
case object QuizCreated

// message: quiz cannot be created because it already exists
case object QuizAlreadyExists

// message: quiz has been deleted
case object QuizDeleted
...

Also, we need instructions on how to (un)marshall a Quiz case class.

// file src/main/scala/com/danielasfregola/quiz/management/QuizProtocol.scala
...
object Quiz extends DefaultJsonProtocol {
    implicit val format = jsonFormat3(Quiz.apply)
}
...

The RestApi trait defines the routing and the operation to execute. For each matched HTTP request we create an instance of the Responder actor: once the result of the executed operation is available we send it to the Responder actor.

....

var quizzes = Vector[Quiz]()

def routes: Route =

pathPrefix("quizzes") {
    pathEnd {
        post {
            entity(as[Quiz]) { quiz => requestContext =>
                val responder = createResponder(requestContext)
                createQuiz(quiz) match {
                    case true => responder ! QuizCreated
                    case _ => responder ! QuizAlreadyExists
                }
            }
        }
    } ~
    path(Segment) { id =>
        delete { requestContext =>
            val responder = createResponder(requestContext)
            deleteQuiz(id)
            responder ! QuizDeleted
        }
    }
}
...

private def createQuiz(quiz: Quiz): Boolean = {
    val doesNotExist = !quizzes.exists(_.id == quiz.id)
    if (doesNotExist) quizzes = quizzes :+ quiz
    doesNotExist
}

private def deleteQuiz(id: String): Unit = {
    quizzes = quizzes.filterNot(_.id == id)
}

private def createResponder(requestContext:RequestContext) = {
    context.actorOf(Props(new Responder(requestContext)))
}

When the Responder actor receives a message it maps it to a meaningful HTTP response: it sends it back to the HTTP requester and it kills itself ( 😥 ).

// file src/main/scala/com/danielasfregola/quiz/management/RestInterface.scala
class Responder(requestContext:RequestContext) extends Actor with ActorLogging {
import com.danielasfregola.quiz.management.QuizProtocol._

def receive = {

case QuizCreated =>
    requestContext.complete(StatusCodes.Created)
    killYourself

case QuizDeleted =>
    requestContext.complete(StatusCodes.OK)
    killYourself

case QuizAlreadyExists =>
    requestContext.complete(StatusCodes.Conflict)
    killYourself

....
}

private def killYourself = self ! PoisonPill

Summary

This article has described how to use Spray to create a REST interface. Spray is a library that uses a actor-based model to easily and efficiently implement a REST layer. Although the provided example in not applicable in a realistic system (because all the data is stored in a Vector variable!), it shows a simple pattern on how to structure a REST api using Spray: how to organise the communication between actors, the routing and the response handling.

How to use Case Classes in Scala

Scala has adopted many concepts from other functional programming languages: higher-order functions from Haskell, actors model from Erlang, futures from Clojure, etc. However, Scala has also introduced new tools in the functional programming world: case classes is one of them. Case classes are a special type of classes, as the compiler automatically adds some useful methods to them, and this makes them particularly interesting for pattern matching and data definition. This article describes how to use them.

Defining a Case Class

A case class is identified by the case keyword. An example of case class is following:

scala> case class Person(name: String, age: Int)
defined class Person

Note that no body is needed — you can omit curly braces when empty!

Every time the Scala compiler finds a case class, it automatically adds some convenience methods.

The first one that the compiler generates is a factory method: it allows to create instances of the case class without the need of using the new keyword. Following are three equivalent ways of creating a Person instance:

scala> new Person("Mr Dude", 18)
res0: Person = Person(Mr Dude,18)

scala> Person.apply("Mr Dude", 18)
res1: Person = Person(Mr Dude,18)

scala> Person("Mr Dude", 18) 	
res2: Person = Person(Mr Dude,18)
// The most concise and elegant one!

Having a factory method may not seem a big advantage, but it will make your code easier to read, in particular when dealing with creation of nested objects.

Moreover, all the parameters are converted in immutable values that can be easily accessed without worrying about any side effect:

scala> val dude = Person("Mr Dude", 18)
dude: Person = Person(Mr Dude,18)

scala> dude.name
res3: String = Mr Dude

scala> dude.age
res4: Int = 18

scala> dude.age = 19 
<console>:10: error: reassignment to val
       dude.age = 19
                ^
// Immutability is guaranteed!

Last but not least, the Scala compiler adds intuitive implementations of toString, hashCode, equals that exploit the structure of the class and the value of its parameters. For example, two classes are considered equal if they have the same structure and its parameters are recursively equal:

scala> val dude = Person("Mr Dude", 18)
dude: Person = Person(Mr Dude,18)

scala> val sameDude = Person("Mr Dude", 18)
sameDude: Person = Person(Mr Dude,18)

scala> val anotherDude = Person("Another Dude", 18)
anotherDude: Person = Person(Another Dude,18)

scala> dude equals sameDude
res3: Boolean = true

scala> dude equals anotherDude
res4: Boolean = false

scala> dude equals List()
res5: Boolean = false

Using a Case Class

Case classes are perfect data containers: not only they make the data easy to access and compare, but they also guarantee immutability — a really important aspect to keep in mind when dealing with concurrency!

Also, thanks to their implicitly generated factory method, they naturally support pattern matching:

scala> def sayHello(entity: Any) = entity match {
	| case Person("Mr Dude", _) => "Yo Dude!"
	| case Person(name, _) => s"Hello $name"
	| case _ => "You are not even a person! Go away!"
	| }
sayHello: (entity: Any)String


scala> sayHello(Person("Mr Dude", 18))
res6: String = Yo Dude!

scala> sayHello(Person("James Bond", 50))
res7: String = Hello James Bond

scala> sayHello(List())
res8: String = You are not even a person! Go away!

Summary

This article has discussed the use of case classes in Scala. Case classes are a novel functional programming feature in Scala, particularly useful when used as data containers and for pattern matching.

Akka Actors: Best Practices

Actors are components of message-passing systems that are particularly popular these days. They make concurrency a lot easier to understand compared to the traditional thread-monitor-lock model.

An actor is a thread-like program that run independently from other actors. It has a mailbox to receive messages from other actors, where each message represents a task to complete. Although actors are much easier understand, we still need to pay attention on how to use them. Following is a list of golden rules when using actors:

Never block

Actors should never be blocked to wait for some result to come back. Instead of waiting, the time could be used to process other messages. Moreover, when an actor is blocked, it will lose requests/messages from other actors and the system could risk to collapse due to deadlocks. If blocking cannot be avoided, delegate to special actors that are dedicated just to the specific blocking tasks.

Communicate only via messages

The idea behind the message-passing system is to keep all the shared data within the message. If the communication doesn’t happen through messages, we risk to introduce some extra shared data that need to be protected by locks. A part from the performance loss, what’s the point of using the actor model if we still have to deal with locks?

Messages should be immutable

As mentioned before, the messages contain all the shared data between the actors. Having immutable messages guarantees that the shared data is thread-safe. This can be easily achieved by using case classes for your messages: not only the immutability is guaranteed, but pattern matching can be easily used to identify the type of your message.

Messages should be complete and self-contained

When receiving a message, an actor should have all the information needed to process it. This reduces dependencies between actors and it allows an actor not to have any memory/history of when/why a specific request was made. Don’t be scared of adding some redundancy to your messages if it helps to improve your system performance.

If you try to follow these simple rules, your concurrent challenges will be a lot easier to tackle — and the system more performant!

Type Parameterisation

The following article provides a list of all the different type parameterisations available in Scala and how to use them.

Variance

A class can depend on a type constructor. The following is an example trait that depends on a generic type T:

trait MyExample[T] {...}

The above declaration implies that the generic type T is the only valid parameter for MyExample: this is called nonvariance.

Let’s assume we would like our trait to be compatible with other types, as long as this types are subclasses of T. This can be expressed as following:

trait MyExample[+T] {...}

This concept is called covariance: Given a type U subtype of T, a class MyClass is called covariant if MyClass[U] is a subtype of MyClass[T].

What if we want to achieve the opposite? In other words, we would like our trait to be compatible with any type as long as they are superclass of type T:

trait MyExample[-T] {...}

This concept is called contravariance: Given a type S supertype of T, a class MyClass is called contravariant if MyClass[S] is a subtype of MyClass[T].

Bounds

Compatibility between classes is not the only thing we can achieve. For example, we would like our trait MyExample to accept all the types that are subclasses of T. This can be expressed using the lower bound annotation:

trait MyExample[U >: T] {...}

The upper bound annotation can be used in a similar way to let our MyExample trait accept all the types that are superclasses of T:

trait MyExample[S <: T] {...}

Last but not least, let’s assume we want our trait to accept any type as long as convertible to T. This can be achieved using the view bound annotation:

trait MyExample[V <%: T] {...}

Thank you M. Odersky for implicit conversions!