scalatry-catchsprayspray-dsl

Handle services returning Try values in Spray


I am working on a codebase where calling my Spray API need to synchronously call a service that returns a Try which Spray need to format and return over HTTP.

My initial attempt looked like this :

// Assume myService has a run method that returns a Try[Unit]
lazy val myService = new Service() 

val routes = 
  path("api") {
    get {
      tryToComplete {
        myService.run()
      } 
    }
  } ~ 
  path("api" / LongNumber) { (num: Long) =>
    get {
      tryToComplete {
        myService.run(num)
      } 
    }
  }

def tryToComplete(result: => Try[Unit]): routing.Route = result match {
  case Failure(t) => complete(StatusCodes.BadRequest, t.getMessage)
  case Success(_) => complete("success")
}

However this caused myService.run() to be called when the application started. I am not sure why this method was called as there was no HTTP call made.

So I have two questions :

  1. Why is my service being called as part of initialising the routes?
  2. What is the cleanest way to handle this case? Imagine that there are a few other end points following a similar pattern. So I need to be able to handle this consistently.

Solution

  • The way I solved this was do do the following :

    lazy val myService = new Service() 
    
    val routes = 
      path("api") {
        get {
          complete {
            handleTry {
              myService.run()
            }
          } 
        }
      } ~ 
      path("api" / LongNumber) { (num: Long) =>
        get {
          complete {
             handleTry {
              myService.run(num)
            } 
          }
        }
      }
    
    private def handleTry(operation: Try[_]):HttpResponse = operation match {
      case Failure(t) => 
        HttpResponse(status = StatusCodes.BadRequest, entity = t.getMessage)
      case Success(_) => 
        HttpResponse(status = StatusCodes.OK, entity = successMessage)
    }