I'm working on Play 2.3 (Java) application and I need a custom Action Composition to log request and response. With what I've got so far I am able to get the body of request, but not response:
import play.libs.F;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;
public class LogAction extends Action.Simple {
public F.Promise<Result> call(Http.Context ctx) throws Throwable {
//Request body
String requestBody = ctx.request().body().asText();
//Need to get response body here
//String responseBody = ???
return delegate.call(ctx);
}
}
How to I get the response body in this scenario? If it's difficult to do in java, it may as well be in scala, however it has to work with a java controller method @With
annotation.
@Override
public F.Promise<Result> call(Http.Context ctx) throws Throwable {
Promise<Result> call = delegate.call(ctx);
return call.map((r) -> {
byte[] body = JavaResultExtractor.getBody(r, 0l);
Logger.info(new String(body));
return r;
});
}
You can use play.core.j.JavaResultExtractor
to extract the body from the response. Keep in mind, getBody(..)
blocks until response is ready, thus consider calling onRedeem
instead of map
.
Have you tried something like this:
public class VerboseAction extends play.mvc.Action.Simple {
public F.Promise<Result> call(Http.Context ctx) throws Throwable {
Logger.info("Calling action for " + ctx);
F.Promise<Result> resultPromise = delegate.call(ctx);
resultPromise.map(result -> {
Logger.info(result.toScala().header().status());
Logger.info(result.toScala().body().toString());
return result;
});
return resultPromise;
}
}
The body will be returned as a play.api.libs.iteratee.Enumerator
. Now the hard part is to work with this. First you need to understand the concept of Iteratee
and what role the Enumerator
plays in it. Hint: think of the Enumerator
as a producer of data and think of the Iteratee
as the consumer of this data.
Now on this Enumerator
you can run an Iteratee
that will transform the data chunks into the type you want.
The bad news is that you need to implement the play.api.libs.iteratee.Iteratee
trait. As you can see it resides in the api
subpackage, that means it is part of the Scala world in Play. Maybe in this case it woul be much easier to use Scala for this part of your task. Unfortunately I cannot provide you with some example implementation but I hope this would be not that hard. I think this is something really missing on the Java side of Play.