Reputation: 1689
Here is an example of what I am trying to post to web service:
Content-Type: application/json "0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"
Note that there is no key-value pair here. I am trying to use 'pipelining' to POST this, but I keep on getting the following error :
> test
[info] Compiling 1 Scala source to /home/chris/dev/coinprism-api/target/scala-2.11/classes...
[error] /home/chris/dev/coinprism-api/src/main/scala/com/coinprism/transaction/TransactionBuilder.scala:102: could not find implicit value for evidence parameter of type spray.httpx.marshalling.Marshaller[spray.json.JsObject]
[error] pipeline(Post(host + version + sendrawtransaction, msg))
Here is the code that I am trying to use:
import TransactionHashFormat._
import DefaultJsonProtocol._
val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject
val pipeline: HttpRequest => Future[TransactionHash] =
addHeader("Content-Type" , "application/json") ~> sendReceive ~> unmarshal[TransactionHash]
pipeline(Post(host + version + sendrawtransaction, msg))
What am I doing incorrectly?
EDIT:
The API that I am trying to call:
Upvotes: 1
Views: 558
Reputation: 8367
Let's break it down:
a) As others have already commented this isn't valid JSON so it will fail at runtime:
val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject
b) You cannot use marshallers because currently spray (1.3.2) only allows JSON objects and arrays to be marshalled. This was a requirement of the former JSON spec (RFC 4627) but this requirement has been lifted with the new RFC 7159. I created a ticket to fix this in the future https://github.com/spray/spray/issues/1034. The API you are targeting, however, expects a double-quoted JSON string.
c) This means you need cannot use marshalling (i.e. automatic conversion of Scala values to HTTP messages) in this case. This isn't a particular problem you just need to create the message yourself. Something like this should work:
val pipeline = sendReceive
val hash: String = "0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"
val msg: String = "\"" + hash + "\""
val request = Post(host + version + sendrawtransaction, HttpEntity(ContentTypes.`application/json`, msg))
// run request
pipeline(request) // receive result as Future[HttpResponse]
You need to understand that spray handles the Content-Type header specially: it isn't represented as a normal header but it is modeled as part of the HttpEntity.
Unfortunately, unmarshal
doesn't work for the same reason as explained in b) so you need to extract the value yourself.
You should be able to do it roughly like this:
def extractJsonStringResult(res: HttpResponse): String = {
// TODO: check status code
import spray.json._
res.entity.asString(HttpCharsets.`UTF-8`).parseJson match {
case JsString(string) => string
case _ => ??? // TODO: fail
}
}
val pipeline = sendReceive ~> extractJsonStringResult
Upvotes: 1
Reputation: 4182
Just because it is surrounded by curly braces does not make it valid json. Spray does give you some options if you want to post invalid json
Can't you make the Content-Type "application/text" and post msg
as a string?
Upvotes: 0