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)
}
}
}
}
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
on controller side use like
The abstract method
EssentialFilter.apply
that you implement when you create anEssentialFilter
returns anEssentialAction
which basically is a function that goes fromRequestHeader
to anIteratee[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 aResult
out of those.The normal play
Action
's is a subclass ofEssentialAction
that parses the body using aBodyParser
and then feeding the result of that (Request
which is both request headers and the parsed body) into a function that in turn returns aFuture[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 itsIteratee[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 useEnumeratees
to transform or peek into data fed into an iteratee.Some starting points
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
Important note
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 customAction
that will allow you to look at the parsed request.