I am following this tutorial - https://www.lagomframework.com/documentation/1.3.x/scala/ServiceImplementation.html
I created a logged service
//logged takes a ServerServiceCall as argument (serviceCall) and returns a ServerServiceCall.
//ServerServiceCall's compose method creates (composes) another ServerServiceCall
//we are returing the same ServerServiceCall that we received but are logging it using println
def logged[Request,Response](serviceCall:ServerServiceCall[Request,Response]) = {
println("inside logged");
//return new ServerServiceCall after logging request method and uri
ServerServiceCall.compose({
requestHeader=>println(s"Received ${requestHeader.method} ${requestHeader.uri}")
serviceCall
}
)}
I used logged as follows:
override def hello3 = logged(ServerServiceCall
{ (requestHeader,request) =>
println("inside ssc")
val incoming:Option[String] = requestHeader.getHeader("user");
val responseHeader = ResponseHeader.Ok.withHeader("status","authenticated")
incoming match {
case Some(s) => Future.successful((responseHeader,("hello3 found "+s)))
case None => Future.successful((responseHeader,"hello3 didn't find user"))
}
})
I expected that inside ssc
would be printed first and then print in logged but it was opposite. Shouldn't the arguments passed to the function be evaluated first?
I got this. Why?
inside logged
Received POST /hello3
inside ssc
logged
is a function that you've written that takes a ServiceCall
and decorates it with its own ServiceCall
. Later on, Lagom invokes the service call with the request header. You are logging inside logged
at the point that the service call is decorated, before it has been returned to Lagom, and so before it has been invoked, that's why it gets invoked first. This might explain it:
def logged[Request, Response](serviceCall:ServerServiceCall[Request, Response]) = {
println("3. inside logged method, composing the service call")
val composed = ServerServiceCall.compose { requestHeader=>
println("6. now Lagom has invoked the logged service call, returning the actual service call that is wrapped")
serviceCall
}
println("4. Returning the composed service call")
composed
}
override def hello3 = {
println("1. create the service call")
val actualServiceCall: ServerServiceCall[Request, Response] = ServerServiceCall { (requestHeader, request) =>
println("7. and now the actual service call has been invoked")
val incoming:Option[String] = requestHeader.getHeader("user");
val responseHeader = ResponseHeader.Ok.withHeader("status","authenticated")
incoming match {
case Some(s) => Future.successful((responseHeader,("hello3 found "+s)))
case None => Future.successful((responseHeader,"hello3 didn't find user"))
}
}
println("2. wrap it in the logged service call")
val loggedServiceCall = logged(actualServiceCall)
println("5. return the composed service call to Lagom")
loggedServiceCall
}
The important thing to remember is that the invocation of the hello3
method is not the invocation of the service call, hello3
merely returns a ServiceCall
that Lagom will use to invoke it.