It’s not a rage session, just a love/hate relationship.
in build.sbt
"io.spray" %% "spray-routing" % "1.3.3",
"io.spray" %% "spray-can" % "1.3.3",
"com.typesafe.akka" %% "akka-actor" % "2.4.1" //2.3.3 ?
Actor
class YourActor extends HttpService with Actor {
def actorRefFactory = context
def receive = runRoute(
complete{
"Go home world!"
})
}
Server
object Boot extends App{
private val system: ActorSystem = ActorSystem("system")
/* could be implicit */
private val actorRef: ActorRef =
system.actorOf(Props(classOf[YourActor]))
IO(Http)(system) ! Http.Bind(
actorRef,
interface = "localhost",
port = 7771)
}
"io.spray" %% "spray-testkit" % "1.3.3" % "test"
specs2
"org.specs2" %% "specs2-core" % "2.4.17" % "test"
class Spec
extends org.spec2.Specification
with Directives {
"Spec group " >> {
"Spec" >> {
Get("/nowhere") ~>
{ _ => complete {"ok"}} ~>
check {
response.status.isSuccess must beTrue
}
}
}
}
scalatest
"org.scalatest" %% "scalatest" % "2.2.6" % "test"
class Spec
extends FreeSpec
with Matchers
with Directives
with ScalatestRouteTest {
"Spec Group" - {
"spec" in {
Get("/ping") ~>
complete{"ok"} ~>
check{
response.status.isSuccess shouldBe (true)
}
}
}
}
Tested here is the actual testing.
You would, usually, test your routes (say they are called someRoutes
)
by writing ~> someRoutes
instead of that complete
up there.
To test response content use responseAs
(requires Unmarshaller
for a given type in the scope):
responseAs[String] === "ok"
is accomplished with the plugin called sbt-revolver
.
It will recompile and redeploy on every code change.
addSbtPlugin("io.spray" % "sbt-revolver" % "0.8.0")
Forking jvm when running spray
also, to forward stdin
to a forked process add
connectInput in run := true
complete
attempts to transform the result you provided to HttpResponse
pathPrefix
filters paths based on their prefix
path
attempts to match a complete remaining path
Segment
matches any segment
unmatchedPath
provides you with the remaining unmatched path to complete
with
get
post
put
delete
matches with the method
parameter
(s)
extract query parameters from the path
entity(as[SomeClass])
attempts to unmarshall an incoming request as an instance of SomeClass
getFromBrowseableDirectory
complete with given directorty
detach
! detaches an execution of your code from neverendnessness…
pathPrefix("service") {
path("entity" / Segment) { id =>
get {
complete {
s"you requested $id"
}
}
} ~
path("entity") {
get {
parameters("id") { mId =>
complete {
s"your query id is $id"
}
}
}
}
}
pathEndOrSingleSlash{
getFromResource("index.html")
} ~ pathPrefix("assets"){
getFromResourceDirectory("assets")
}
Add an implicit Marshaller/Unmarshaller to the scope
trait Marshallers {
private val ct = spray.http.ContentTypeRange.*
protected val jsonSerialization: Serialization
implicit val msUnmarshaller = Unmarshaller[MessageType](ct) {
case HttpEntity.NonEmpty(contentType, data) =>
jsonSerialization
.deserialize[MessageType](data.asString)
}
}
define:
protected def authenticator(
userPass: Option[UserPass]): Future[Option[String]] =
Future {
userPass.flatMap {
case UserPass("admin", "multipass") => Some("xyz")
case _ => None
}
}
then pass it to the authenticate
directive passably like this:
authenticate(BasicAuth(authenticator _, "realm"))
runRoute
accepts one implicitly
implicit val divByZeroHandler = ExceptionHandler {
case _: Throwable =>
complete(StatusCodes.BadRequest, "Anything could happen!")
}
Almost the same as Exceptions
implicit val totallyMissingHandler = RejectionHandler {
case Nil /* secret code for path not found */ =>
complete(StatusCodes.NotFound,
"Oh man, what you are looking for is long gone.")
}
Cannot support TLS_RSA_WITH_AES_256_CBC_SHA with currently installed providers
IO(Http) ! HttpRequest(POST,
Uri(somePath),
entity = HttpEntity(someJson))
Path can be constructed with Uri.Path
There are also shorthands for Get
, Post
, Put
. Query params are added with the withQuery
method on Uri
.
You may have already noticed this is used in the test example above.
When you get
could not find implicit value for parameter um:
spray.httpx.unmarshalling.FromRequestUnmarshaller
but you already have
implicit val yourStupidClassUnmarshaller =
Unmarshaller[IrrelevantEntity]() {
case HttpEntity.NonEmpty(contentType, data) =>
superObjectHandler.deserialize[IrrelevantEntity](data)
}
If you have everything in one file make sure that you define an implicit before its usage, even if its in a different trait.
But the path seems fine
try adding the / at start of the path ...
CAUSED BY java.lang.ClassNotFoundException: spray.testkit.RouteTest
When trying to test authorization.
ArrayIndexOutOfBoundsException: : 59704 (BytecodeReadingParanamer.java:452)
[error] found : spray.routing.directives.NameReceptacle[the.Clazz]
[error] required: spray.routing.directives.ParamDefMagnet
editor -> Code Style -> multi-line strings -> Add/Insert margin ….
comments powered by Disqus