I am new to Scala. As mentioned in play framework official documentation in https://www.playframework.com/documentation/2.3.x/ScalaHttpFilters :
Play provides a lower level filter API called EssentialFilter which gives you full access to the body of the request.
but there is not any method to accessing request body in requestHeader
object.
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 =>
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" -> requestTime.toString)
}
}
}
}
The abstract method EssentialFilter.apply
that you implement when you create an EssentialFilter
returns an EssentialAction
which basically is a function that goes from RequestHeader
to an Iteratee[Array[Byte], Result]
into which play will feed the incoming byte chunks of the http body.
If you aren't familiar with the iteratee API, the signature above basically means, a thing that will accept chunks of data of the type Array[Byte]
and sooner or later produce a Result
out of those.
The normal play Action
's is a subclass of EssentialAction
that parses the body using a BodyParser
and then feeding the result of that (Request
which is both request headers and the parsed body) into a function that in turn returns a Future[Result]
So if you only have one filter, then next: EssentialAction
in your filter is basically the actual controller action. That you get to take its Iteratee[Array[Bytes], Result]
and wrap it with something is what makes it possible to access the body of the request, before the body parser has gotten to touch it.
So to achieve what you want will require you to learn a bit about how Iteratees
works and how to use Enumeratees
to transform or peek into data fed into an iteratee.
The play framework docs has got some pretty good information about iteratees: https://www.playframework.com/documentation/2.3.x/Iteratees
There is also a nice blog article by James Roper (play tech lead) that might help: https://jazzy.id.au/2012/11/06/iteratees_for_imperative_programmers.html
How filters works in play makes it impossible to look at the parsed body with a filter. Unless you make an enumeratee that will parse the body but still pass the bytes on to the actual action (this will have you parsing the body twice).
If this is what you want you may be better off working with the ActionBuilder
and creating your own custom Action
that will allow you to look at the parsed request.
you don't want to parse request body on filtering level because of the body not parsed on filtering process, you have to buffer, parse and stream so it is better to use action composition
object LoggingAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
Logger.debug(request.body.asInstanceOf[AnyContentAsJson].json.toString())
block(request)
}
}
on controller side use like
def index = LoggingAction {...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With