Search code examples
scalaakka-http

Akka Http map response on rejection discarded


I currently do a logging operation using mapResponse, as well as utilise the setCookie directive to perform a token rotation. However when a reject is called it disregards all previous mapResponse calls. Is there a way for this not to happen?

Here is a super simple illustrative example where the set cookie is dropped:

  get{
    setCookie(HttpCookie("Test", "Value")) {
      reject(MalformedRequestContentRejection("Bad content", new Exception("Pants")))
    }
  }

Solution

  • So one confusing thing about akka-http is there's 3 possible ways a route can be completed. Either Complete(httpResonse), Reject(rejection) or with an exception. mapResponse only maps in the Complete case.

    You can use handleRejections or handleException to convert Rejections/Exceptions into a Complete with a Response.

    If you don't, the framework will use its default mappers, which is happening after all your directives have already finished (too late for your mapResponse call).

    Have your mapResponse directive outside of handleExceptions/handleRejections so that you will be dealing with a Response object, and not exceptions/rejections reasons.

    import akka.http.scaladsl.server.Directives._
    
    mapResponse(loggingMethodHere) {
      handleExceptions(exceptionHandler) {
        handleRejections(rejectionHandler) {
          complete("your logic here")
        }
      }
    }
    

    Alternatively, if you're not worried about catching Exceptions, you can use mapRouteResult to handle the Complete and the Rejected cases.

    mapRouteResult {
        case Complete(response) =>
          log.info(s"Logging responses $response")
          Complete(response)
        case Rejected(rejects) =>
          log.info(s"route rejected with $rejects")
          Rejected(rejects)
      }