2017-05-04 58 views
2

我正在尝试在Akka/Scala中编写一个调用HTTP REST API的演员,并将结果发回给主叫演员。 API可能会返回必须首先转换为内部供应商中性格式的结果的集合/向量,以便将来可以更改供应商,而无需对代码进行太多的更改。大部分的代码工作,但我不知道如何解压缩并发送内部向量。从演员返回实际结果而不是承诺/未来

这是我拥有的代码,它会将Promise返回给调用actor。我想回到的是,获取最终的map操作所创建的实际载体:

class RESTActor extends Actor with ActorLogging with JsonSupport { 

    final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system)) 
    val http = Http(context.system) 

    import akka.pattern.pipe 
    import context.dispatcher 

    override def receive: Receive = { 
    case query: String => { 
     val requester = sender 
     var uri = Uri(Settings.autoCompleteURL).withQuery(Query(Map("query" -> query))) 

     sender! http 
     .singleRequest(HttpRequest(HttpMethods.GET, uri = uri)) 
     .flatMap(response => 
      response.status match { 
      case status if status.isSuccess() => Unmarshal(response.entity).to[VendorResponse].map(_.result.map(x => VendorNeutralResponse(x.id, x.field))) 

      case _ => response.entity.toStrict(5.seconds).map { entity => 
       val body = entity.data.decodeString("UTF-8") 
       log.warning(errorMessage(response, body)) 
       Left(errorMessage(response, body)) 
      } 

      }) 
    } 

    } 

调用演员:

pathPrefix("search") { 
      get { 
      parameter("query") { query => 
       { 
       complete(restActor.ask(query)) //Doesn't work as the reply is a promise 

       } 
      } 
      } 
     } 

如何更改上面的代码中RESTActor发送实际结果而不是未来或承诺?

编辑:根据我自己的研究和建议更改代码之后@米哈尔和@西里尔 - corpet,下面的代码工作:

pathPrefix("search") { 
      get { 
      parameter("query") { query => 
       { 
       onComplete(gisRouter.ask(query)) { 
        case Success(resp: Future[Vector[VendorNeutralResponse]]) => { 
        resp.map(println) 
        complete("ok") 
        } 
        case Failure(e) => complete(e.toString) 
       } 

       } 
      } 
      } 
     } 

好像我仍然得到一个future作为我的演员的回应。我如何让演员回应实际数据而不是Future

回答

1

可以使用onComplete功能,即需要一个Future[T]作为输入,并返回一个Directive1[Try[T]],这样你就可以如下使用:

pathPrefix("search") { 
    get { 
    parameter("query") { query => 
     onComplete(restActor.ask(query)) { 
     case Success(resp) => ... 
     case Failure(e) => ... 
     } 
    } 
    } 
} 

编辑有关从演员的回报,你应该管的http.singleRequest给发件人,而不是告诉它的结果:

http.singleRequest(...).flatMap(...) pipeTo requester 

这样一来,实际的诉说(!)将唐e只有在解决了Future之后。

+0

嗨..代码没有帮助。我仍然需要在onComplete中解开未来。请参阅更新/编辑。 – MojoJojo

+0

@MojoJojo对答案的编辑建议你将'Future'传送给发件人,而不是回复Future作为回复的一部分 – dk14

+0

@ dk14编辑完成是因为此评论... –

1

你可以做类似一元使用图吧:

pathPrefix("search") { 
    get { 
    parameter("query") { query => 
     restActor.ask(query) map { 
     case Success(resp) => ... 
     case Failure(e) => ... 
     } 
    } 
    } 
} 

编辑:目前你的演员与未来的响应。尝试重构它,所以它确实返回未包装的值:

class RESTActor extends Actor with ActorLogging with JsonSupport { 

    final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system)) 
    val http = Http(context.system) 

    import akka.pattern.pipe 
    import context.dispatcher 

    private def handleHttpResponse = { 
    case status if status.isSuccess() => Unmarshal(response.entity).to[VendorResponse].map(_.result.map(x => VendorNeutralResponse(x.id, x.field))) 

    case _ => response.entity.toStrict(5.seconds).map { entity => 
     val body = entity.data.decodeString("UTF-8") 
     log.warning(errorMessage(response, body)) 
     Left(errorMessage(response, body)) 
    } 

    } 

    override def receive: Receive = { 
    case query: String => { 
     val requester = sender 
     var uri = Uri(Settings.autoCompleteURL).withQuery(Query(Map("query" -> query))) 

     http.singleRequest(HttpRequest(HttpMethods.GET, uri = uri)).flatMap(response => 
      response.status map handleHttpResponse) pipeTo requester 
    } 

    } 
+0

谢谢你的回应...代码并没有帮助 - 我仍然从演员得到一个未来,必须再次映射/平面地图..已更新与代码的问题。 – MojoJojo

+0

@MojoJojo请参考上面的修改 –