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 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 →