2016-12-04 4 views
0

Я пытаюсь выстроить в Акку HttpResponse как таковой:Маршал Akka `HttpResponse`, как Аргонавт` Json`

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

Если я пишу Аргонавт EncodeJson для этого экземпляра, он может выглядеть следующим образом:

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

Мне удалось выставить заголовки как json. Единственная проблема заключается в корпусе, то есть ResponseEntity. Поскольку это поток akka, он может вернуть только будущее, если я использую .toStrict.

Может ли кто-нибудь вести меня о том, как я мог бы его маршалировать?

ответ

0

Если возможно, я бы сохранил маршаллированное значение как Future, чтобы сохранить асинхронность извлечения объекта.

Я хотел бы начать, имея что-то вдоль линий

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) 

, а затем - например, - обрабатывать результат encodeResponse, предоставляя обратный вызов.

+0

Спасибо большое за ваш ответ. Думаю, я сделал почти то же самое. Можете ли вы просмотреть мой ответ? –

0

Я в конечном счете использовал это:

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

Полный код и использование образец можно найти здесь: https://github.com/yashsriv/akka-http-batch-api/blob/argonaut/src/main/scala/org.yashsriv/json/Batch.scala

Смежные вопросы