Spray Transparent Head Requests and Testing
Recently I've been using Spray for API work. While doing so I've written a few posts like JSON and Generic Class Serialization and Logging with Spray, but the other day I ran into a weird bit of a nonsense and ended up raising an issue about it on the spray-can repo.
It may just be my own poor reading comprehension, but I was quite confused
that the feature Transparent Head Request can cause an untestable situation.
As I documented in my example repository that reproduces the error, you can
test a head
directive within your code and it will never actually check out
against the Transparent Head Request behavior.
The issue is that if you have a route which only supports head
directives,
having the spray.can.server.transparent-head-requests="on"
line in your
application.conf file will result in an error. Why? Because the transparent
head request doesn't enhance the request or handle it like a rejection catcher
of some kind (my initial assumption), but rather replaces the actual HEAD
request with a GET
!
You can see this in the code here that it's just copying the request into a
GET
. This is handy when you have a route that responds to GET
it now also
responds to HEAD
. But if you head a route that is only meant for a HEAD
request than it will reject any HEAD
request sent to it while you have the
transparent requests on! In order to fix that, you need to set the transparent
requests off, and now if you want to support HEAD
on each of those GET
routes of yours, you need to code them yourself manually.
The extra labour isn't really my issue, after all, if you're supporting HEAD
requests, there's a chance that you probably don't want the same logic to be
applied (for example if you don't want to hit your database on every HEAD
),
so you might be coding your head
directives anyway. The reason why I raised
this as a bug on the spray-can repository was because there is absolutely
no way to test this behavior.
"That's because tests built with the testkit are executed without spray-can and so transparent-head-request handling isn't available. I agree that this is unfortunate as it prevents proper testing of the behavior." -jrudolph
So while you can test your code and head
directives and the tests will tell
you they pass, when you actually run the server and send a HEAD
request to
one of your endpoints to check that it works. BAM Whatever code you're
expecting to run on a HEAD
-only endpoint isn't running. And there's probably
no way you're going to know that.*
Best part is that transparent head requests is on
by default. So if you're not
aware of this by reading the Transparent Head Request documentation, you'll get
hit by this!
*At least not until your DBA asks why all your health checks against database intensive endpoints are triggering the database when you assured him the HEAD
requests wouldn't do that ;)