Chris Stewart
Chris Stewart

Reputation: 1689

Posting JSON message with no key value pair Spray

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:

http://docs.coinprism.apiary.io/#reference/transaction-signing-and-broadcasting/push-a-signed-raw-transaction-to-the-network/post?console=1

Upvotes: 1

Views: 558

Answers (2)

jrudolph
jrudolph

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

Gangstead
Gangstead

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

Related Questions