简体   繁体   English

将akka`HttpResponse`作为元帅`Json`

[英]Marshal akka `HttpResponse` as Argonaut `Json`

I'm trying to marshal an akka HttpResponse as such: 我试图像这样封送akka HttpResponse

{
  "code": 200,
  "headers": [],
  "body": "{\"data\": \"Yes!\"}"
}

If I write an Argonaut EncodeJson for this Instance, it might look like this: 如果我为此实例编写一个Argonaut EncodeJson ,它可能看起来像这样:

implicit def httpResponseEncodeJson: EncodeJson[HttpResponse] =
  EncodeJson(
    (res: HttpResponse) ⇒ {
      ("code" := res._1.value) ->:
      ("headers" := res._2.toList) ->:
      ("body" := res._3) ->: jEmptyObject
    }
  )

I have managed to marshal the headers as json. 我设法将标头编组为json。 The only problem is with the body, ie, the ResponseEntity . 唯一的问题是主体,即ResponseEntity Since it is an akka stream, it can only return a future, if I use .toStrict . 由于它是akka流,因此如果我使用.toStrict ,它只能返回未来。

Can anybody guide me as to how I might marshal it? 有人可以指导我如何封送吗?

If possible, I would keep the marshalled value as a Future , to preserve the asynchrony of the entity extraction. 如果可能,我将把编组后的值保留为Future ,以保留实体提取的异步性。

I would start by having something along the lines of 我将从遵循以下原则开始

  case class StrictHttpResponse(code: String, headers: List[HttpHeader], body: String)

  def toStrictResponse(response: HttpResponse): Future[StrictHttpResponse] = response.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map { bs =>
    StrictHttpResponse(response.status.value, response.headers.toList, bs.utf8String)
  }

  implicit def httpResponseEncodeJson: EncodeJson[StrictHttpResponse] =
    EncodeJson(
      (res: StrictHttpResponse) ⇒ {
        ("code" := res.code) ->:
          ("headers" := res.headers) ->:
          ("body" := res.body) ->: jEmptyObject
      }
    )

  def encodeResponse(response: HttpResponse): Future[Json] = toStrictResponse(response).map(_.jencode)

and then - eg - handle the result of encodeResponse by providing a callback. 然后-例如-通过提供回调来处理encodeResponse的结果。

I ultimately used this: 我最终使用了这个:

  implicit def httpResponseListMarshal: ToEntityMarshaller[List[HttpResponse]] =
Marshaller { implicit ec ⇒ (responses: List[HttpResponse]) ⇒

    // Sink for folding Source of ByteString into 1 single huge ByteString
    val sink = Sink.fold[ByteString, ByteString](ByteString.empty)(_ ++ _)

    // A List of Future Json obtained by folding Source[ByteString]
    // and mapping appropriately
    val listFuture: List[Future[Json]] = for {
      res ← responses
    } yield for {
      byteString ← res._3.dataBytes runWith sink
      string = byteString.utf8String
    } yield ("code" := res._1.intValue) ->:
      ("headers" := res._2.toList) ->:
      ("body" := string) ->: jEmptyObject


    // Convert List[Future[Json]] to Future[List[Json]]
    val futureList: Future[List[Json]] = Future.sequence(listFuture)

    // ToEntityMarshaller is essentially a   Future[List[Marshalling[RequestEntity]]]
    for {
      list ← futureList
      json = jArray(list).nospaces
    } yield List(
      Marshalling.Opaque[RequestEntity](() ⇒
        HttpEntity(`application/json`, json)
    ).asInstanceOf[Marshalling[RequestEntity]]
  )
}

The full code and sample usage can be found here: https://github.com/yashsriv/akka-http-batch-api/blob/argonaut/src/main/scala/org.yashsriv/json/Batch.scala 完整的代码和示例用法可以在这里找到: https : //github.com/yashsriv/akka-http-batch-api/blob/argonaut/src/main/scala/org.yashsriv/json/Batch.scala

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM