Spray(5)REST API Project - Recall and Prepare Project
Spray(5)REST API Project - Recall and Prepare Project
1. Recall some ideas
These things consist of all the modules we are using.
spray-can, spray-routing, spray-io, spray-http, spray-util, spray-testkit, spray-json
How we deal with HTTP
def receive = {
case HttpRequest(HttpMethods.GET, "/", _, _, _) =>
sender ! index
case HttpRequest(HttpMethods.GET, "/stop", _, _, _) =>
sender ! HttpResponse(entity = "Shutting down in 1 second ...")
context.system.scheduler.scheduleOnce(1 second span, new Runnable { def run() { context.system.shutdown() } })
case HttpRequest(GET, "/server-stats", _, _, _) =>
valclient = sender
(context.actorFor("../http-server") ? HttpServer.GetStats).onSuccess {
casex: HttpServer.Stats => client ! statsPresentation(x)
}
case HttpRequest(GET, "/io-stats", _, _, _) =>
valclient = sender
(IOExtension(context.system).ioBridge() ? IOBridge.GetStats).onSuccess {
case IOBridge.StatsMap(map) => client ! statsPresentation(map)
}
case HttpRequest(HttpMethods.GET, "/event", _, _, _) =>
sender ! ok
}
Spray Routing
class MyService extends Actor with HttpServiceActor {
def receive = handleTimeouts orElse runRoute(myRoute)
def myRoute: Route = `<my-route-definition>`
def handleTimeouts: Receive = {
case Timeout(x: HttpRequest) =>
sender ! HttpResponse(StatusCodes.InternalServerError, "Too late")
} }
The ~ operator was introduced, which connects two routes in a way that allows a second route to get a go at a request if the first route "rejected" it.
Spray-json
Then I can parse the string to AST abstract Syntax Tree(AST).
1.1. String to AST
valjson1 = """{ "streetNumber": "A1", "street" : "Main Street", "city" : "Colombo" }"""
valjson2 = """{ "name" : "John", "age" : 26, "sex" : 0 , "address" : { "streetNumber": "A1", "street" : "Main Street", "city" : "Colombo" }}"""
//string to AST
valaddressAST = json1.asJson //or JsonParser(source)
valpersonAST = json2.asJson
1.2. AST to String
//AST to string
println(addressAST.compactPrint) //or .compactPrint
println(personAST.prettyPrint)
1.3. AST to Object
import AddressJsonProtocol._
//AST 2 Object
val address1 = addressAST.convertTo[Address]
1.4. Object to AST
//Object 2 AST
valaddressAST2 = address1.toJson
Slick
Do with slick and native SQL.
2. Prepare a New Project
I need to add something to build.sbt to make some sbt commands works.
sbt>re-start
sbt>re-stop
sbt>assembly
build.sbt
import AssemblyKeys._
seq(Revolver.settings: _*)
mainClass in assembly := Some("com.sillycat.easysprayrestserver.Boot")
artifact in (Compile, assembly) ~= { art =>
art.copy(`classifier` = Some("assembly"))
}
excludedJars in assembly <<= (fullClasspath in assembly) map { cp =>
cp filter {_.data.getName == "parboiled-scala_2.10.0-RC1-1.1.3.jar"}
}
addArtifact(artifact in (Compile, assembly), assembly)
Do remember to change the mainClass in assembly.
project/build.properties
sbt.version=0.12.1
project/Build.scala
import sbt._
import Keys._
object ApplicationBuild extends Build {
lazyvalmain = Project(id = "easysprayrestserver",
base = file("."), settings = Project.defaultSettings).settings()
}
project/plugins.sbt
addSbtPlugin("io.spray" % "sbt-revolver" % "0.6.2")
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.8.5")
Then we can do the command like this
Start the application with default configuration
sbt>re-start
Stop the application
sbt>re-stop
Build the binary file
sbt>assembly
Run the application directly from Java
>java -Dconfig.file=/path/application.conf -jar LocalpointAPI-assembly-0.1.jar
And there is another configuration file.
src/main/resources/application.conf
build.env = ""
build.env = ${?env}
server {
address = "0.0.0.0"
port = 9000
}environment {app1 { server { address = "0.0.0.0" port = 9001 }}
app2 { server { address = "0.0.0.0" port = 9002 }}
}
The application which will use this configuration will be
val config = ConfigFactory.load()
val env = config.getString("build.env")
var serverAddress: String = config.getString("server.address")
var serverPort: Int = config.getInt("server.port")
if (env != null && env != "") {
serverAddress = if (config.getString("environment." + env + ".server.address") != null) config.getString("environment." + env + ".server.address") elseserverAddress
serverPort = if (config.getInt("environment." + env + ".server.port") != 0) config.getInt("environment." + env + ".server.port") elseserverPort
}
newHttpServer(handler) ! Bind(interface = serverAddress, port = serverPort)
Then the command will be
Open the port 9001
sbt>re-start --- -Dbuild.env=app1
Open the port 9002
sbt>re-start --- -Dbuild.env=app2
Open the default port 9000
sbt>re-start
3. How to Write Test
come soon…
4. How to Work with Actor
come soon…
5. How to Work with Logback
come soon…
Tips
1. Eclipse is so slow
I try to download and use eclipse from type safe
http://typesafe.com/stack/downloads/scala-ide
And install the JGit for it
http://download.eclipse.org/egit/updates
References:
spray
http://sillycat.iteye.com/blog/1766558
http://sillycat.iteye.com/blog/1766568
http://sillycat.iteye.com/blog/1767203
http://sillycat.iteye.com/blog/1768065
slick
http://sillycat.iteye.com/blog/1767204
http://sillycat.iteye.com/blog/1767865
Source codes
https://github.com/spray/spray
http://spray.io/documentation/spray-testkit/
https://github.com/spray/spray-template