我正在尝试在Akka / Scala中编写一个调用HTTP REST API并将结果发送回调用actor的actor。 API可能会返回结果的集合/向量,这些结果必须首先转换为内部供应商中性格式,以便将来可以更改供应商,而无需对代码进行太多更改。大多数代码都在工作,但我不确定如何解压缩并发送内部向量。
这是我的代码,它向调用的actor返回Promise
。我想要返回的是在最终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中的上述代码以发回实际结果而不是未来或承诺?
修改:根据我自己的研究和@michał和@ cyrille-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
?
答案 0 :(得分: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
这样,实际的tell(!
)只有在Future
被解析后才会完成。
答案 1 :(得分:1)
你可以使用map来实现monadic:
pathPrefix("search") {
get {
parameter("query") { query =>
restActor.ask(query) map {
case Success(resp) => ...
case Failure(e) => ...
}
}
}
}
编辑:目前您的演员回应未来。尝试重构它,以便它确实返回unwrapped值:
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
}
}