Hi scala and spray people!
I have a small annoying issue with extracting the HTTP 'Accept' header from the RequestContext
and matching on it. On a normal route like so:
get {
respondWithMediaType(`text/plain`) {
complete ( "Hello World!" )
}
}
It works like a charm. But whenever I bring the context into scope like so (as suggested in the documentation for directives):
get { context => {
respondWithMediaType(`text/plain`) {
complete ( "Hello World!" )
}
} }
The result becomes the following error message:
The server was not able to produce a timely response to your request.
I am fairly new to Spray, but it looks really odd to me that bringing an (otherwise implicit) object into scope can have such a weird sideeffect. Does any of you have a clue on what is going on?
Direct access to the RequestContext
is rarely needed. In fact, you only need it if you want to write custom directives. Common tasks and extracting the usual bits of data can normally be handled using one of the predefined directives.
It seems what you want to do is manual content type negotiation. In fact, you don't have to do it manually as spray does content type automatically for common data structures. Your example can be shortened to
get {
complete("Hello World!")
}
When complete
is called with a string the response will always be of type text/plain
. If the client would send a request with an Accept
header that doesn't accept text/plain
the request would already be rejected by the server.
If you want to customize the kinds of content types that can be provided from a Scala data-type you need to provide a custom Marshaller. See the documentation on how to achieve that.
Answering your original question why adding context =>
makes the request timeout: This is because the predefined directives already are of type RequestContext => Unit
. So, writing
respondWithMediaType(`text/plain`) {
complete("Hello World!")
}
is exactly equivalent to (i.e. automatically expanded to)
ctx => respondWithMediaType(`text/plain`) {
complete("Hello World!")
}.apply(ctx)
So, if you add only ctx =>
manually, but don't add the apply
call, an incoming request is never fed into the inner route and therefore never completed. The compiler doesn't catch this kind of error because the type of a route is RequestContext => Unit
and so the variant with and the variant without the apply
invocation are both valid. We are going to improve this in the future.
See the documentation for more info about how routes are built.
Finally, if you need to extract a header or its value you can use one of the predefined HeaderDirectives that simplify working with request headers a lot.
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