added Adam's talk about spray.io

This commit is contained in:
Jakub Fojtl
2014-04-25 13:07:44 +02:00
parent 1157dc4da3
commit 9ef8ef26b6
18 changed files with 563 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
███████╗██████╗ ██████╗ █████╗ ██╗ ██╗██╗ ██████╗
██╔════╝██╔══██╗██╔══██╗██╔══██╗╚██╗ ██╔╝██║██╔═══██╗
███████╗██████╔╝██████╔╝███████║ ╚████╔╝ ██║██║ ██║
╚════██║██╔═══╝ ██╔══██╗██╔══██║ ╚██╔╝ ██║██║ ██║
███████║██║ ██║ ██║██║ ██║ ██║██╗██║╚██████╔╝
╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═════╝
( ( ( ( )
)\ )\ ) ) ) )\))( ' ) ( ( /( (
((((_)( (()/( ( /( ( ((_)()\ ) ( /( )( ( )\()))\
)\ _ )\ ((_)))(_)) )\ ' _(())\_)() )(_))(()\ )\ ((_)\((_)
(_)_\(_) _| |((_)_ _((_)) \ \((_)/ /((_)_ ((_)((_)| |(_)(_)
/ _ \ / _` |/ _` || ' \() \ \/\/ / / _` || '_|(_-<| / / | |
/_/ \_\\__,_|\__,_||_|_|_| \_/\_/ \__,_||_| /__/|_\_\ |_|
_____ _ _ _____
|_ _|___ ___| |_ ___ ___| |___ ___ _ _ | | |___ _ _ ___
| | | -_| _| | | . | | . | . | | | | | . | | | _|
|_| |___|___|_|_|_|_|___|_|___|_ |_ | |__|__|___|___|_|
|___|___|

View File

@@ -0,0 +1,8 @@
* What is Spray.IO?
"Open source toolkit for building REST/HTTP-based
integration layers on top of Scala and Akka"
* Elegant & high-performance HTTP, using Actors
* "Acquired" by Akka

View File

@@ -0,0 +1,7 @@
Plan:
* code a REST service
* code a test
* (code a client)

View File

@@ -0,0 +1,9 @@
About me
* coder @ [SoftwareMill](http://www.softwaremill.com)
* open-source: Envers, ElasticMQ, MacWire, Veripacks
* [blog](http://www.warski.org)
* [twitter](@adamwarski)

View File

@@ -0,0 +1,22 @@
.___________. __ __ ___ .__ __. __ ___
| || | | | / \ | \ | | | |/ /
`---| |----`| |__| | / ^ \ | \| | | ' /
| | | __ | / /_\ \ | . ` | | <
| | | | | | / _____ \ | |\ | | . \
|__| |__| |__| /__/ \__\ |__| \__| |__|\__\
____ ____ ______ __ __
\ \ / / / __ \ | | | |
\ \/ / | | | | | | | |
\_ _/ | | | | | | | |
| | | `--' | | `--' |
|__| \______/ \______/
* http://www.spray.io
* http://www.warski.org
* https://github.com/adamw/spray-tutorial
* @adamwarski

View File

@@ -0,0 +1,23 @@
package com.softwaremill.spray
import org.json4s.native.Serialization
import org.json4s.native.Serialization._
import org.json4s.ShortTypeHints
trait Printer
case class LaserPrinter(color: Boolean) extends Printer
case class NeedlePrinter(manufacturer: String, pins: Int) extends Printer
object Printer {
val somePrinters = List[Printer](
NeedlePrinter(manufacturer = "Epson", pins = 12),
NeedlePrinter(manufacturer = "Epson", pins = 24),
LaserPrinter(color = false)
)
private implicit val formats = Serialization.formats(ShortTypeHints(List(classOf[LaserPrinter], classOf[NeedlePrinter])))
def toJson(printer: List[Printer]): String = writePretty(printer)
def toJson(printer: Printer): String = writePretty(printer)
}

View File

@@ -0,0 +1,27 @@
package com.softwaremill.spray.client
import spray.http._
import spray.client.pipelining._
import akka.actor.ActorSystem
object ClientComplete extends App {
implicit val system = ActorSystem()
import system.dispatcher
val pipeline = sendReceive
val securePipeline = addCredentials(BasicHttpCredentials("adam", "1234")) ~> sendReceive
val result = securePipeline(Get("http://localhost:8080/list/all"))
result.foreach { response =>
println(s"Request completed with status ${response.status} and content:\n${response.entity.asString}")
}
pipeline(Post("http://localhost:8080/printer/add/needle?manufacturer=Canon&pins=10"))
Thread.sleep(1000L)
system.shutdown()
system.awaitTermination()
}

View File

@@ -0,0 +1,18 @@
package com.softwaremill.spray.server
import akka.actor.ActorSystem
import spray.routing.SimpleRoutingApp
object Step1Complete extends App with SimpleRoutingApp {
implicit val actorSystem = ActorSystem()
startServer(interface = "localhost", port = 8080) {
get {
path("hello") {
complete {
"Welcome to the Land of PrinTers (LPT)!"
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
package com.softwaremill.spray.server
import akka.actor.ActorSystem
import spray.routing.SimpleRoutingApp
import com.softwaremill.spray.Printer
import spray.http.MediaTypes
object Step2Complete extends App with SimpleRoutingApp {
implicit val actorSystem = ActorSystem()
var plentyOfPrinters = Printer.somePrinters
startServer(interface = "localhost", port = 8080) {
get {
path("hello") { ctx =>
ctx.complete("Welcome to the Land of PrinTers (LPT)!")
}
} ~
get {
path("list" / "all") {
respondWithMediaType(MediaTypes.`application/json`) {
complete {
Printer.toJson(plentyOfPrinters)
}
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
package com.softwaremill.spray.server
import akka.actor.ActorSystem
import spray.routing._
import com.softwaremill.spray._
import spray.http.MediaTypes
import com.softwaremill.spray.NeedlePrinter
object Step3Complete extends App with SimpleRoutingApp {
implicit val actorSystem = ActorSystem()
var plentyOfPrinters = Printer.somePrinters
def getJson(route: Route) = get {
respondWithMediaType(MediaTypes.`application/json`) { route }
}
startServer(interface = "localhost", port = 8080) {
get {
path("hello") { ctx =>
ctx.complete("Welcome to the Land of PrinTers (LPT)!")
}
} ~
getJson {
path("list" / "all") {
complete {
Printer.toJson(plentyOfPrinters)
}
}
} ~
getJson {
path("printer" / IntNumber / "details") { index =>
complete {
Printer.toJson(plentyOfPrinters(index))
}
}
} ~
post {
path("printer" / "add" / "needle") {
parameters("manufacturer"?, "pins".as[Int]) { (manufacturer, pins) =>
val newPrinter = NeedlePrinter(manufacturer.getOrElse("Epson"), pins)
plentyOfPrinters = newPrinter :: plentyOfPrinters
complete {
"OK"
}
}
}
}
}
}

View File

@@ -0,0 +1,89 @@
package com.softwaremill.spray.server
import akka.actor.{Props, Actor, ActorSystem}
import spray.routing._
import com.softwaremill.spray._
import spray.http.MediaTypes
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import com.softwaremill.spray.NeedlePrinter
object Step4Complete extends App with SimpleRoutingApp {
implicit val actorSystem = ActorSystem()
var plentyOfPrinters = Printer.somePrinters
implicit val timeout = Timeout(1.second)
import actorSystem.dispatcher
val helloActor = actorSystem.actorOf(Props(new HelloActor()))
val inkActor = actorSystem.actorOf(Props(new InkActor()))
def getJson(route: Route) = get {
respondWithMediaType(MediaTypes.`application/json`) { route }
}
lazy val printerRoute = {
get {
path("hello") { ctx =>
helloActor ! ctx
}
} ~
getJson {
path("list" / "all") {
complete {
Printer.toJson(plentyOfPrinters)
}
}
} ~
getJson {
path("printer" / IntNumber / "details") { index =>
complete {
Printer.toJson(plentyOfPrinters(index))
}
}
} ~
post {
path("printer" / "add" / "needle") {
parameters("manufacturer"?, "pins".as[Int]) { (manufacturer, pins) =>
val newPrinter = NeedlePrinter(manufacturer.getOrElse("Epson"), pins)
plentyOfPrinters = newPrinter :: plentyOfPrinters
complete {
"OK"
}
}
}
}
}
lazy val supplyRoute = {
get {
path("supply" / "ink") {
complete {
(inkActor ? GetInkSupply).mapTo[Int]
.map(s => s"The supply of the ink is $s")
}
}
}
}
startServer(interface = "localhost", port = 8080) {
printerRoute ~ supplyRoute
}
class HelloActor extends Actor {
override def receive = {
case ctx: RequestContext => ctx.complete("Welcome to the Land of PrinTers (LPT)!")
}
}
class InkActor extends Actor {
private val inkSupply = 10
override def receive = {
case GetInkSupply => sender ! inkSupply
}
}
object GetInkSupply
}

View File

@@ -0,0 +1,15 @@
package com.softwaremill.spray.server
import org.scalatest.{FlatSpec, ShouldMatchers}
import spray.testkit.ScalatestRouteTest
import spray.routing.Directives
class Step4CompleteTest extends FlatSpec with ShouldMatchers
with ScalatestRouteTest with Directives {
it should "work" in {
Get("/hello") ~> Step4Complete.printerRoute ~> check {
responseAs[String] should include ("LPT")
}
}
}