REST

Alternating between Spray-servlet and Spray-can

Posted on by  
Tammo Sminia

On a server you may want to deploy your application as a war. How to build a war with spray-servlet Locally it's easiest to run without an application server. We include both the spray-servlet and spray-can dependencies:

name := "sprayApiExample"

version := "1.0"

scalaVersion := "2.11.6"

libraryDependencies ++= {
  val akkaV = "2.3.9"
  val sprayV = "1.3.3"
  Seq(
    "io.spray"            %%  "spray-can"     % sprayV,
    "io.spray"            %%  "spray-servlet" % sprayV,
    "io.spray"            %%  "spray-routing" % sprayV,
    "io.spray"            %%  "spray-json"    % "1.3.1", //has not been updated yet
    "com.typesafe.akka"   %%  "akka-actor"    % akkaV
  )
}

//This adds tomcat dependencies, you can also use jetty()
tomcat()

Continue reading →

Building a rest API with spray

Posted on by  
Tammo Sminia

Building a rest API with akka and spray is easy. This is how I did it: SprayApiApp:

import akka.actor.{ActorSystem, Props}
import akka.io.IO
import akka.pattern.ask
import akka.util.Timeout
import spray.can.Http
import scala.concurrent.duration._

object SprayApiApp extends App {
  //we need an ActorSystem to host our application in
  implicit val system = ActorSystem("SprayApiApp")

  //create apiActor
  val apiActor = system.actorOf(Props[ApiActor], "apiActor")

  //timeout needs to be set as an implicit val for the ask method (?)
  implicit val timeout = Timeout(5.seconds)

  //start a new HTTP server on port 8080 with apiActor as the handler
  IO(Http) ? Http.Bind(apiActor, interface = "localhost", port = 8080)
}

ApiActor:

import akka.actor.{ActorLogging, Actor}
import spray.http.MediaTypes
import spray.httpx.SprayJsonSupport._
import spray.json.DefaultJsonProtocol
import spray.routing._

object RobotProtocol extends DefaultJsonProtocol {
  //Our domain class
  case class Robot(name: String)

  //We use the default json marshalling for Robot.
  //There are multiple jsonFormat methods in DefaultJsonProtocol. Depending on how many parameters the model class has.
  //Robot has just one, so we use jsonFormat1
  implicit val RobotFormat = jsonFormat1(Robot)
}
import RobotProtocol._

class ApiActor extends Actor with HttpService with ActorLogging {
  //A list of our domain objects
  var robots = List(Robot("R2D2"), Robot("Asimo"))

  //The HttpService trait defines only one abstract member, which
  //connects the services environment to the enclosing actor or test
  def actorRefFactory = context

  //This actor only runs our route, but you could add
  //other things here, like request stream processing or timeout handling
  def receive = runRoute(apiRoute)

  //Notice that both path methods return a Route. We need to chain them together with ~
  val apiRoute: Route =
    path("robots") {
      get { //with get we will return our current list of robots
        log.info("Building get route")
        complete {
          log.info("Executing get route")
          //complete will return the result in an appropriate format
          //With SprayJsonSupport it knows how to marshall a List to json
          //With RobotFormat it knows how to marshall Robot
          robots
        }
      } ~ post { //With post we will add a robot
        log.info("Building post route")
        handleWith { robot: Robot =>  //handleWith will unmarshall the input
          log.info("Executing post route")
          robots = robot :: robots
          robot //handleWith will also marshall the result. Here we simply return the new robot.
        }
      }
    } ~ path("") { //When we go to localhost:8080/ just show a link to localhost:8080/robots
      respondWithMediaType(MediaTypes.`text/html`) { //XML is marshalled to `text/xml` by default, so we simply override here
        complete {
          [The list of robots](/robots)
        }
      }
    }
}

Continue reading →

shadow-left