Scalatra is not so suitable for asynchronous code. I recently came across the same problem as you. The problem is that scalatra tries to make the code as declarative as possible by exposing dsl, which removes as much fuss as possible, and in particular, does not require you to explicitly pass the data.
I will try to explain.
In your example, the code inside post("/test") is an anonymous function. Note that it does not accept any parameters, not even the current request object. Instead, scalatra will store the current request object inside the local value of the stream just before it calls your own handler, and you can get it back through ScalatraServlet.request .
This is a classic dynamic scale pattern. The advantage is that you can write many useful methods that access the current request and call them from your handlers, without explicitly passing the request.
Now the problem arises when you use asynchronous code, just like you do. In your case, the code inside withJsonFuture is executed in a different thread than the original thread originally called by the handler (it will be executed in the thread from the thread pool ExecutionContext ). Thus, when accessing the local stream, you get access to a completely different instance of the local stream variable. Simply put, the classic Dynamic Scope pattern is not suitable in an asynchronous context.
The solution here is to capture the request at the very beginning of your handler, and then only reference it:
post("/test") { val currentRequest = request withJsonFuture[MyJsonParams]{ params => // code that calls request.getRemoteAddr goes here // sometimes request is null and I get an exception println(currentRequest) } }
Quite frankly, this is too easy to make a mistake IMHO, so I would personally avoid using Scalatra at all if you are in a synchronous context.
source share