从基于json数组的akka​​ http响应获取实体的序列

时间:2019-01-19 20:35:40

标签: scala akka future akka-stream akka-http

我试图像Akka http客户端一样使用Flow,并遇到从http响应中的json数组获取case类对象的Seq的麻烦。

HTTP响应:

{
 "bars": [],
 "foos": [
   {
    "id": "a7d1ba80-0934-11e9-0ef9-efa612d204a1",
    "type": "manual",
    "color": "green",
   },
   {
    "id": "b7d1ba80-0934-11e9-0ef9-efa612d204a2",
    "type": "semi-manual",
    "color": "white"
   }
 ]
}

案例课程:

case class FooResponse(foos: Seq[Foo])
case class Foo(id: String, type: String, color: String)

我做过的客户:

private val flow: Flow[HttpRequest, HttpResponse, Future[Http.OutgoingConnection]] = Http().outgoingConnection(host, port)

def getFoos(): Seq[Foo] = {
  val req = HttpRequest(method = HttpMethods.GET)
  .withUri(Uri("/api/foo")).withHeaders(headers.Accept(MediaRange(MediaTypes.`application/json`)))

  Source
   .single(req)
   .via(flow)
   .map(response => Unmarshal(response.entity).to[FooResponse])
}

因此,我有一个带有Future [FooResponse]的源。如何从中返回Seq [Foo]作为函数结果。

2 个答案:

答案 0 :(得分:2)

我建议将[16:39:21] Possible Unhandled Promise Rejection (id: 0): [16:39:21] Object { [16:39:21] "D": 5, [16:39:21] } [16:39:21] 的返回类型从getFoos更改为Seq[Foo],以便停留在Future[Seq[Foo]]的上下文中:

Future

此外,由于def getFoos(): Future[Seq[Foo]] = { val req = HttpRequest(method = HttpMethods.GET) .withUri(Uri("/api/foo")) .withHeaders(headers.Accept(MediaRange(MediaTypes.`application/json`))) Source .single(req) .via(flow) .map(response => Unmarshal(response.entity).to[FooResponse]) .mapAsync(parallelism = 1)(fooResponse => fooResponse.map(_.foos)) .runWith(Sink.head) } 是Scala中的保留关键字,因此您需要将其包装在type案例类的反引号中:

Foo

答案 1 :(得分:1)

  1. type是关键字(类型别名),不应用作变量名
  2. 您需要在onComplete()上调用Future方法以等待结果。为此,我们可以在getFoos()-var fs: Seq[Foo] = Nil中定义一个占位符。将来,我们会添加onComplete(tfr => fs = tfr.get.foos),然后等待一段时间:Await.result(f, Duration(5000, "millis"))(在此示例中最多5s)。最后,我们可以返回占位符中的内容。

这应该可以完成工作:

def getFoos(): Seq[Foo] = {
  var fs: Seq[Foo] = Nil
  val req = HttpRequest(method = HttpMethods.GET)
  .withUri(Uri("/api/foo")).withHeaders(headers.Accept(MediaRange(MediaTypes.`application/json`)))

  val f = Source
   .single(req)
   .via(flow)
   .map(response => Unmarshal(response.entity).to[FooResponse])
  f.onComplete(tfr => fs = tfr.get.foos)
  Await.result(f, Duration(5000, "millis"))
  fs
}