title: Play framework filter that modifies json request and response
body: <p>I'll appreciate if someone can throw pointers on how to modify the following play framework logging filter (ref. <a href="https://www.playframework.com/documentation/2.3.4/ScalaHttpFilters" rel="nofollow noreferrer">play filters</a>) to achieve the following:</p>
  
  <ul>
  <li>Print and modify the incoming json request body and http headers (e.g., for POST, PUT, &amp; PATCH)</li>
  <li>Print and modify the outgoing json response body and http headers</li>
  <li>A modification example can be injecting/replacing some token strings in the request and response body, e.g,</li>
  <li>REQUEST Json: {'a': 'REPLACE_ME', 'b': 'REPLACE_ME_TOO', 'c':'something'}</li>
  <li>RESPONSE Json: {'A': 'REPLACE_ME', 'Bb': 'REPLACE_ME_TOO', 'C':'anything'}</li>
  </ul>
  
  <hr>
  
  <pre><code>import play.api.Logger
  import play.api.mvc._
  import play.api.libs.concurrent.Execution.Implicits.defaultContext
  
  object LoggingFilter extends EssentialFilter {
    def apply(nextFilter: EssentialAction) = new EssentialAction {
      def apply(requestHeader: RequestHeader) = {
        val startTime = System.currentTimeMillis
        nextFilter(requestHeader).map { result =&gt;
          val endTime = System.currentTimeMillis
          val requestTime = endTime - startTime
          Logger.info(s"${requestHeader.method} ${requestHeader.uri}" +
            s" took ${requestTime}ms and returned ${result.header.status}")
          result.withHeaders("Request-Time" -&gt; requestTime.toString)
        }
      }
    }
  }
  </code></pre>
  
  <hr>
  
  <p>So far I have tried the following solution which is clearly ugly and brutal as it contains blocking calls and cryptic operators. I am still not sure how to re-inject the modified request body. (The presented solution incorporates code from <a href="https://jazzy.id.au/2012/11/06/iteratees_for_imperative_programmers.html" rel="nofollow noreferrer">2</a> and <a href="https://stackoverflow.com/questions/19825543/play-framework-inconsistent-filter-behaviour">3</a>.)</p>
  
  <pre><code>import play.api.libs.iteratee._
  import play.api.mvc._
  
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.{Await, Future}
  import scala.concurrent.duration.Duration
  
  class ReqResFilter extends EssentialFilter {
  
    def apply(next: EssentialAction) = new EssentialAction {
      def apply(requestHeader: RequestHeader): Iteratee[Array[Byte], Result] = {
        modifyRequest(next, requestHeader).map { result =&gt; modifyResponse(result)}
      }
    }
  
    def bytesToString: Enumeratee[Array[Byte], String] = Enumeratee.map[Array[Byte]] { bytes =&gt; new String(bytes)}
  
    def modifyRequest(nextA: EssentialAction, request: RequestHeader): Iteratee[Array[Byte], Result] = {
  
      def step(body: Array[Byte], nextI: Iteratee[Array[Byte], Result])(i: Input[Array[Byte]]):
      Iteratee[Array[Byte], Result] = i match {
        case Input.EOF =&gt;
          val requestBody = new String(body, "utf-8")
          val modRequestBody = requestBody.replaceAll("REPLACE_ME", "1224")
          println(s"modifyRequest:: Here is the request body ${modRequestBody}")
          Iteratee.flatten(nextI.feed(Input.EOF))
        case Input.Empty =&gt;
          Cont[Array[Byte], Result](step(body, nextI) _)
        case Input.El(e) =&gt;
          val curBody = Array.concat(body, e)
          Cont[Array[Byte], Result](step(curBody, Iteratee.flatten(nextI.feed(Input.El(e)))) _)
      }
  
      val nextIteratee: Iteratee[Array[Byte], Result] = nextA(request)
  
      Cont[Array[Byte], Result](i =&gt; step(Array(), nextIteratee)(i))
    }
  
    def modifyResponse(result: Result): Result = {
      val responseBodyFuture: Future[String] = result.body |&gt;&gt;&gt; bytesToString &amp;&gt;&gt; Iteratee.consume[String]()
      val responseBody = Await.result(responseBodyFuture, Duration.Inf)
      val modResponseBody = responseBody.replaceAll("REPLACE_ME", "1224")
      println(s"modifyResponse:: Here is the response body ${modResponseBody}")
      new Result(result.header, Enumerator(modResponseBody.getBytes)).withHeaders("New-Header" -&gt; "1234")
    }
  }
  </code></pre>