1

I am new to Scala, Spray and functional programming. And I am so sad that I still can not understand event the basic example of Spray RestAPI.

I have written the program according to the instructions given in this blog post. http://www.smartjava.org/content/first-steps-rest-spray-and-scala

And my Route function is as bellow.

  val aSimpleRoute =
    path("path1") {
      println("in path path1..")
      put {
        println("in path path1/put..")
        respondWithMediaType(MediaTypes.`text/html`) {
          complete {
            <h1>in path path1/put..</h1>
          }
        }
      } ~ get {
        println("in path path1/get..")
        respondWithMediaType(MediaTypes.`application/json`) {
          complete {
            <h1>in path path1/get..</h1>
          }
        }
      }
    } ~
  path("path2") {
    println("in path path2..")
    get {
      println("in path path2/get..")
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          <h1>in path path2/get..</h1>
        }
      }
    } ~ post {
      println("in path path2/post..")
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          <h1>in path path2/post..</h1>
        }
      }
    }
  }

Everything works as expected. But my problem is, when my programm started it will run through the receive function. See my output of println, when program started (before it handle any http request)

in path path1..
in path path1/put..
in path path1/get..
in path path2..
in path path2/get..
in path path2/post..
[INFO] [09/14/2015 12:56:01.364] [on-spray-can-akka.actor.default-dispatcher-4] [akka://on-spray-can/user/IO-HTTP/listener-0] Bound to localhost/127.0.0.1:8080

So I can not understand why the program comes into all it's possible call paths, when it started. And also, non of these println is reached when an HTTP request received.

Can anyone explain why ?

2 Answers2

2

You can find an explanation here: Understanding extractions

In short, non-leaf and non-parametrized (with no extraction) directives are executed only once when route is build. Leaf directive (like complete) is executed only if request is hitting directive's route. Parametrized directives (and everything inside them) are executed per request (as extracted parameter is different every time) - even if directive itself is coming after directive that already accepted this request.

In your case you've got printlns inside non-leaf and non-parametrized directives so they were executed only once on initialization. If you want them to be executed per acceptable request - just move them inside complete:

val aSimpleRoute =
  path("path1") {
    put {     
      respondWithMediaType(MediaTypes.`text/html`) {
        complete {
          println("in path path1/put..")
          <h1>in path path1/put..</h1>
        }
      }
    } ~ get {
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          println("in path path1/get..")
          <h1>in path path1/get..</h1>
        }
      }
    }
  } ~
  path("path2") {
    get {    
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          println("in path path2/get..")
          <h1>in path path2/get..</h1>
        }
      }
    } ~ post {
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          println("in path path2/post..")
          <h1>in path path2/post..</h1>
        }
    }
  }

Discussion is here

dk14
  • 22,206
  • 4
  • 51
  • 88
  • Thanks for providing the exact answer for my question. Is this behavior Spray specific or generally with Scala ?? – Janaka Priyadarshana Sep 18 '15 at 05:21
  • 1
    it's spray-specific; however it uses features of scala language, like lazy computation. For instance, the body of `complete` function comes as call-by-name parameter, which means that it (body) is practically a function with zero parameters, so it's execution might be delayed. That's why `println` inside `complete` acts differently. – dk14 Sep 18 '15 at 05:43
1

Well, you used "val" to declare spray routes, it is normal behavior because when you run your program, Scala initialize vals, if you will put "lazy val" instead of "val" you will see that you will get print when you will use this val explicitly.

For Example:

    val a = {
        println("val a initialization")
        "val a initialization"
      }
 
   lazy val b = {
        println("using of val b")
        "using of val b"
      }
    
      println("use of Val a " + a)
    
      println("use of val b  " + b)

Result:

val a initialization
use of Val a val a initialization
using of val b
use of val b  using of val b
Dmitri
  • 271
  • 2
  • 11