Rest with-spray
-
Upload
nimrod-argov -
Category
Software
-
view
251 -
download
0
Transcript of Rest with-spray
–spray.io
“Open source toolkit for building REST/HTTP-based integration layers on top of Scala and Akka”
Things We Don’t WantContainers XML Mutability Java under the surface
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet> <servlet-name>controlServlet</servlet-name> <servlet-class> com.jenkov.butterfly.ControlServlet </servlet-class> </servlet>
<servlet-mapping> <servlet-name>controlServlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app>
Spray Under the Hood
Scala
Akka Actors & Futures
Akka I/O (used to be spray-io)
Thread Pool / Config / Logging by Akka
Main Modules
Server DSL (spray-routing)
Client DSL (spray-client)
Low-level HTTP Server/Client (spray-can)
HTTP Data Model (spray-http)
Test Kit (spray-testkit)
Hello, World!val myRoute = path("hello"){ complete { "world" } }
object MyServiceActor extends App with SimpleRoutingApp with MyService { implicit val system = ActorSystem("MyService-System") startServer(interface = "localhost", port = 9090)(myRoute) }
Route CompositionTransform request / response for inner nested routes
Filter requests for certain routes by
Method
Path
Params
…
Route Chaining - Try a different route
Directives - Chainingval route = a { b { c { ... // route 1 } ~ d { ... // route 2 } ~ ... // route 3 } ~ e { ... // route 4 } }
Directives - Filteringval myRoute = path("hello") { get { complete { "world" } } } ~ path("hi") { post { complete("Hello World!") } }
Directives - Extraction
val myRoute = path("student" / IntNumber){ id => complete(s"student id received: $id") }
Directives - Composition
val getOrPost = get | post
val myRoute = (path("test") & getOrPost) { complete("This could have been a get or a post only") }
Directives - Composition
val teacher = "teacher" / IntNumberval course = "course" / IntNumberval teacherCourse = path(teacher / course)
val myRoute = teacherCourse { (teacherId, courseId) => complete(s"Got teacher $teacherId and course $courseId") }
Directives - Composition
val teacher = "teacher" / IntNumberval course = "course" / IntNumberval teacherCourse = path(teacher / course)
val myRoute = (teacherCourse & getOrPost){ (teacherId, courseId) => complete(s"Got teacher $teacherId and course $courseId") }
Directives - Compositionval teacher = "teacher" / IntNumberval course = "course" / IntNumberval teacherCourse = path(teacher / course)
val getOrPostTeacherCourse = teacherCourse & getOrPost
val myRoute = getOrPostTeacherCourse { (teacherId, courseId) => complete(s"Got teacher $teacherId and course $courseId") }
Directives - Type Safety
val teacher = "teacher" / IntNumber
(teacher | get){ teacherId => complete(s"Got teacher $teacherId") }
DOES NOT COMPILE!
Directives - Many Variations
path("hi") { post { parameter("param".as[Int]) { param => validate(param > 0, "Sorry, param has to be greater than zero"){ complete("Hello World!" * param) } } }}
Rejectionsval noSuchPageHandler = RejectionHandler { case Nil => complete(NotFound, "Sorry, it's not here!") }
val myRoute = getOrPostTeacherCourse { (teacherId, courseId) => handleRejections(noSuchPageHandler) { complete(s"Got teacher $teacherId and course $courseId") }}
Rejections - Selective
implicit val generalRejectionHandler = RejectionHandler { case MissingQueryParamRejection("id") :: _ => complete(BadRequest, "Looks like a bug to me!") }
Asynchronous Processingclass CalculatingActor extends Actor { override def receive = { case _ => sender ! 42 } } val calculator: ActorRef = actorRefFactory.actorOf(Props[CalculatingActor])
path("calc") { complete{ (calculator ? "calc"). mapTo[Int]. map(result => s"calculation result is $result") }}
TestKitclass RouteTest extends Specification with Specs2RouteTest
with MyService{ def actorRefFactory = system "My REST service" should { "Answer a hello message" in { Get("/hello") ~> myRoute ~> check { responseAs[String] === "world" } } } }
TestKitclass RouteTest extends Specification with Specs2RouteTest
with MyService{ def actorRefFactory = system "My REST service" should { "Reject a POST request" in { Post("/hello") ~> myRoute ~> check { rejection === MethodRejection(HttpMethods.GET) } } }}
TestKitclass RouteTest extends Specification with Specs2RouteTest
with MyService{ def actorRefFactory = system "My REST service" should { "Reject a POST request" in { Post("/hello") ~> sealRoute(myRoute) ~> check { status === MethodNotAllowed } } } }
Akka-HTTP
Better API for handling chunked messages
Client Overhaul
Websockets support (spray doesn’t support out of the box)
References
http://spray.io/documentation/
https://github.com/spray/spray/tree/master/examples
nimroda at wix dot com
@nimrodargov