com.compstak.models.Comp
package com.compstak.models
import com.github.nscala_time.time.Imports._
case class Comp(id: Int, createdAt: DateTime)
com.compstak.models.Market
package com.compstak.models
import com.github.nscala_time.time.Imports._
case class Market(id: Int, name: String, createdAt: DateTime)
com.compstak.server.Boot
package com.compstak.server
import akka.actor.{ActorSystem, Props}
import akka.io.IO
import spray.can.Http
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import com.compstak.api.service.ApiServiceActor
object Boot extends App {
// we need an ActorSystem to host our application in
implicit val system = ActorSystem("on-spray-can")
// create and start our service actor
val service = system.actorOf(Props[ApiServiceActor], "api-service")
implicit val timeout = Timeout(5.seconds)
// start a new HTTP server on port 8080 with our service actor as the handler
IO(Http) ? Http.Bind(service, interface = "localhost", port = 8080)
}
com.compstak.server.service.PoorService
package com.compstak.server.service
import akka.actor.Actor
import spray.routing._
// this trait defines our service behavior independently from the service actor
trait PoorService extends HttpService
// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
abstract class ServiceActor extends Actor with PoorService {
// the HttpService trait defines only one abstract member, which
// connects the services environment to the enclosing actor or test
def actorRefFactory = ???
// this actor only runs our route, but you could add
// other things here, like request stream processing
// or timeout handling
def receive = ???
}
com.compstak.api.service.ApiService
package com.compstak.api.service
import akka.actor.Actor
import spray.http._
import com.compstak.api._
trait ApiService extends CompsApi with MarketsApi
class ApiServiceActor extends Actor with ApiService {
def actorRefFactory = context
def receive = runRoute {
compsApiRoute ~ marketsApiRoute
}
}
com.compstak.api.CompsApi.scala
package com.compstak.api
import com.github.nscala_time.time.Imports.DateTime
import play.api.libs.json._
import com.compstak.server.marshalling.JsonSupport
import com.compstak.server.service.PoorService
import com.compstak.models.Comp
trait CompsApi extends PoorService with JsonSupport {
implicit val compWrites: Writes[Comp] = Json.writes[Comp]
/*
* GET /v1/comps
* POST /v1/comps
* PUT /v1/comps/:comp_id
* DELETE /v1/comps/:comp_id
* PATCH (?)
*
*/
val compsApiRoute = {
pathPrefix("v1" / "comps") {
pathEnd {
get {
complete {
Seq(new Comp(1, new DateTime))
}
} ~
post {
respondWithStatus(201) { // 201 Created
complete {
new Comp(201, new DateTime)
}
}
}
} ~
path(IntNumber) { compId =>
put {
complete {
new Comp(44, new DateTime)
}
} ~
delete {
complete {
new Comp(1, new DateTime)
}
}
}
}
}
}
com.compstak.api.MarketsApi
package com.compstak.api
import com.github.nscala_time.time.Imports.DateTime
import play.api.libs.json._
import com.compstak.server.service.PoorService
import com.compstak.server.marshalling.JsonSupport
import com.compstak.models.Market
trait MarketsApi extends PoorService with JsonSupport {
implicit val marketWrites: Writes[Market] = Json.writes[Market]
/*
* GET /v1/markets
* POST /v1/markets
* PUT /v1/markets/:market_id
* DELETE /v1/markets/:market_id
* PATCH (?)
*
*/
val marketsApiRoute = {
pathPrefix("v1" / "markets") {
pathEnd {
get {
complete {
Seq(new Market(1, "New York City", new DateTime), new Market(2, "Chicago", new DateTime), new Market(3, "Dallas", new DateTime))
}
} ~
post {
respondWithStatus(201) { // 201 Created
complete {
new Market(201, "Bay Area", new DateTime)
}
}
}
} ~
path(IntNumber) { marketId =>
put {
complete {
new Market(44, "Minneapolis", new DateTime)
}
} ~
delete {
complete {
new Market(1, "Philadelphia", new DateTime)
}
}
}
}
}
}
com.compstak.server.marshalling.JsonSupport
package com.compstak.server.marshalling
import spray.httpx.PlayJsonSupport
trait JsonSupport extends PlayJsonSupport // allows switching marshaller at any time
I thought spray was supposed to completely hide actors from us?
I really dislike this route syntax we would have to further abstract out some of our own directives.