Spray marshalling collection of ToResponseMarshallable - scala

I have a simple Spray scenario that doesn't work as I've expected.
I have a spray server that dispatches work to different modules, and then return their composed responses.
As I don't want to limit Module responses, I chose that the Module's method return ToResponseMarshallable, as I have Modules that need to return a plain String.
Module signature could be:
def moduleProcessing(): ToResponseMarshallable = randomString()
And my "complete" block look similar to this:
complete {
val response1 = moduleProcessing()
val response2 = moduleProcessing()
Seq(response1,response2)
}
In the previous example, I would expect to get:
[{"someRandomString"},{"anotherRandomString"}]
But I am getting:
[{},{}]
Of course it will propagate as expected, if I return a single response or if I change the signature of the moduleProcessing return type to any Marshallable Type.
Thanks in advance for your help!

I think it's strange that your moduleProcessing method returns directly a ToResponseMarshallable[T]. The spray way would be to have this method return a T and have an in scope Marshaller[T] for when you complete requests by providing a T.
Finally, I don't think Marshaller.of[Seq[T]] is a built in marshaller in spray.
This means you'll need to provide your own Seq marshaller. This could delegate the actual marshalling of each item in the seq to an implicit Marshaller[T] and concatenate the results. Many builtin spray marshallers require implicit Marshaller[T] values like this. Alternatively, if you want a simple Seq[T] to string marshaller, try something like the following:
implicit val CustomMarshaller = Marshaller.delegate[Seq[T], String](`text/html`)(_.mkString("{", ",", "}"))

Related

Cannot mock WSRequest.post() using scalamock

I am writing unit tests for Play application using Scalamock and Scalatest.
My original code looks like:
// Here ws is an injected WSClient
val req = Json.toJson(someRequestObject)
val resp: Future[WSResponse] = ws.url(remoteURL).post(Json.toJson(req))
In a part I have to mock external calls to a web service, which I am trying to do using scalamock:
ws = stub[WSClient]
wsReq = stub[WSRequest]
wsResp = stub[WSResponse]
ws.url _ when(*) returns wsReq
wsReq.withRequestTimeout _ when(*) returns wsReq
(wsReq.post (_: java.io.File)).when(*) returns Future(wsResp)
I am successfully able to mock post requests using a file, but I cannot mock post requests using JSON.
I tried putting stub function references separately like:
val f: StubFunction1[java.io.File, Future[WSResponse]] = wsReq.post (_: java.io.File)
val j: StubFunction1[JsValue, Future[WSResponse]] = wsReq.post(_: JsValue)
I get the compile error for second line: Unable to resolve overloaded method post
What am I missing here? Why cannot I mock one overloaded method but not the other one?
play.api.libs.ws.WSRequest has two post methods (https://www.playframework.com/documentation/2.4.x/api/scala/index.html#play.api.libs.ws.WSRequest), taking:
File
T (where T has an implicit bounds on Writeable)
The compiler is failing because you are trying to calling post with a single parameter, which only matches version 1. However, JsValue cannot be substituted with File.
You actually want to call the 2nd version, but this is a curried method that takes two sets of parameters (albeit the 2nd are implicit). Therefore you need to explicitly provide the mock value that you expect for the implicit, i.e.
val j: StubFunction1[JsValue, Future[WSResponse]] = wsReq.post(_: JsValue)(implicitly[Writeable[JsValue]])
Therefore a working solution would be:
(wsReq.post(_)(_)).when(*) returns Future(wsResp)
Old answer:
WSRequest provides 4 overloads of post method (https://www.playframework.com/documentation/2.5.8/api/java/play/libs/ws/WSRequest.html), taking:
String
JsonNode
InputStream
File
You can mock with a File because it matches overload 4, but JsValue does not match (this is part of the Play JSON model, whereas JsonNode is part of the Jackson JSON model). If you convert to a String or JsonNode, then it will resolve the correct overload and compile.
My best guess is that your WSRequest is actually a play.libs.ws.WSRequest which is part of the Java API, instead you should use play.api.libs.ws.WSRequest which is the Scala API.
The method WSRequest.post exists and BodyWritable[JsValue] is implicitly provided by WSBodyWritables in the Scala API but not in the Java API.
Another cause could be that your JsValue is not a play.api.libs.json.JsValue but something else (e.g. spray.json.JsValue).
I'll quote an example where I have successfully achieved what you are trying to do, the main difference is that I used mock instead of stub.
The important part is:
val ws = mock[WSClient]
val responseBody = "{...}"
...
"availableBooks" should {
"retrieve available books" in {
val expectedBooks = "BTC_DASH ETH_DASH USDT_LTC BNB_LTC".split(" ").map(Book.fromString).map(_.get).toList
val request = mock[WSRequest]
val response = mock[WSResponse]
val json = Json.parse(responseBody)
when(ws.url(anyString)).thenReturn(request)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.get()).thenReturn(Future.successful(response))
whenReady(service.availableBooks()) { books =>
books.size mustEqual expectedBooks.size
books.sortBy(_.string) mustEqual expectedBooks.sortBy(_.string)
}
}
}
An you could see the complete test at: BinanceServiceSpec
I guess it should work fine, if you mock a response that is JsValue.
when(wsReq.post(Json.parse("""{...json request...}"""))).thenReturn(Future(wsResp))
Here Json.parse returns JsValue. Yo should pass the json string that you expect in the request body.

How to avoid coupling to a representation in Play 2.3?

The RESTful example Action in the Play 2.3 docs reads:
def listPlaces = Action {
val json = Json.toJson(Place.list)
Ok(json)
}
What makes the method tightly coupled to this specific JSON format.
Is it possible to have the service logic separated from content representation, for example as JAX-RS does with MessageBody Writers and Readers?
Ok(json) is actually calling Status.apply. It requires a play.api.http.Writeable[A], which is something that can transform A to a byte array and return the content type for A. In your case A stands for JsValue.
What you can do is to go a step further and supply a Writeable[Place], so you can write something like this:
def listPlaces(implicit writeable: Writeable[Place]) = Action {
Ok(Place.list)
}
I assume you already have a Writes[Place]. All that's left is to implement a generic function that converts json Writes to http Writeable:
implicit def jsonWritesToHttpWriteable[A](jsWrites: Writes[A])
(implicit writeable: Writeable[JsValue]): Writeable[A] =
writeable.map(jsWrites.writes)
Now, having defined this conversion function as implicit, you can just supply the Writes[Place] when you call listPlaces:
val listPlacesJson = listPlaces(placeJsonWrites)
Of course, your route must point to listPlacesJson now.

spray-can how to unwrap unmarshalled FormData

I have something like this:
case HttpRequest(POST, Uri.Path("/userAction"), headers, entity: HttpEntity.NonEmpty, protocol) =>
val x = entity.as[spray.http.FormData].merge.asInstanceOf[spray.http.FormData].fields
sender ! HttpResponse(entity="Got it: " + x)
It seems a little bit inconvinient to unwrap the HttpEntity, is there a much more elegant way?
Furthermore: is it possible to get the data from inputs with multiple delacred variables? Is there a better way to access FormData, e.g. as Json or HashMap?
Is there an actual reason why you are implementing this with spray-can? In routing it's more easier and natural:
lazy val yourRoute: Route = {
(post & path("userAction")) {
entity(as[SomeType]) { data =>
// do what you want
}
}
}
In this version it all comes to the proper unmarshaller for your type (SomeType). But if you want to stick with spray-can, you can use spray-httpx unmarshaller. I don't have IDE near to me, but this can like this (actual code from my project with some Scalaz tricks):
case request # HttpRequest(...) =>
fromTryCatch(request.entity |> unmarshal[SomeType]) // returns Throwable \/ SomeType, like scala's Either type
Here it also comes to the right unmarshaller, e.g if you want to get your entity in Json format (i.e spray JsObject), then you need to emit a request with json payload, write entity(as[JsObject]) and provide an implicit unmarshaller from spray.json.SprayJsonSupport. I think that using this approach for FormData is a bit overhead, cause for simple Post payload you have formFields directive, and you can write:
lazy val yourRoute: Route = {
(post & path("userAction")) {
formFields(...) { fields => // just enumerate field names from your FormData
// do what you want
}
}
}
For Map approach if the same, just add spray.json.DefaultJsonProtocol into the scope, to add unmarshaller for maps.
Still using spray-routing DSL is far better then dealing with low-level can code. If you still want to use, then take a look at spray.httpx.unmarshalling package, it contains different types of unmarshallers, for entity, request and response.

Can I return Future[Option[Foo]] in spray?

My attempt so far ran into java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scala.Option. In fact I even can not think how the appropriate response may look like. Is it possible?
Here could be two options: either it's a bug in your program or you didn't provide spray any way to marshall your Foo type, cause Future and Option are handled by default. E.g this route can be handled by standard spray marshallers without any problems:
val route = {
(get & path("test")) {
complete {
Future(Option("Hello Spray!"))
}
}
}
Now if you make a GET request on /test you'll get a correct response.
If you have a specific type, then you need to provide you own marshaller of type ToResponseMarshallable to sray through implicit context. I think the most common and easiest way would be to make a Json response, for this you need a spray-json (or some other supported json lib) and just provide a converter to json, like:
import spray.json.DefaultJsonProtocol._
case class Boy(name: String, age: String)
object Boy {
implicit val boyJson = jsonFormat2(Boy.apply)
}
Now the only thing left to do is place a json marshaller into the scope:
import spray.httpx.SprayJsonSupport._ // import json marshaller
val route = {
(get & path("test") {
complete {
Future(Option(Boy("Name", 0)))
}
}
}
Now you'll get a json response. IF you need some other kind of response, make a custom marshaller for a Boy type.
In short - Yes, but you need to make compiler happy.
Spray lets you return Future or plain response as long as it can be marshalled back to a response. You need to make sure that you either have implicit conversions in the scope that do the marshalling for you or transform your Foo object explicitly.
Here is how response transformation is performed: http://spray.io/documentation/1.2.0/spray-httpx/response-transformation/.
To anyone still getting issues returning a future in the complete block, make sure to have an execution context such as scala.concurrent.ExecutionContext.Implicits.global in scope! IDE tends to not understand this is the problem and can send you down a long rabbit hole.

How can I combine fluent interfaces with a functional style in Scala?

I've been reading about the OO 'fluent interface' approach in Java, JavaScript and Scala and I like the look of it, but have been struggling to see how to reconcile it with a more type-based/functional approach in Scala.
To give a very specific example of what I mean: I've written an API client which can be invoked like this:
val response = MyTargetApi.get("orders", 24)
The return value from get() is a Tuple3 type called RestfulResponse, as defined in my package object:
// 1. Return code
// 2. Response headers
// 2. Response body (Option)
type RestfulResponse = (Int, List[String], Option[String])
This works fine - and I don't really want to sacrifice the functional simplicity of a tuple return value - but I would like to extend the library with various 'fluent' method calls, perhaps something like this:
val response = MyTargetApi.get("customers", 55).throwIfError()
// Or perhaps:
MyTargetApi.get("orders", 24).debugPrint(verbose=true)
How can I combine the functional simplicity of get() returning a typed tuple (or similar) with the ability to add more 'fluent' capabilities to my API?
It seems you are dealing with a client side API of a rest style communication. Your get method seems to be what triggers the actual request/response cycle. It looks like you'd have to deal with this:
properties of the transport (like credentials, debug level, error handling)
providing data for the input (your id and type of record (order or customer)
doing something with the results
I think for the properties of the transport, you can put some of it into the constructor of the MyTargetApi object, but you can also create a query object that will store those for a single query and can be set in a fluent way using a query() method:
MyTargetApi.query().debugPrint(verbose=true).throwIfError()
This would return some stateful Query object that stores the value for log level, error handling. For providing the data for the input, you can also use the query object to set those values but instead of returning your response return a QueryResult:
class Query {
def debugPrint(verbose: Boolean): this.type = { _verbose = verbose; this }
def throwIfError(): this.type = { ... }
def get(tpe: String, id: Int): QueryResult[RestfulResponse] =
new QueryResult[RestfulResponse] {
def run(): RestfulResponse = // code to make rest call goes here
}
}
trait QueryResult[A] { self =>
def map[B](f: (A) => B): QueryResult[B] = new QueryResult[B] {
def run(): B = f(self.run())
}
def flatMap[B](f: (A) => QueryResult[B]) = new QueryResult[B] {
def run(): B = f(self.run()).run()
}
def run(): A
}
Then to eventually get the results you call run. So at the end of the day you can call it like this:
MyTargetApi.query()
.debugPrint(verbose=true)
.throwIfError()
.get("customers", 22)
.map(resp => resp._3.map(_.length)) // body
.run()
Which should be a verbose request that will error out on issue, retrieve the customers with id 22, keep the body and get its length as an Option[Int].
The idea is that you can use map to define computations on a result you do not yet have. If we add flatMap to it, then you could also combine two computations from two different queries.
To be honest, I think it sounds like you need to feel your way around a little more because the example is not obviously functional, nor particularly fluent. It seems you might be mixing up fluency with not-idempotent in the sense that your debugPrint method is presumably performing I/O and the throwIfError is throwing exceptions. Is that what you mean?
If you are referring to whether a stateful builder is functional, the answer is "not in the purest sense". However, note that a builder does not have to be stateful.
case class Person(name: String, age: Int)
Firstly; this can be created using named parameters:
Person(name="Oxbow", age=36)
Or, a stateless builder:
object Person {
def withName(name: String)
= new { def andAge(age: Int) = new Person(name, age) }
}
Hey presto:
scala> Person withName "Oxbow" andAge 36
As to your use of untyped strings to define the query you are making; this is poor form in a statically-typed language. What is more, there is no need:
sealed trait Query
case object orders extends Query
def get(query: Query): Result
Hey presto:
api get orders
Although, I think this is a bad idea - you shouldn't have a single method which can give you back notionally completely different types of results
To conclude: I personally think there is no reason whatsoever that fluency and functional cannot mix, since functional just indicates the lack of mutable state and the strong preference for idempotent functions to perform your logic in.
Here's one for you:
args.map(_.toInt)
args map toInt
I would argue that the second is more fluent. It's possible if you define:
val toInt = (_ : String).toInt
That is; if you define a function. I find functions and fluency mix very well in Scala.
You could try having get() return a wrapper object that might look something like this
type RestfulResponse = (Int, List[String], Option[String])
class ResponseWrapper(private rr: RestfulResponse /* and maybe some flags as additional arguments, or something? */) {
def get : RestfulResponse = rr
def throwIfError : RestfulResponse = {
// Throw your exception if you detect an error
rr // And return the response if you didn't detect an error
}
def debugPrint(verbose: Boolean, /* whatever other parameters you had in mind */) {
// All of your debugging printing logic
}
// Any and all other methods that you want this API response to be able to execute
}
Basically, this allows you to put your response into a contain that has all of these nice methods that you want, and, if you simply want to get the wrapped response, you can just call the wrapper's get() method.
Of course, the downside of this is that you will need to change your API a bit, if that's worrisome to you at all. Well... you could probably avoid needing to change your API, actually, if you, instead, created an implicit conversion from RestfulResponse to ResponseWrapper and vice versa. That's something worth considering.