Spray rejection handler not detecting an existing path - scala

I have a file static.scala :
val staticRoute = {
path("") {
getFromResource("web/index.html")
} ~ pathPrefix("web") {
getFromResourceDirectory("web")
}
}
Another file a.scala :
val actionRoute = (handleRejections(rejectionHandler) & handleExceptions(exceptionHandler))
{
path("action" / "create") {
(put | post) {
implicit ctx => {
val xmlString = ctx.request.entity.asString
val actionObject = XML.loadString(xmlString).toAction
ActionService.write(actionObject)
sendResponse(StatusCodes.OK, APIResponseOK(Map("id" -> actionObject.id)))
}
}
}
}
My Base.scala contains the definition of the rejectionHandler :
val rejectionHandler = RejectionHandler {
case Nil => ctx => {
complete((StatusCodes.NotFound, "The Requested Resource was not found"))
}
case mcr : MissingCookieRejection =>ctx=> { //testing
complete(StatusCodes.BadRequest, "Missing cookie")
}
}
Both the files extend Base.scala which has the rejection handler defined in it. However on opening the correct port for the server ( localhost:8080 ) which corresponds to
path("")
in static.scala , the rejectionHandler still is going to case Nil and printing the message "The Requested Resource was not found" which should not be the case! Shouldn't it enter the handler if that path is not defined? If i comment out the rejectionHandler everything works as expected. Please help me out !

actionRoute will complete / because it doesn't have a path for it and does have a handleRejections. Which means it does have a route for / and actionRoute ~ staticRoute will never "fall through" to staticRoute.
You usually want to only do rejection handling at the very top level (or maybe within a pathPrefix, if you don't want other routes to use the same prefix). Move the handleRejections out of actionRoute and move it right up to the top level:
handleRejections(myHandler) {
actionsRoute ~ staticRoute
}

Related

How to count akkaHttp RejectionHandler rejections and successes?

I am trying to count rejects that were returned by RejectionHandler
I guess the way I doing this now is not the best one, or even incorrect. I am just trying to invoke the incremental method in my database, in each of the handled cases.
implicit def rejectionHandler: RejectionHandler =
RejectionHandler.newBuilder()
.handle {
case MissingCookieRejection(cookieName) =>
requestInfoEntry.incrementRjectedNum
complete(HttpResponse(BadRequest, entity = "No cookies, no service!!!"))
}
.handle {
case AuthorizationFailedRejection =>
requestInfoEntry.incrementRjectedNum
complete((Forbidden, "You're out of your depth!"))
}
.handle {
case ValidationRejection(msg, _) =>
requestInfoEntry.incrementRjectedNum
complete((InternalServerError, "That wasn't valid! " + msg))
}
.handleAll[MethodRejection] { methodRejections =>
requestInfoEntry.incrementRjectedNum//todo sideeffect ??
val names = methodRejections.map(_.supported.name)
complete((MethodNotAllowed, s"Can't do that! Supported: ${names mkString " or "}!"))
}
.handleNotFound {
requestInfoEntry.incrementRjectedNum
complete((NotFound, "Not here bldghad!"))
}
.result()
While I "visit my unfound page", Akka HTTP returns me a right response: "Not here bldghad!" every time I refresh browser on not existed web-page. But when I check my database, I see the only one increment. Can I do this way as I do at all? (I need to count successes too)
PS Maybe I need to work with status codes and do not use side effects. But what is the best place where I can do it? I have a lot of controllers and do not want to intercept this in every controller)
Can I globally intercept responses somewhere?
I've done it this way, hope it would be useful
def rejectionHandlerWithCounter: RejectionHandler = { (rejections: Seq[Rejection]) =>
requestInfoEntry.incrementRjectedNum
Some(complete((StatusCodes.Forbidden)))
}

cannot get rest service

This drives me crazy, I have 2 http requests in a sample application:
open class RestController : Controller() {
val api = Rest()
init {
api.baseURI = "http://127.0.0.1:5059/"
}
}
class PendingCtlr : RestController() {
fun load(): ObservableList<PendingEntity> {
val txt = api.get("pendings").list()
val temp = txt.toModel<PendingEntity>()
return temp.observable()
}
}
class ConfirmedCtrl : RestController() {
fun load(id: Long): ObservableList<ConfirmedEntity> {
val li= api.get("confirmeds").list()
val temp = li.toModel<ConfirmedEntity>()
return temp.observable()
}
}
The first one works, the second one doesn't even hit the application level, it gets rejected with 400 BadRequest by my backend (Werkzeug).
I see absolutely no difference in both functions, and I can call both routes from my Swagger, as well as from python as well as from curl! Could someone please advise at least where to look for debug?
EDIT: The problem was on server side -_- Solved

Scenario outline in scalatest

I´m implementing my test framework using scalatest and I think I made a mistake using this framework instead of Cucumber
I´m trying to use some sort of features as Scenario outline of cucumber to avoid break DRY
here my problem
feature("Features of mus client") {
scenario("GET message with mus client") {
Given("a Musin message")
val config: Properties = new Properties
config.put("method", "POST")
config.put("encoding", "UTF-8")
config.put("uri", "http://localhost:9083/musClient")
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(READ))
Then("The message it´s returned successfully")
assert(response != null)
}
scenario("POST message with mus client") {
Given("a Musin message")
val config: Properties = new Properties
config.put("method", "POST")
config.put("encoding", "UTF-8")
config.put("uri", "http://localhost:9083/musClient")
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(CREATE))
Then("The message it´s returned successfully")
assert(response != null)
}
As you can see I have two scenarios where the 99% it´s the same steps but a variable that change the request.
Any idea how to do this elegant and efficient in scalatest
And I'm one of those too who chose scalatest over cucumber, cucumber was too much for me(ME) to write the feature file, and then come back to scala/java file and change accordingly. Maintain two files. I actually played cucumber java, scala cucumber might be more fluent. Anyway, I am liking scalatest so far for all my unit testing, component testing and the flow testing.
In case like yours if the properties are common for multiple scenarios and you won't mutate inside scenarios then defining as common property would be fine, as below.
class E2E extends FeatureSpec with GivenWhenThen {
feature("Features of mus client") {
Given("http config")
val config: Properties = new Properties(){{
put("method", "POST") //you are doing POST in both case by the way
put("encoding", "UTF-8")
put("uri", "http://localhost:9083/musClient")
}}
scenario("GET message with mus client") {
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(READ))
Then("The message it´s returned successfully")
assert(response != null)
}
scenario("POST message with mus client") {
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(CREATE))
Then("The message it´s returned successfully")
assert(response != null)
}
}
}
But, You might also want to use property based testing for the only part that changes, property based check was very fluent and readable in spock framework.
property based check in scalatest would look like below where I am testing for two different input parameters. (you neeed import org.scalatest.prop.TableDrivenPropertyChecks._)
class TestE2E extends FeatureSpec with GivenWhenThen {
val requestResponse =
Table(
("request", "response"),
( "GET", "GET-something"),
( "POST", "POST-something")
)
feature("testMe") {
forAll (requestResponse) { (givenRequestFromTable: String, expectedResponseFromTable: String) =>
scenario("for input " + givenRequestFromTable) {
When("input is " + givenRequestFromTable)
val output = testMe(input = givenRequestFromTable)
Then("responseFromTable has something appended to it")
assert(output == expectedResponseFromTable)
}
}
}
def testMe(input: String) : String = {
input + "-something"
}
}
There would be two scenarios based on two given properties,
And for you, the tests would be something as below with property based, hope there's no compile error :)
import org.scalatest.prop.TableDrivenPropertyChecks._
import org.scalatest.prop.Tables.Table
import org.scalatest.{FeatureSpec, GivenWhenThen}
class PaulWritesSpecs extends FeatureSpec with GivenWhenThen {
val requestResponse =
Table(
("httpMethod", "requestType"),
("GET", READ),
("POST", CREATE))
feature("Features of mus client") {
forAll(requestResponse) { (httpMethod: String, requestType: String) => {
scenario(s"$httpMethod message with mus client") {
Given("http config")
val config: Properties = new Properties() {{
put("method", httpMethod)
put("encoding", "UTF-8")
put("uri", "http://localhost:9083/musClient")
}}
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(requestType))
Then("The message it´s returned successfully")
assert(response != null)
}
}
}
}
}

Execute some logic asynchronously in spray routing

Here is my simple routing application:
object Main extends App with SimpleRoutingApp {
implicit val system = ActorSystem("my-system")
startServer(interface = "0.0.0.0", port = System.getenv("PORT").toInt) {
import format.UsageJsonFormat._
import spray.httpx.SprayJsonSupport._
path("") {
get {
complete("OK")
}
} ~
path("meter" / JavaUUID) {
meterUUID => pathEnd {
post {
entity(as[Usage]) {
usage =>
// execute some logic asynchronously
// do not wait for the result
complete("OK")
}
}
}
}
}
}
What I want to achieve is to execute some logic asynchronously in my path directive, do not wait for the result and return immediately HTTP 200 OK.
I am quite new to Scala and spray and wondering if there is any spray way to solve this specific problem. Otherwise I would go into direction of creating Actor for every request and letting it to do the job. Please advice.
There's no special way of handling this in spray: simply fire your async action (a method returning a Future, a message sent to an actor, whatever) and call complete right after.
def doStuffAsync = Future {
// literally anything
}
path("meter" / JavaUUID) { meterUUID =>
pathEnd {
post {
entity(as[Usage]) { usage =>
doStuffAsync()
complete("OK")
}
}
}
}
Conversely, if you need to wait for an async action to complete before sending the response, you can use spray-specific directives for working with Futures or Actors.

spray and actor non deterministic tests

Helo,
at the beginning i wold like to apologize for my english :)
akka=2.3.6
spray=1.3.2
scalatest=2.2.1
I encountered strange behavior of teting routes, which asks actors in handleWith directive,
I've route with handleWith directive
pathPrefix("firstPath") {
pathEnd {
get(complete("Hello from this api")) ~
post(handleWith { (data: Data) =>{ println("receiving data")
(dataCalculator ? data).collect {
case Success(_) =>
Right(Created -> "")
case throwable: MyInternalValidatationException =>
Left(BadRequest -> s"""{"${throwable.subject}" : "${throwable.cause}"}""")
}
}})
}
}
and simple actor wchich always responds when receive object Data and has own receive block wrapped in LoggingReceive, so I should see logs when message is receiving by actor
and i test it using (I think simple code)
class SampleStarngeTest extends WordSpec with ThisAppTestBase with OneInstancePerTest
with routeTestingSugar {
val url = "/firstPath/"
implicit val routeTestTimeout = RouteTestTimeout(5 seconds)
def postTest(data: String) = Post(url).withJson(data) ~> routes
"posting" should {
"pass" when {
"data is valid and comes from the identified user" in {
postTest(correctData.copy(createdAt = System.currentTimeMillis()).asJson) ~> check {
print(entity)
status shouldBe Created
}
}
"report is valid and comes from the anonymous" in {
postTest(correctData.copy(createdAt = System.currentTimeMillis(), adid = "anonymous").asJson) ~> check {
status shouldBe Created
}
}
}
}
}
and behavior:
When I run either all tests in package (using Intellij Idea 14 Ultimate) or sbt test I encounter the same results
one execution -> all tests pass
and next one -> not all pass, this which not pass I can see:
1. fail becouse Request was neither completed nor rejected within X seconds ( X up tp 60)
2. system console output from route from line post(handleWith { (data: Data) =>{ println("receiving data"), so code in handleWith was executed
3. ask timeout exception from route code, but not always (among failed tests)
4. no logs from actor LoggingReceive, so actor hasn't chance to respond
5. when I rerun teststhe results are even different from the previous
Is there problem with threading? or test modules, thread blocking inside libraries? or sth else? I've no idea why it isn't work :(