joanOfArc
joanOfArc

Reputation: 467

Switching from Scalatra to Spray : Handling notFound and errors in spray?

We were Scalatra users. Everytime we would create a servlet , we would extend our BaseServlet which extend ScalatraBase :

    trait BaseServlet extends ScalatraFilter with ScalateSupport with FlashMapSupport  {

      /**
       * Returns the request parameter value for the given argument.
       */
      def getParam(key:String)(implicit request: HttpServletRequest): Option[String] = Option(request.getParameter(key))

      notFound {
        // If no route matches, then try to render a Scaml template
        val templateBase = requestPath match {
          case s if s.endsWith("/") => s + "index"
          case s => s
        }
        val templatePath = "/WEB-INF/templates/" + templateBase + ".scaml"
        servletContext.getResource(templatePath) match {
          case url: URL =>
            contentType = "text/html"
            templateEngine.layout(templatePath)
          case _ =>
            filterChain.doFilter(request, response)
        }
      }

      error {
        case e:ControlThrowable => throw e
        case e:Throwable =>
          val errorUID:String =  UUID.randomUUID.getLeastSignificantBits.abs.toString
          Log.logger(Log.FILE.ALL_EXCEPTIONS).error("#"+ errorUID + " -- " + e.getMessage + e.getStackTraceString)
          contentType = "application/json"
          response.setStatus(500)
          JsonUtility.toJSONString( Map("message" ->  ("Server Error # "+ errorUID  ) ,  "reason" -> e.getMessage ))
      }
}

EDIT: I want to abstract it out. I mean I want to add all the error and rejection handling functionalities in my BaseServlet and then extend it ( in say AnyServlet) . So if AnyServlet has an unfound path or has an exception thrown somewhere it is automatically handled by the BaseServlet. Is there something similar in Spray which can handle my paths not found and errors in a similar fashion? Thanks in advance!

Upvotes: 2

Views: 375

Answers (2)

lmm
lmm

Reputation: 17431

You don't need to "abstract it out" because in spray you don't have distinct "servlets" - you just have a route, which may call other routes:

class UserRoute {
  val route: Route = ...
}
class DepartmentRoute {
  val route: Route = ...
}
class TopLevelRoute(userRoute: UserRoute, departmentRoute: DepartmentRoute) {
  val route: Route =
    (handleRejections(MyRejHandler) & handleExceptions(MyExHandler)) {
      path("users") {
        userRoute.route
      } ~
      path("departments") {
        departmentRoute.route
      }
    }
}

You can put the handler in TopLevelRoute and it will apply to anything in UserRoute or DepartmentRoute. A spray HttpServiceActor only handles a single route, not a bunch of different "controllers" - it's up to you how you combine all your routes into a single route.

Upvotes: 1

Vishal John
Vishal John

Reputation: 4382

You have to define a custom RejectionHandler.

In your application define this RejectionHandler as an implicit val.

import spray.routing.RejectionHandler

private implicit val notFoundRejectionHandler = RejectionHandler {
  case Nil => {
     // If no route matches, then try to render a Scaml template...
  }
}

I figured it out from the spray github spec

Upvotes: 1

Related Questions