Отправка сообщения JSON без пары ключ-значение Spray

Вот пример того, что я пытаюсь опубликовать на веб-сервисе:

Content-Type: применение / JSON "0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"

Обратите внимание, что здесь нет пары ключ-значение. Я пытаюсь использовать 'конвейеризацию', чтобы POST это, но я продолжаю получать следующую ошибку:

> 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))

Вот код, который я пытаюсь использовать:

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))

Что я делаю неправильно?

РЕДАКТИРОВАТЬ:

API, который я пытаюсь вызвать:

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

2 ответа

Решение

Давайте разберемся с этим:

а) Как уже отмечали другие, это недопустимый JSON, поэтому он потерпит неудачу во время выполнения:

val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject

b) Вы не можете использовать маршалеры, потому что в настоящее время спрей (1.3.2) позволяет маршалировать только объекты и массивы JSON. Это было требованием прежней спецификации JSON (RFC 4627), но это требование было снято с новым RFC 7159. Я создал заявку, чтобы исправить это в будущем https://github.com/spray/spray/issues/1034, Однако API, на который вы ориентируетесь, ожидает строку JSON в двойных кавычках.

c) Это означает, что вам не нужно использовать маршаллинг (то есть автоматическое преобразование значений Scala в HTTP-сообщения) в этом случае. Это не особая проблема, вам просто нужно создать сообщение самостоятельно. Примерно так должно работать:

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]

Вы должны понимать, что спрей обрабатывает заголовок Content-Type специально: он не представлен как обычный заголовок, но моделируется как часть HttpEntity.

К несчастью, unmarshal не работает по той же причине, как описано в пункте б), поэтому вам нужно извлечь значение самостоятельно.

Вы должны быть в состоянии сделать это примерно так:

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

То, что он окружен фигурными скобками, не делает его действительным. Спрей дает вам несколько вариантов, если вы хотите опубликовать недействительный JSON

Разве вы не можете сделать Content-Type "application/text" и опубликовать msg как строка?

Другие вопросы по тегам