SlideShare una empresa de Scribd logo
1 de 61
Descargar para leer sin conexión
Massimiliano Dessì
           &
     Alberto Quario

Scala On Web
Play - Scalatra - Spray

Google Technology User Group Sardegna




                       1
Speakers
    Massimiliano Dessì & Alberto Quario                 GTUG Sardegna



Max has more than 13 years of experience in
programming. He’s a proud father of three.
Manager of GTUG Sardegna, Founder of
SpringFramework IT, co-founder of Jug Sardegna.
Author of Spring 2.5 AOP. He works in Energeya and
lives in Cagliari, Italy.




Alberto has more than 15 years experience in
developing software, he wrote his first programs on a
TI-99/4A and hasn't stopped since. Other than
languages and development, Alberto's passions
include squash, cooking and Monet paintings. He
lives and works in Milano, Italy.




                             2
Agenda
Massimiliano Dessì & Alberto Quario    GTUG Sardegna


      Scalatra -Playframework -Spray

                      REST

                      JSON

                    Routing

                    Template

                     Actors

                    Sessions

                     Deploy

                 Hot Reloading

                       Test


                         3
Massimiliano Dessì & Alberto Quario   GTUG Sardegna



            Scalatra
  is a web microframework
        written in Scala
      inspired to Sinatra
a Ruby DSL to build webapp
   http://www.scalatra.org

      the BBC, LinkedIn,
         the Guardian,
      games website IGN,
        UK government
        rely on Scalatra.

                         4
REST
                              Massimiliano Dessì & Alberto Quario       GTUG Sardegna


class JellyBeans extends ScalatraServlet {

    get("/jellybs/:id") { ... }

    post("/jellybs") { ... }

    put("/jellybs/:id") { ... }

    delete("/jellybs/:id") { ... }

}

For browser add PUT & DELETE support client side
X-HTTP-METHOD-OVERRIDE or _method=put _method=delete in the post body




class JellyBeansBrowser extends ScalatraFilter with MethodOverride




                                                        5
Routes
                   Massimiliano Dessì & Alberto Quario        GTUG Sardegna



class JellyBeans extends ScalatraServlet {

  get("/jellybs/:id") {

        val id:Int = params.getOrElse("id", halt(400)).toInt
        ...
  }

  get("/jellybs/download/*.*") {            //with wildcard
     ...
   }

  get("""^/j(.*)/f(.*)""".or) {            //REGEX
     ...
   }

  post("/jellybs", request.getRemoteHost == "127.0.0.1",
     request.getRemoteUser == "admin") {
     ....
  }


                                            6
Filter
                    Massimiliano Dessì & Alberto Quario                    GTUG Sardegna




class JellyBeans extends ScalatraServlet {

     before() {
        db.acquireConnecion
        contentType="text/html"                                 Like Servlet Filter
    }                                                     (or Aspect Oriented Programming)
                                                          You can add logic before or the
    get("/") {                                                         routes
       val menu = db.findWelcome()
       templateEngine.layout("index.ssp", menu)
    }

    after() {
       db.releaseConnection
    }
}




                                             7
Filter
                  Massimiliano Dessì & Alberto Quario   GTUG Sardegna




class JellyBeans extends ScalatraServlet {

    before("""/api/v1/.*""".r) {
        contentType = "application/json"
    }


    before("/admin/*") { auth }


    after("/admin/*") { user.logout }




}



                                           8
Handlers
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna



Handlers are top level methods for http routines


class JellyBeans extends ScalatraServlet {


    notFound {
      <h1>Not found</h1>
    }

    halt(status = 301, headers =
                 Map("Location" -> "http://www.codemotion.com/"))


    get("/jellybs/names/*") {
      "Name not found!"
    }

}



                                                   9
Handlers
                       Massimiliano Dessì & Alberto Quario      GTUG Sardegna




class JellyBeans extends ScalatraServlet {

     get("/jellybs/names/:who") {
       params("who") match {
         case "Cherry" => "Found Cherry!"
         case _ => pass() /* call the next matching route route, routes are
     matched from bottom up*/
       }
     }

    get("/jellybs/download/:id") {
           jellyBeanService.find(params("id")) match {
              case Some(jellybean) => Ok(jellybean)
              case None => NotFound("Sorry, jellybean not found")
          }
    }

}


                                               10
Request Response & Friends
                Massimiliano Dessì & Alberto Quario      GTUG Sardegna




class JellyBeans extends ScalatraServlet {

    get("/jellybs/shows/:id") {
       //access to request,response, session and params
       request.body                  //request body as a string
       request.cookies               // cookie map
       request.isAjax                // is ajaxRequest
       request.getSession            // HttpServletSession
       request.locale                // user locale
       response.getOutputStream      //response outputstream
       servletContext.get("myIntParam") //servlet context
       val idString = params("id")
       val id = params.getAs[Int]("id")
    //val id = params.getOrElse("id", halt(500)) //another way
       ....
    }
}




                                        11
Request Response & Friends
             Massimiliano Dessì & Alberto Quario      GTUG Sardegna




class JellyBeans extends ScalatraServlet {


    get("/jellybs/*/conf/*") {
        // Matches "GET /jellybs/one/conf/two"
        multiParams("splat") // Seq("one", "two")
        //wildcard accessible with key splat
     }

    get("""^/jelly(.*)/fla(.*)""".r) {
      // Matches "GET /jellybs/flavor"
      multiParams("captures") // == Seq("bs", "vor")
    }


}



                                     12
Binding
                        Massimiliano Dessì & Alberto Quario                   GTUG Sardegna



To avoid manual binding from http and our Object Scalatra provide a binding module



   case class MyClass(id: Integer, name: String)


   post("/myroute") {
       val cmd = command[CreateMyClassCommand]
       ...
   }




                                                13
Binding
                            Massimiliano Dessì & Alberto Quario               GTUG Sardegna




     Under the hood


     abstract class MyClassCommand[S](implicit mf: Manifest[S])
                                                extends ModelCommand[S] with JsonCommand {
  
         implicit def todoStringValidators(b: FieldDescriptor[String]) =
                                                               new MyClassStringValidations(b)
     }



     class CreateMyClassCommand extends MyClassCommand[MyClass] {

         protected implicit val jsonFormats = DefaultFormats
         val name: Field[String] = asType[String]("name").notBlank.minLength(3)
     }




                                                    14
Binding
                      Massimiliano Dessì & Alberto Quario                GTUG Sardegna




  Under the hood


class MyClassStringValidations(b: FieldDescriptor[String]) {
    def startsWithCap(message: String = "%s must start with a capital letter.") =
    b.validateWith(_ =>
                    _ flatMap {
                                new PredicateValidator[String](
                                   b.name,
                                   """^[A-Z,0-9]""".r.findFirstIn(_).isDefined,
                                   message).validate(_)
                                )
                             }
                   )
  }




                                              15
Gzip
               Massimiliano Dessì & Alberto Quario   GTUG Sardegna




class GzipJellyBeans extends ScalatraServlet with GZipSupport{
    get("/") {
     <html>
       <body>
         <h1>This is
            <a href="http://en.wikipedia.org/wiki/Sparta">
              http/gzip
            </a>!
         </h1>
       </body>
     </html>
  }
}




                                       16
Flash message
                   Massimiliano Dessì & Alberto Quario   GTUG Sardegna




class FlashServlet extends ScalatraServlet with FlashMapSupport{

  post("/jellybs/create") {
    flash("notice") = "jellybean created successfully"
    redirect("/home")
  }

  get("/home") {
    ssp("/home")       //Scala Server Pages
  }




                                           17
JSON
                           Massimiliano Dessì & Alberto Quario   GTUG Sardegna




Automatic Serialization and deserialization of any Case class


object JSONServlet extends ScalatraServlet with JacksonJsonSupport{


  case class JellyBean(id: Int, name: String, flavor:String)


  protected implicit val jsonFormats: Formats = DefaultFormats


  before() {
      contentType = formats("json")
  }

  ....




                                                   18
JSON
                         Massimiliano Dessì & Alberto Quario    GTUG Sardegna



Automatic Serialization and deserialization of any Case class


object JSONServlet extends ScalatraServlet with JacksonJsonSupport{

    ...

    get("/jellybs/all"){
      jellyBeanRepo.all         //from class to json
    }

    post("/jellybs/create") {
      val jb = parsedBody.extract[JellyBean] //from json to class
      ...
    }

}




                                                 19
Template
Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                Html inline,
                   Scalate
           Twirl (Play2 template)


                  Scalate
                   mean
          SSP (Scala Server Page)
                  Scaml
                Mustache
                   Jade




                        20
Template
                    Massimiliano Dessì & Alberto Quario      GTUG Sardegna


class ScalateServlet extends ScalatraServlet with ScalateSupport{

  get("/"jellybeans/ssp) {
    contentType="text/html"
    ssp("/index", "foo" -> "uno", "bar" -> "two")
    // the layout used it’s WEB-INF/layouts/default.ssp
  }

 get("/jellybeans/jade") {
   jade("/index", "layout" -> "", "foo" -> "one", "bar" -> "two")
   // render without a layout.
 }

 get("/jellybeans/direct") {
    templateEngine.layout("/jellybeans/index.ssp")
   //direct invoking of scalate
 }




                                            21
Template
      Massimiliano Dessì & Alberto Quario    GTUG Sardegna


SSP

<%@ var body: String %>
<%@ var title: String = "Some Default Title" %>
<%@ var head: String = "" %>
<html>
<head>
  <title>${title}</title>

  <%-- page specific head goes here --%>
  ${unescape(head)}
</head>
<body>
  <p>layout header goes here...</p>

  ${unescape(body)}

  <p>layout footer goes here...</p>
</body>
</html>



                              22
Template
Massimiliano Dessì & Alberto Quario   GTUG Sardegna

JADE

!!! 5
html(lang="en")
  head
    title= pageTitle
    :javascript
       if (foo) {
          bar()
       }
  body
    h1 Jade - node template engine
    #container
       - if (youAreUsingJade)
         p You are amazing
       - else
         p Get on it!
    :coffeescript
       alert "Hello, Coffee!"




                        23
Template
Massimiliano Dessì & Alberto Quario    GTUG Sardegna




Mustache

Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}




                        24
Template
  Massimiliano Dessì & Alberto Quario   GTUG Sardegna




SCAML

!!! XML
!!!
%html
  %head
    %title Myspace
  %body
    %h1 I am the international space station
    %p Sign my guestbook




                          25
Actors
         Massimiliano Dessì & Alberto Quario   GTUG Sardegna




Non Blocking and Async
         with
   Akka and Actors




                                 26
Actors
                             Massimiliano Dessì & Alberto Quario     GTUG Sardegna




The routes can returns a Future

class MyActorServlet(system:ActorSystem, myActor:ActorRef)
                         extends ScalatraServlet with FutureSupport {

    import _root_.akka.pattern.ask
    implicit val timeout = Timeout(10)
    protected implicit def executor: ExecutionContext = system.dispatcher

    get("/async") {
      myActor ? "Do stuff and give me an answer"
    }

    get("/fire-forget") {
      myActor ! "Hey, you know what?"
      Accepted() //if you do not want return a future
    }


}


                                                     27
Actors
                        Massimiliano Dessì & Alberto Quario     GTUG Sardegna

    get("/async") {
      myActor ? "Do stuff and give me an answer"
    }


    get("/fire-forget") {
      myActor ! "Hey, you know what?"
      Accepted() //if you don’t want return a future
    }

    class CodemotionActor extends Actor {
      def receive = {
         case "Do stuff and give me an answer" => sender ! "The answer is 42"
         case "Hey, you know what?" => println("Yeah I know...")
      }
    }

}




                                                28
Actors
                         Massimiliano Dessì & Alberto Quario       GTUG Sardegna

Akka start in the Bootstrap of Scalatra



class ScalatraBootstrap extends LifeCycle {

    val system = ActorSystem()
    val codemotionActor = system.actorOf(Props[CodemotionActor])

     override def init(context: ServletContext) {
       context.mount(new JSONServlet, "/jellybs/*")
       context.mount(new FrontServlet, "/template/*")
       context.mount(new MyActorServlet(system, codemotionActor), "/actors/*")
     }

     override def destroy(context:ServletContext) {
        system.shutdown()
      }
}




                                                 29
Authentication & Security
                         Massimiliano Dessì & Alberto Quario         GTUG Sardegna


Scalatra uses Scentry a porting of Ruby Warden authentication



class OurAuthStrategy(protected override val app: ScalatraBase, realm: String)
  extends BasicAuthStrategy[User](app, realm) {

    protected def validate(userName: String, password: String): Option[User] = {
      if(userName == "myusername" && password == "secret") Some(User("myusername"))
      else None
    }

    protected def getUserId(user: User): String = user.id
}



case class User(id: String)




                                                 30
Authentication & Security
                          Massimiliano Dessì & Alberto Quario               GTUG Sardegna




Now we need to combine our strategy and ScentrySupport
trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] {
  self: ScalatraBase =>

    val realm = "Scalatra Basic Auth Example"

    protected def fromSession = { case id: String => User(id) }
    protected def toSession = { case usr: User => usr.id }
    protected val scentryConfig = (new ScentryConfig {}).asInstanceOf[ScentryConfiguration]


}




                                                  31
Authentication & Security
                          Massimiliano Dessì & Alberto Quario                  GTUG Sardegna

Now we need to combine our strategy and ScentrySupport


trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] {
  ....

    override protected def configureScentry = {
      scentry.unauthenticated {
        scentry.strategies("Basic").unauthenticated()
        scentry.strategies("")
      }
    }

    override protected def registerAuthStrategies = {
      scentry.register("Basic", app => new OurBasicAuthStrategy(app, realm))
    }

    protected def validate(userName: String, password: String): Option[User] = {
       if(userName == "scalatra" && password == "scalatra") Some(User("scalatra"))
       else None
     }
}




                                                  32
Authentication & Security
                         Massimiliano Dessì & Alberto Quario                GTUG Sardegna




Now we can use the Authentication for all routes defined in our Authenticated Servlets


class AuthenticatedServlet extends ScalatraServlet with AuthenticationSupport{

      //every route goes under authentication

}

Unauthenticated user will see a browser prompt login




                                                 33
Deployment
             Massimiliano Dessì & Alberto Quario   GTUG Sardegna




The simplest way to deploy
your Scalatra application
is as a
Web application ARchive file




                                     34
Deployment
                                         Massimiliano Dessì & Alberto Quario                     GTUG Sardegna

                                              Scalatra is based on regular Java Servlet 3.0
                                                            it can start from:
                                                   Standalone from jetty embedded
                                                         From Servlet container
                                                                 Heroku
                                                                 Jelastic
                                                                CloudBees
                                                        GAE (not out of the box )

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">
    <listener>
      <listener-class>org.scalatra.servlet.ScalatraListener</listener-class>
    </listener>

    <servlet-mapping>
      <servlet-name>default</servlet-name>
      <url-pattern>/img/*</url-pattern>
      <url-pattern>/css/*</url-pattern>
      <url-pattern>/js/*</url-pattern>
      <url-pattern>/assets/*</url-pattern>
    </servlet-mapping>
</web-app>




                                                                   35
Test
                     Massimiliano Dessì & Alberto Quario   GTUG Sardegna

                                       Test with Specs2




class FrontServletSpec extends ScalatraSpec {
  def is =
    "GET / on FrontServlet" ^
      "should return status 200" ! root200 ^
      end

    addServlet(classOf[FrontServlet], "/*")

    def root200 = get("/") {
      status must_== 200
    }
}




                                              36
Hot reloading
    Massimiliano Dessì & Alberto Quario   GTUG Sardegna




Thanks JRebel for free Scala plan !




                            37
Massimiliano Dessì & Alberto Quario   GTUG Sardegna




          www.playframework.com

• Stateless
• CoC
• Integrated Testing
• Asynchronous I/O
• Java friendly


                                 38
Controller & View
                     Massimiliano Dessì & Alberto Quario            GTUG Sardegna



package controllers                                        Application.scala
import play.api.mvc.{Controller, Action}

object Application extends Controller {
  def index() = Action {
    Ok(views.html.index("Hello codemotion!"))
  }
}



@(message: String)                                         index.scala.html
@main("Welcome to Play 2.1") {
    <h2>@message</h2>
}




                                             39
Routing
                   Massimiliano Dessì & Alberto Quario             GTUG Sardegna


conf/routes
  GET   /clients/all                  controllers.Clients.list()
  GET   /clients/:id                  controllers.Clients.show(id: Long)




  GET   /clients/$id<[0-9]+>          controllers.Clients.show(id: Long)




  GET   /clients                      controllers.Clients.list(page: Int ?= 1)

  GET   /api/list-all                 controllers.Api.list(Option[version])


                                           40
Session
       Massimiliano Dessì & Alberto Quario     GTUG Sardegna




def index = Action { implicit request =>
  session.get("connected").map { user =>
    Ok("Hello " + user)
  }.getOrElse {
    Unauthorized("Oops, you are not connected")
  }
}

Ok("Welcome!").withSession(
  "connected" -> "user@gmail.com"
)

Ok("Welcome!").withSession(
  session + ("saidHello" -> "yes") - "theme"
)




                               41
Authentication
             Massimiliano Dessì & Alberto Quario   GTUG Sardegna

import play.api.mvc.Security
trait Secured {
  private def username(request: RequestHeader) =
request.session.get("user_id")

  private def onUnauthorized(request: RequestHeader) =
Results.Redirect(routes.Application.login)

  def isAuthenticated(f: => String => Request[AnyContent] =>
Result) = Security.Authenticated(username,onUnauthorized) {
    user => Action(request => f(user)(request))
  }
}
object Application extends Controller with Secured {
  def index = isAuthenticated { userId => implicit request =>
    Ok(html.index(userId))
  }
}


                                     42
Template
                Massimiliano Dessì & Alberto Quario         GTUG Sardegna



• compiled as standard Scala functions
• follow a simple naming convention
 views/index.scala.html ➡ views.html.index
 @(customer: Customer, orders: List[Order])

 @title(text: String) = @{
   text.split(' ').map(_.capitalize).mkString(" ")
 }

 <h1>@title(customer.name)</h1>
 <ul>
 @for(order <- orders) {
   <li>@order.getTitle()</li>
 }
 </ul>

 @defining(customer.name + " " + customer.surname) { fullName =>
   <div>Regards @fullName</div>
 }


                                        43
REST
                            Massimiliano Dessì & Alberto Quario                                GTUG Sardegna


GET          /api/reviews                                controllers.Reviews.list
GET          /api/reviews/count                          controllers.Reviews.count
GET          /api/reviews/:id                            controllers.Reviews.show(id: Int)
import play.api.libs.json._                               object Reviews extends Controller {
import play.api.libs.functional.syntax._
                                                              def list = Action { request =>
case class Review(id: Int, text: String)                        Ok(toJson(Review.findAll))
                                                              }
object Review {
  val reviews: List[Review] =                                 def count = Action { request =>
    List(Review(1, "hello"), Review(2, "codemotion"))           Ok(toJson(Review.count))
                                                              }
    def findAll: Seq[Review] = reviews
                                                              def show(id: Int) = Action {
    def count: Int = reviews.size                               Review.findById(id).map { review =>
                                                                  Ok(toJson(review))
    def findById(id: Int): Option[Review] =                     }.getOrElse(NotFound(
      reviews.find(_.id == id)                                    toJson(Map("error" ->
                                                                    "Review with id %s not found".
    implicit val reviewReads = (                                    format(id)))))
      (__  "id").read[Int] and                               }
      (__  "text").read[String]                          }
    )(Review.apply _)

    implicit val creatureWrites = (
      (__  "id").write[Int] and
      (__  "text").write[String]
    )(unlift(Review.unapply))
}




                                                    44
Form
                Massimiliano Dessì & Alberto Quario               GTUG Sardegna

object Contacts extends Controller {
                                                      case class Contact(
  val contactForm: Form[Contact] = Form(                firstname: String,
    mapping(                                            lastname: String,
                                                        company: Option[String]
      "firstname" -> nonEmptyText,                    )
      "lastname" -> nonEmptyText,
      "company" -> optional(text)
    )(Contact.apply)(Contact.unapply)
  )

  def form = Action {
    Ok(html.contact.form(contactForm))
  }

  def submit = Action { implicit request =>
    contactForm.bindFromRequest.fold(
      errors => BadRequest(html.contact.form(errors)),
      contact => Ok(html.contact.summary(contact))
    )
  }


                                        45
Form /2
             Massimiliano Dessì & Alberto Quario                     GTUG Sardegna

@(contactForm: Form[Contact])
    @helper.form(action = routes.Contacts.submit) {

        <fieldset>
            <legend>General informations</legend>

            @inputText(
                contactForm("firstname"),
                '_label -> "First name"
            )

            @inputText(
                contactForm("lastname"),
                '_label -> "Last name"
            )

            @inputText(
                contactForm("company"),
                '_label -> "Company"
            )

        </fieldset>
        <div class="actions">
            <input type="submit" class="btn primary" value="Insert">
            <a href="@routes.Application.index" class="btn">Cancel</a>
        </div>

    }



                                     46
Non-blocking IO
                    Massimiliano Dessì & Alberto Quario    GTUG Sardegna




object Application extends Controller {

    def intensiveComputation(): Int = ...

    def index = Action {
      val futureInt = scala.concurrent.Future { intensiveComputation() }
      Async {
        futureInt.map(i => Ok(views.html.index("Got result: " + i)))
      }
    }
}

            play.api.libs.ws.WS

            WS.url("http://example.com/feed").get()
            WS.url("http://example.com/item").post("content")




                                            47
Non-blocking IO /2
                     Massimiliano Dessì & Alberto Quario          GTUG Sardegna


def race() = Action {
  Async {
    val start = System.currentTimeMillis()
    def getLatency(r: Any): Long = System.currentTimeMillis() - start

        val googleTime = WS.url("http://www.google.com").get().map(getLatency)
        val yahooTime = WS.url("http://www.yahoo.com").get().map(getLatency)
        val bingTime = WS.url("http://www.bing.com").get().map(getLatency)

        Future.sequence(Seq(googleTime, yahooTime, bingTime)).map {
          case times =>
            Ok(Json.toJson(Map(
              "google" -> times(0),
              "yahoo" -> times(1),
              "bing" -> times(2),
              "total" -> getLatency(0))))
        }
    }
}

{"google":343,"yahoo":3043,"bing":1608,"total":3048}

                                             48
Test
                            Massimiliano Dessì & Alberto Quario          GTUG Sardegna

class ApplicationSpec extends Specification {

    "Application" should {

        "send 404 on a bad request" in {
          running(FakeApplication()) {
            route(FakeRequest(GET, "/boum")) must beNone
          }
        }

        "render the index page" in {
          running(FakeApplication()) {
            val home = route(FakeRequest(GET, "/")).get

                status(home) must equalTo(OK)
                contentType(home) must beSome.which(_ == "text/html")
                contentAsString(home) must contain ("Your new application is ready.")
            }
        }
    }
}




                                                    49
Test /2
                            Massimiliano Dessì & Alberto Quario          GTUG Sardegna

class IntegrationSpec extends Specification {

    "Application" should {

        "work in a server" in {
          running(TestServer(3333)) {
            await(WS.url("http://localhost:3333").get).status must equalTo(OK)
          }
        }

        "work from within a browser" in {
          running(TestServer(3333), HTMLUNIT) { browser =>

                browser.goTo("http://localhost:3333/")

                browser.pageSource must contain("Your new application is ready.")
            }
        }
    }
}




                                                    50
Deploy
Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                        51
Deploy /2
                     Massimiliano Dessì & Alberto Quario                  GTUG Sardegna

Welcome to Play 2.1.0!

These commands are available:
-----------------------------
classpath                  Display the project classpath.
clean                      Clean all generated files.
compile                    Compile the current application.
console                    Launch the interactive Scala console (use :quit to exit).
dependencies               Display the dependencies summary.
dist                       Construct standalone application package.
exit                       Exit the console.
h2-browser                 Launch the H2 Web browser.
license                    Display licensing informations.
package                    Package your application as a JAR.
play-version               Display the Play version.
publish                    Publish your application in a remote repository.
publish-local              Publish your application in the local repository.
reload                     Reload the current application build file.
run <port>                 Run the current application in DEV mode.
test                       Run Junit tests and/or Specs from the command line
eclipse                    generate eclipse project file
idea                       generate Intellij IDEA project file
sh <command to run>        execute a shell command
start <port>               Start the current application in another JVM in PROD mode.
update                     Update application dependencies.




                                             52
Massimiliano Dessì & Alberto Quario          GTUG Sardegna




spray is an open-source toolkit for REST/HTTP
                        and
low-level network IO on top of Scala and Akka.


                 aka Scala -IKEA


         VMWare and Ebay use spray
           for some internal projects




                            53
Routing
                Massimiliano Dessì & Alberto Quario   GTUG Sardegna




class PingServiceActor extends Actor {
  def receive = {
       case HttpRequest(GET, "/ping", _, _, _) =>
       sender ! HttpResponse(200, "PONG")
   }
}




                                        54
Routing
                        Massimiliano Dessì & Alberto Quario   GTUG Sardegna

path with name order => directive route
get and put => are inner route
~ =>route concatenation

class MyServiceActor extends Actor with Routing {
 def receive = receiveFromRoute {
   path("order" / HexIntNumber) { id =>
       get {
           completeWith {
               "Received GET for order " + id
           }
       } ~
       put {
           completeWith { "Received PUT for order " + id

                }
            }
        }
    }
}

                                                55
Routing
                            Massimiliano Dessì & Alberto Quario                       GTUG Sardegna



trait LongerService extends HttpService with MyApp {

  val simpleCache = routeCache(maxCapacity = 1000, timeToIdle = Duration("30 min"))

    val route = {
    path("orders") {
      authenticate(BasicAuth(realm = "admin area")) { user =>
        get {
          cache(simpleCache) {
            encodeResponse(Deflate) {
               complete {
                 getOrdersFromDB
               }
            }
          }
        } ~
        post {
          (decodeRequest(Gzip) | decodeRequest(NoEncoding)) {
            entity(as[Order]) { order =>
               detachTo(singleRequestServiceActor) {
                 complete {
                   // ... write order to DB
                   "Order received"
                 }
               }
            }
          }
        }
      }
    } ~




                                                       56
Routing
                Massimiliano Dessì & Alberto Quario          GTUG Sardegna




pathPrefix("order" / IntNumber) { orderId =>
  path("") {
    // method tunneling via query param
    (put | parameter('method ! "put")) {
      // form extraction from multipart or www-url-encoded forms
      formFields('email, 'total.as[Money]).as(Order) { order =>
        complete {
          // complete with serialized Future result
          (myDbActor ? Update(order)).mapTo[TransactionResult]
        }
      }
    } ~
    get {
      jsonpWithParameter("callback") {
        produce(instanceOf[Order]) { complete => ctx =>
          processOrderRequest(orderId, complete)
        }
      }
    }
  } ~



                                        57
Non-blocking IO
                 Massimiliano Dessì & Alberto Quario          GTUG Sardegna


def race() {
  val start = System.currentTimeMillis()
  def getLatency(r: Any): Long = System.currentTimeMillis() - start

    val googleFuture = httpClient.ask(Get("http://www.google.com"))
      .mapTo[HttpResponse].map(getLatency)
    val yahooFuture = httpClient.ask(Get("http://www.yahoo.com"))
      .mapTo[HttpResponse].map(getLatency)
    val bingFuture = httpClient.ask(Get("http://www.example.com"))
      .mapTo[HttpResponse].map(getLatency)

    Future.sequence(Seq(googleFuture, yahooFuture, bingFuture)).map {
      case times =>
        log.info(
          "google" + times(0) +
          " yahoo" + times(1) +
          " bing" + times(2) +
          " total: "+getLatency(0))
        system.shutdown() // stops all actors
    }
}



                                         58
Test
                          Massimiliano Dessì & Alberto Quario               GTUG Sardegna

class DemoServiceSpec extends Specification with Specs2RouteTest with DemoService {
  def actorRefFactory = system

    "The DemoService" should {

        "return a greeting for GET requests to the root path" in {
          Get() ~> demoRoute ~> check { entityAs[String] must contain("Say hello") }
        }

        "return a 'PONG!' response for GET requests to /ping" in {
          Get("/ping") ~> demoRoute ~> check { entityAs[String] === "PONG!" }
        }

        "leave GET requests to other paths unhandled" in {
          Get("/kermit") ~> demoRoute ~> check { handled must beFalse }
        }

        "return a MethodNotAllowed error for PUT requests to the root path" in {
          Put() ~> sealRoute(demoRoute) ~> check {
            status === MethodNotAllowed
            entityAs[String] === "HTTP method not allowed, supported methods: GET"
          }
        }
    }
}



                                                  59
Massimiliano Dessì & Alberto Quario   GTUG Sardegna




Q&A




                          60
Agenda
      Massimiliano Dessì & Alberto Quario                           GTUG Sardegna




        Thanks for your attention!

Massimiliano: @desmax74                     Alberto :@realrealbot




                              61

Más contenido relacionado

La actualidad más candente

td_mxc_rubyrails_shin
td_mxc_rubyrails_shintd_mxc_rubyrails_shin
td_mxc_rubyrails_shintutorialsruby
 
FrOScamp Zurich: Introducing JCR - 2010
FrOScamp Zurich: Introducing JCR - 2010FrOScamp Zurich: Introducing JCR - 2010
FrOScamp Zurich: Introducing JCR - 2010David Nuescheler
 
Realm Java 2.2.0: Build better apps, faster apps
Realm Java 2.2.0: Build better apps, faster appsRealm Java 2.2.0: Build better apps, faster apps
Realm Java 2.2.0: Build better apps, faster appsSavvycom Savvycom
 
Dependency Injection in Laravel
Dependency Injection in LaravelDependency Injection in Laravel
Dependency Injection in LaravelHAO-WEN ZHANG
 
What istheservicestack
What istheservicestackWhat istheservicestack
What istheservicestackDemis Bellot
 
node.js Module Development
node.js Module Developmentnode.js Module Development
node.js Module DevelopmentJay Harris
 
There's more than web
There's more than webThere's more than web
There's more than webMatt Evans
 

La actualidad más candente (9)

td_mxc_rubyrails_shin
td_mxc_rubyrails_shintd_mxc_rubyrails_shin
td_mxc_rubyrails_shin
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 
FrOScamp Zurich: Introducing JCR - 2010
FrOScamp Zurich: Introducing JCR - 2010FrOScamp Zurich: Introducing JCR - 2010
FrOScamp Zurich: Introducing JCR - 2010
 
Realm Java 2.2.0: Build better apps, faster apps
Realm Java 2.2.0: Build better apps, faster appsRealm Java 2.2.0: Build better apps, faster apps
Realm Java 2.2.0: Build better apps, faster apps
 
Dependency Injection in Laravel
Dependency Injection in LaravelDependency Injection in Laravel
Dependency Injection in Laravel
 
Con5623 pdf 5623_001
Con5623 pdf 5623_001Con5623 pdf 5623_001
Con5623 pdf 5623_001
 
What istheservicestack
What istheservicestackWhat istheservicestack
What istheservicestack
 
node.js Module Development
node.js Module Developmentnode.js Module Development
node.js Module Development
 
There's more than web
There's more than webThere's more than web
There's more than web
 

Similar a Codemotion 2013 scalatra play spray

Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scala Italy
 
Codemotion 2013 scalatra_play_spray
Codemotion 2013 scalatra_play_sprayCodemotion 2013 scalatra_play_spray
Codemotion 2013 scalatra_play_sprayMassimiliano Dessì
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Arnaud Giuliani
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、GaelykでハンズオンTsuyoshi Yamamoto
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkIndicThreads
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Frameworkvhazrati
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScriptAndrew Dupont
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
 
Scaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with ScalaScaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with ScalaOstap Andrusiv
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Tsuyoshi Yamamoto
 
How to replace rails asset pipeline with webpack?
How to replace rails asset pipeline with webpack?How to replace rails asset pipeline with webpack?
How to replace rails asset pipeline with webpack?Tomasz Bak
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesAnkit Rastogi
 
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsMeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsSimo Ahava
 

Similar a Codemotion 2013 scalatra play spray (20)

Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)
 
Codemotion 2013 scalatra_play_spray
Codemotion 2013 scalatra_play_sprayCodemotion 2013 scalatra_play_spray
Codemotion 2013 scalatra_play_spray
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
名古屋SGGAE/J勉強会 Grails、Gaelykでハンズオン
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
 
Scaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with ScalaScaladroids: Developing Android Apps with Scala
Scaladroids: Developing Android Apps with Scala
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
How to replace rails asset pipeline with webpack?
How to replace rails asset pipeline with webpack?How to replace rails asset pipeline with webpack?
How to replace rails asset pipeline with webpack?
 
Os Secoske
Os SecoskeOs Secoske
Os Secoske
 
Jersey Guice AOP
Jersey Guice AOPJersey Guice AOP
Jersey Guice AOP
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsMeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
 

Último

Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 

Último (20)

Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 

Codemotion 2013 scalatra play spray

  • 1. Massimiliano Dessì & Alberto Quario Scala On Web Play - Scalatra - Spray Google Technology User Group Sardegna 1
  • 2. Speakers Massimiliano Dessì & Alberto Quario GTUG Sardegna Max has more than 13 years of experience in programming. He’s a proud father of three. Manager of GTUG Sardegna, Founder of SpringFramework IT, co-founder of Jug Sardegna. Author of Spring 2.5 AOP. He works in Energeya and lives in Cagliari, Italy. Alberto has more than 15 years experience in developing software, he wrote his first programs on a TI-99/4A and hasn't stopped since. Other than languages and development, Alberto's passions include squash, cooking and Monet paintings. He lives and works in Milano, Italy. 2
  • 3. Agenda Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra -Playframework -Spray REST JSON Routing Template Actors Sessions Deploy Hot Reloading Test 3
  • 4. Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra is a web microframework written in Scala inspired to Sinatra a Ruby DSL to build webapp http://www.scalatra.org the BBC, LinkedIn, the Guardian, games website IGN, UK government rely on Scalatra. 4
  • 5. REST Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/:id") { ... } post("/jellybs") { ... } put("/jellybs/:id") { ... } delete("/jellybs/:id") { ... } } For browser add PUT & DELETE support client side X-HTTP-METHOD-OVERRIDE or _method=put _method=delete in the post body class JellyBeansBrowser extends ScalatraFilter with MethodOverride 5
  • 6. Routes Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/:id") { val id:Int = params.getOrElse("id", halt(400)).toInt ... } get("/jellybs/download/*.*") { //with wildcard ... } get("""^/j(.*)/f(.*)""".or) { //REGEX ... } post("/jellybs", request.getRemoteHost == "127.0.0.1", request.getRemoteUser == "admin") { .... } 6
  • 7. Filter Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { before() { db.acquireConnecion contentType="text/html" Like Servlet Filter } (or Aspect Oriented Programming) You can add logic before or the get("/") { routes val menu = db.findWelcome() templateEngine.layout("index.ssp", menu) } after() { db.releaseConnection } } 7
  • 8. Filter Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { before("""/api/v1/.*""".r) { contentType = "application/json" } before("/admin/*") { auth } after("/admin/*") { user.logout } } 8
  • 9. Handlers Massimiliano Dessì & Alberto Quario GTUG Sardegna Handlers are top level methods for http routines class JellyBeans extends ScalatraServlet { notFound { <h1>Not found</h1> } halt(status = 301, headers = Map("Location" -> "http://www.codemotion.com/")) get("/jellybs/names/*") { "Name not found!" } } 9
  • 10. Handlers Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/names/:who") { params("who") match { case "Cherry" => "Found Cherry!" case _ => pass() /* call the next matching route route, routes are matched from bottom up*/ } } get("/jellybs/download/:id") { jellyBeanService.find(params("id")) match { case Some(jellybean) => Ok(jellybean) case None => NotFound("Sorry, jellybean not found") } } } 10
  • 11. Request Response & Friends Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/shows/:id") { //access to request,response, session and params request.body //request body as a string request.cookies // cookie map request.isAjax // is ajaxRequest request.getSession // HttpServletSession request.locale // user locale response.getOutputStream //response outputstream servletContext.get("myIntParam") //servlet context val idString = params("id") val id = params.getAs[Int]("id") //val id = params.getOrElse("id", halt(500)) //another way .... } } 11
  • 12. Request Response & Friends Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/*/conf/*") { // Matches "GET /jellybs/one/conf/two" multiParams("splat") // Seq("one", "two") //wildcard accessible with key splat } get("""^/jelly(.*)/fla(.*)""".r) { // Matches "GET /jellybs/flavor" multiParams("captures") // == Seq("bs", "vor") } } 12
  • 13. Binding Massimiliano Dessì & Alberto Quario GTUG Sardegna To avoid manual binding from http and our Object Scalatra provide a binding module case class MyClass(id: Integer, name: String) post("/myroute") { val cmd = command[CreateMyClassCommand] ... } 13
  • 14. Binding Massimiliano Dessì & Alberto Quario GTUG Sardegna Under the hood abstract class MyClassCommand[S](implicit mf: Manifest[S]) extends ModelCommand[S] with JsonCommand {    implicit def todoStringValidators(b: FieldDescriptor[String]) = new MyClassStringValidations(b) } class CreateMyClassCommand extends MyClassCommand[MyClass] { protected implicit val jsonFormats = DefaultFormats val name: Field[String] = asType[String]("name").notBlank.minLength(3) } 14
  • 15. Binding Massimiliano Dessì & Alberto Quario GTUG Sardegna Under the hood class MyClassStringValidations(b: FieldDescriptor[String]) { def startsWithCap(message: String = "%s must start with a capital letter.") = b.validateWith(_ =>      _ flatMap { new PredicateValidator[String]( b.name, """^[A-Z,0-9]""".r.findFirstIn(_).isDefined, message).validate(_)    ) } ) } 15
  • 16. Gzip Massimiliano Dessì & Alberto Quario GTUG Sardegna class GzipJellyBeans extends ScalatraServlet with GZipSupport{ get("/") { <html> <body> <h1>This is <a href="http://en.wikipedia.org/wiki/Sparta"> http/gzip </a>! </h1> </body> </html> } } 16
  • 17. Flash message Massimiliano Dessì & Alberto Quario GTUG Sardegna class FlashServlet extends ScalatraServlet with FlashMapSupport{ post("/jellybs/create") { flash("notice") = "jellybean created successfully" redirect("/home") } get("/home") { ssp("/home") //Scala Server Pages } 17
  • 18. JSON Massimiliano Dessì & Alberto Quario GTUG Sardegna Automatic Serialization and deserialization of any Case class object JSONServlet extends ScalatraServlet with JacksonJsonSupport{ case class JellyBean(id: Int, name: String, flavor:String) protected implicit val jsonFormats: Formats = DefaultFormats before() { contentType = formats("json") } .... 18
  • 19. JSON Massimiliano Dessì & Alberto Quario GTUG Sardegna Automatic Serialization and deserialization of any Case class object JSONServlet extends ScalatraServlet with JacksonJsonSupport{ ... get("/jellybs/all"){ jellyBeanRepo.all //from class to json } post("/jellybs/create") { val jb = parsedBody.extract[JellyBean] //from json to class ... } } 19
  • 20. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna Html inline, Scalate Twirl (Play2 template) Scalate mean SSP (Scala Server Page) Scaml Mustache Jade 20
  • 21. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna class ScalateServlet extends ScalatraServlet with ScalateSupport{ get("/"jellybeans/ssp) { contentType="text/html" ssp("/index", "foo" -> "uno", "bar" -> "two") // the layout used it’s WEB-INF/layouts/default.ssp } get("/jellybeans/jade") { jade("/index", "layout" -> "", "foo" -> "one", "bar" -> "two") // render without a layout. } get("/jellybeans/direct") { templateEngine.layout("/jellybeans/index.ssp") //direct invoking of scalate } 21
  • 22. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna SSP <%@ var body: String %> <%@ var title: String = "Some Default Title" %> <%@ var head: String = "" %> <html> <head> <title>${title}</title> <%-- page specific head goes here --%> ${unescape(head)} </head> <body> <p>layout header goes here...</p> ${unescape(body)} <p>layout footer goes here...</p> </body> </html> 22
  • 23. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna JADE !!! 5 html(lang="en") head title= pageTitle :javascript if (foo) { bar() } body h1 Jade - node template engine #container - if (youAreUsingJade) p You are amazing - else p Get on it! :coffeescript alert "Hello, Coffee!" 23
  • 24. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna Mustache Hello {{name}} You have just won ${{value}}! {{#in_ca}} Well, ${{taxed_value}}, after taxes. {{/in_ca}} 24
  • 25. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna SCAML !!! XML !!! %html %head %title Myspace %body %h1 I am the international space station %p Sign my guestbook 25
  • 26. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna Non Blocking and Async with Akka and Actors 26
  • 27. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna The routes can returns a Future class MyActorServlet(system:ActorSystem, myActor:ActorRef) extends ScalatraServlet with FutureSupport { import _root_.akka.pattern.ask implicit val timeout = Timeout(10) protected implicit def executor: ExecutionContext = system.dispatcher get("/async") { myActor ? "Do stuff and give me an answer" } get("/fire-forget") { myActor ! "Hey, you know what?" Accepted() //if you do not want return a future } } 27
  • 28. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna get("/async") { myActor ? "Do stuff and give me an answer" } get("/fire-forget") { myActor ! "Hey, you know what?" Accepted() //if you don’t want return a future } class CodemotionActor extends Actor { def receive = { case "Do stuff and give me an answer" => sender ! "The answer is 42" case "Hey, you know what?" => println("Yeah I know...") } } } 28
  • 29. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna Akka start in the Bootstrap of Scalatra class ScalatraBootstrap extends LifeCycle { val system = ActorSystem() val codemotionActor = system.actorOf(Props[CodemotionActor]) override def init(context: ServletContext) { context.mount(new JSONServlet, "/jellybs/*") context.mount(new FrontServlet, "/template/*") context.mount(new MyActorServlet(system, codemotionActor), "/actors/*") } override def destroy(context:ServletContext) { system.shutdown() } } 29
  • 30. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra uses Scentry a porting of Ruby Warden authentication class OurAuthStrategy(protected override val app: ScalatraBase, realm: String) extends BasicAuthStrategy[User](app, realm) { protected def validate(userName: String, password: String): Option[User] = { if(userName == "myusername" && password == "secret") Some(User("myusername")) else None } protected def getUserId(user: User): String = user.id } case class User(id: String) 30
  • 31. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Now we need to combine our strategy and ScentrySupport trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { self: ScalatraBase => val realm = "Scalatra Basic Auth Example" protected def fromSession = { case id: String => User(id) } protected def toSession = { case usr: User => usr.id } protected val scentryConfig = (new ScentryConfig {}).asInstanceOf[ScentryConfiguration] } 31
  • 32. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Now we need to combine our strategy and ScentrySupport trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { .... override protected def configureScentry = { scentry.unauthenticated { scentry.strategies("Basic").unauthenticated() scentry.strategies("") } } override protected def registerAuthStrategies = { scentry.register("Basic", app => new OurBasicAuthStrategy(app, realm)) } protected def validate(userName: String, password: String): Option[User] = { if(userName == "scalatra" && password == "scalatra") Some(User("scalatra")) else None } } 32
  • 33. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Now we can use the Authentication for all routes defined in our Authenticated Servlets class AuthenticatedServlet extends ScalatraServlet with AuthenticationSupport{ //every route goes under authentication } Unauthenticated user will see a browser prompt login 33
  • 34. Deployment Massimiliano Dessì & Alberto Quario GTUG Sardegna The simplest way to deploy your Scalatra application is as a Web application ARchive file 34
  • 35. Deployment Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra is based on regular Java Servlet 3.0 it can start from: Standalone from jetty embedded From Servlet container Heroku Jelastic CloudBees GAE (not out of the box ) web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <listener> <listener-class>org.scalatra.servlet.ScalatraListener</listener-class> </listener> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/img/*</url-pattern> <url-pattern>/css/*</url-pattern> <url-pattern>/js/*</url-pattern> <url-pattern>/assets/*</url-pattern> </servlet-mapping> </web-app> 35
  • 36. Test Massimiliano Dessì & Alberto Quario GTUG Sardegna Test with Specs2 class FrontServletSpec extends ScalatraSpec { def is = "GET / on FrontServlet" ^ "should return status 200" ! root200 ^ end addServlet(classOf[FrontServlet], "/*") def root200 = get("/") { status must_== 200 } } 36
  • 37. Hot reloading Massimiliano Dessì & Alberto Quario GTUG Sardegna Thanks JRebel for free Scala plan ! 37
  • 38. Massimiliano Dessì & Alberto Quario GTUG Sardegna www.playframework.com • Stateless • CoC • Integrated Testing • Asynchronous I/O • Java friendly 38
  • 39. Controller & View Massimiliano Dessì & Alberto Quario GTUG Sardegna package controllers Application.scala import play.api.mvc.{Controller, Action} object Application extends Controller { def index() = Action { Ok(views.html.index("Hello codemotion!")) } } @(message: String) index.scala.html @main("Welcome to Play 2.1") { <h2>@message</h2> } 39
  • 40. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna conf/routes GET /clients/all controllers.Clients.list() GET /clients/:id controllers.Clients.show(id: Long) GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long) GET /clients controllers.Clients.list(page: Int ?= 1) GET /api/list-all controllers.Api.list(Option[version]) 40
  • 41. Session Massimiliano Dessì & Alberto Quario GTUG Sardegna def index = Action { implicit request => session.get("connected").map { user => Ok("Hello " + user) }.getOrElse { Unauthorized("Oops, you are not connected") } } Ok("Welcome!").withSession( "connected" -> "user@gmail.com" ) Ok("Welcome!").withSession( session + ("saidHello" -> "yes") - "theme" ) 41
  • 42. Authentication Massimiliano Dessì & Alberto Quario GTUG Sardegna import play.api.mvc.Security trait Secured { private def username(request: RequestHeader) = request.session.get("user_id") private def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Application.login) def isAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username,onUnauthorized) { user => Action(request => f(user)(request)) } } object Application extends Controller with Secured { def index = isAuthenticated { userId => implicit request => Ok(html.index(userId)) } } 42
  • 43. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna • compiled as standard Scala functions • follow a simple naming convention views/index.scala.html ➡ views.html.index @(customer: Customer, orders: List[Order]) @title(text: String) = @{ text.split(' ').map(_.capitalize).mkString(" ") } <h1>@title(customer.name)</h1> <ul> @for(order <- orders) { <li>@order.getTitle()</li> } </ul> @defining(customer.name + " " + customer.surname) { fullName => <div>Regards @fullName</div> } 43
  • 44. REST Massimiliano Dessì & Alberto Quario GTUG Sardegna GET /api/reviews controllers.Reviews.list GET /api/reviews/count controllers.Reviews.count GET /api/reviews/:id controllers.Reviews.show(id: Int) import play.api.libs.json._ object Reviews extends Controller { import play.api.libs.functional.syntax._ def list = Action { request => case class Review(id: Int, text: String) Ok(toJson(Review.findAll)) } object Review { val reviews: List[Review] = def count = Action { request => List(Review(1, "hello"), Review(2, "codemotion")) Ok(toJson(Review.count)) } def findAll: Seq[Review] = reviews def show(id: Int) = Action { def count: Int = reviews.size Review.findById(id).map { review => Ok(toJson(review)) def findById(id: Int): Option[Review] = }.getOrElse(NotFound( reviews.find(_.id == id) toJson(Map("error" -> "Review with id %s not found". implicit val reviewReads = ( format(id))))) (__ "id").read[Int] and } (__ "text").read[String] } )(Review.apply _) implicit val creatureWrites = ( (__ "id").write[Int] and (__ "text").write[String] )(unlift(Review.unapply)) } 44
  • 45. Form Massimiliano Dessì & Alberto Quario GTUG Sardegna object Contacts extends Controller { case class Contact( val contactForm: Form[Contact] = Form( firstname: String, mapping( lastname: String, company: Option[String] "firstname" -> nonEmptyText, ) "lastname" -> nonEmptyText, "company" -> optional(text) )(Contact.apply)(Contact.unapply) ) def form = Action { Ok(html.contact.form(contactForm)) } def submit = Action { implicit request => contactForm.bindFromRequest.fold( errors => BadRequest(html.contact.form(errors)), contact => Ok(html.contact.summary(contact)) ) } 45
  • 46. Form /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna @(contactForm: Form[Contact]) @helper.form(action = routes.Contacts.submit) { <fieldset> <legend>General informations</legend> @inputText( contactForm("firstname"), '_label -> "First name" ) @inputText( contactForm("lastname"), '_label -> "Last name" ) @inputText( contactForm("company"), '_label -> "Company" ) </fieldset> <div class="actions"> <input type="submit" class="btn primary" value="Insert"> <a href="@routes.Application.index" class="btn">Cancel</a> </div> } 46
  • 47. Non-blocking IO Massimiliano Dessì & Alberto Quario GTUG Sardegna object Application extends Controller { def intensiveComputation(): Int = ... def index = Action { val futureInt = scala.concurrent.Future { intensiveComputation() } Async { futureInt.map(i => Ok(views.html.index("Got result: " + i))) } } } play.api.libs.ws.WS WS.url("http://example.com/feed").get() WS.url("http://example.com/item").post("content") 47
  • 48. Non-blocking IO /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna def race() = Action { Async { val start = System.currentTimeMillis() def getLatency(r: Any): Long = System.currentTimeMillis() - start val googleTime = WS.url("http://www.google.com").get().map(getLatency) val yahooTime = WS.url("http://www.yahoo.com").get().map(getLatency) val bingTime = WS.url("http://www.bing.com").get().map(getLatency) Future.sequence(Seq(googleTime, yahooTime, bingTime)).map { case times => Ok(Json.toJson(Map( "google" -> times(0), "yahoo" -> times(1), "bing" -> times(2), "total" -> getLatency(0)))) } } } {"google":343,"yahoo":3043,"bing":1608,"total":3048} 48
  • 49. Test Massimiliano Dessì & Alberto Quario GTUG Sardegna class ApplicationSpec extends Specification { "Application" should { "send 404 on a bad request" in { running(FakeApplication()) { route(FakeRequest(GET, "/boum")) must beNone } } "render the index page" in { running(FakeApplication()) { val home = route(FakeRequest(GET, "/")).get status(home) must equalTo(OK) contentType(home) must beSome.which(_ == "text/html") contentAsString(home) must contain ("Your new application is ready.") } } } } 49
  • 50. Test /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna class IntegrationSpec extends Specification { "Application" should { "work in a server" in { running(TestServer(3333)) { await(WS.url("http://localhost:3333").get).status must equalTo(OK) } } "work from within a browser" in { running(TestServer(3333), HTMLUNIT) { browser => browser.goTo("http://localhost:3333/") browser.pageSource must contain("Your new application is ready.") } } } } 50
  • 51. Deploy Massimiliano Dessì & Alberto Quario GTUG Sardegna 51
  • 52. Deploy /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna Welcome to Play 2.1.0! These commands are available: ----------------------------- classpath Display the project classpath. clean Clean all generated files. compile Compile the current application. console Launch the interactive Scala console (use :quit to exit). dependencies Display the dependencies summary. dist Construct standalone application package. exit Exit the console. h2-browser Launch the H2 Web browser. license Display licensing informations. package Package your application as a JAR. play-version Display the Play version. publish Publish your application in a remote repository. publish-local Publish your application in the local repository. reload Reload the current application build file. run <port> Run the current application in DEV mode. test Run Junit tests and/or Specs from the command line eclipse generate eclipse project file idea generate Intellij IDEA project file sh <command to run> execute a shell command start <port> Start the current application in another JVM in PROD mode. update Update application dependencies. 52
  • 53. Massimiliano Dessì & Alberto Quario GTUG Sardegna spray is an open-source toolkit for REST/HTTP and low-level network IO on top of Scala and Akka. aka Scala -IKEA VMWare and Ebay use spray for some internal projects 53
  • 54. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna class PingServiceActor extends Actor { def receive = { case HttpRequest(GET, "/ping", _, _, _) => sender ! HttpResponse(200, "PONG") } } 54
  • 55. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna path with name order => directive route get and put => are inner route ~ =>route concatenation class MyServiceActor extends Actor with Routing { def receive = receiveFromRoute { path("order" / HexIntNumber) { id => get { completeWith { "Received GET for order " + id } } ~ put { completeWith { "Received PUT for order " + id } } } } } 55
  • 56. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna trait LongerService extends HttpService with MyApp { val simpleCache = routeCache(maxCapacity = 1000, timeToIdle = Duration("30 min")) val route = { path("orders") { authenticate(BasicAuth(realm = "admin area")) { user => get { cache(simpleCache) { encodeResponse(Deflate) { complete { getOrdersFromDB } } } } ~ post { (decodeRequest(Gzip) | decodeRequest(NoEncoding)) { entity(as[Order]) { order => detachTo(singleRequestServiceActor) { complete { // ... write order to DB "Order received" } } } } } } } ~ 56
  • 57. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna pathPrefix("order" / IntNumber) { orderId => path("") { // method tunneling via query param (put | parameter('method ! "put")) { // form extraction from multipart or www-url-encoded forms formFields('email, 'total.as[Money]).as(Order) { order => complete { // complete with serialized Future result (myDbActor ? Update(order)).mapTo[TransactionResult] } } } ~ get { jsonpWithParameter("callback") { produce(instanceOf[Order]) { complete => ctx => processOrderRequest(orderId, complete) } } } } ~ 57
  • 58. Non-blocking IO Massimiliano Dessì & Alberto Quario GTUG Sardegna def race() { val start = System.currentTimeMillis() def getLatency(r: Any): Long = System.currentTimeMillis() - start val googleFuture = httpClient.ask(Get("http://www.google.com")) .mapTo[HttpResponse].map(getLatency) val yahooFuture = httpClient.ask(Get("http://www.yahoo.com")) .mapTo[HttpResponse].map(getLatency) val bingFuture = httpClient.ask(Get("http://www.example.com")) .mapTo[HttpResponse].map(getLatency) Future.sequence(Seq(googleFuture, yahooFuture, bingFuture)).map { case times => log.info( "google" + times(0) + " yahoo" + times(1) + " bing" + times(2) + " total: "+getLatency(0)) system.shutdown() // stops all actors } } 58
  • 59. Test Massimiliano Dessì & Alberto Quario GTUG Sardegna class DemoServiceSpec extends Specification with Specs2RouteTest with DemoService { def actorRefFactory = system "The DemoService" should { "return a greeting for GET requests to the root path" in { Get() ~> demoRoute ~> check { entityAs[String] must contain("Say hello") } } "return a 'PONG!' response for GET requests to /ping" in { Get("/ping") ~> demoRoute ~> check { entityAs[String] === "PONG!" } } "leave GET requests to other paths unhandled" in { Get("/kermit") ~> demoRoute ~> check { handled must beFalse } } "return a MethodNotAllowed error for PUT requests to the root path" in { Put() ~> sealRoute(demoRoute) ~> check { status === MethodNotAllowed entityAs[String] === "HTTP method not allowed, supported methods: GET" } } } } 59
  • 60. Massimiliano Dessì & Alberto Quario GTUG Sardegna Q&A 60
  • 61. Agenda Massimiliano Dessì & Alberto Quario GTUG Sardegna Thanks for your attention! Massimiliano: @desmax74 Alberto :@realrealbot 61