一个动作中有多个WS调用,如何处理Promise对象? [英] Multiple WS call in one action, how to handle Promise objects?

查看:115
本文介绍了一个动作中有多个WS调用,如何处理Promise对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在PlayFramework2/Scala中开发了一个小型服务器,该服务器必须从多个WS(REST/JSON)检索数据,从这些WS中操纵数据,然后编写并返回结果.

I develop a little server in PlayFramework2/Scala which has to retrieve data from multiple WS (REST/JSON), manipulate the data from theses WS, then compose and return a result.

我知道如何调用 one WS,操纵数据并返回异步响应.但是我不知道如何成功地调用几个Web服务,如何处理每次调用之间的数据并生成汇总的答案.

I know how to call one WS, manipulate the data and return an Async response. But I don't know how how to call successively several web-services, handle the data between every call and generate an aggregated answer.

示例:

  • 从WebService A
  • 中获取我喜欢的歌曲列表
  • 然后,针对每首歌曲,从WS B (按歌曲调用)中获取艺术家的详细信息
  • 然后使用 A B 响应生成和返回某物(例如汇总列表)
  • 然后,返回结果
  • Fetch the list of my prefered songs from WebService A
  • then, for each song, fetch the artist detail from WS B (one call by song)
  • then, generate and return something (aggregated list for example) using the A and B responses
  • then, return the result

我被WS API(WS.url(url).get => Promise[Response])的异步处理所阻止.我是否必须依靠Akka来解决此问题?

I am blocked by the asynchronous processings of WS API (WS.url(url).get => Promise[Response]). Do I have to lean on Akka to solve this problem?

谢谢.

推荐答案

flatMapmap是您的朋友! 类型允许将Promise[A]的结果转换为另一个Promise[B].

flatMap and map are your friends! These two methods of the Promise type allow to transform the result of a Promise[A] into another Promise[B].

这是它们在操作中的一个简单示例(我故意写出了比需要更多的类型注释,目的只是为了帮助了解转换发生在何处):

Here is a simple example of them in action (I intentionally wrote explicitly more type annotations than needed, just to help to understand where transformations happen):

def preferredSongsAndArtist = Action {
  // Fetch the list of your preferred songs from Web Service "A"
  val songsP: Promise[Response] = WS.url(WS_A).get
  val resultP: Promise[List[Something]] = songsP.flatMap { respA =>
    val songs: List[Song] = Json.fromJson(respA.json)
    // Then, for each song, fetch the artist detail from Web Service "B"
    val result: List[Promise[Something]] = songs.map { song =>
      val artistP = WS.url(WS_B(song)).get
      artistP.map { respB =>
        val artist: Artist = Json.fromJson(respB.json)
        // Then, generate and return something using the song and artist
        val something: Something = generate(song, artist)
        something
      }
    }
    Promise.sequence(result) // Transform the List[Promise[Something]] into a Promise[List[Something]]
  }
  // Then return the result
  Async {
    resultP.map { things: List[Something] =>
      Ok(Json.toJson(things))
    }
  }
}

无需使用不必要的类型注释,并使用"for comprehension"(表示理解)符号,您可以编写以下更具表现力的代码:

Without the unnecessary type annotations and using the "for comprehension" notation, you can write the following more expressive code:

def preferredSongsAndArtist = Action {
  Async {
    for {
      // Fetch the list of your preferred songs from Web Service "A"
      respA <- WS.url(WS_A).get
      songs = Json.fromJson[List[Song]](respA.json)
      // Then, for each song, fetch the artist detail from Web Service "B"
      result <- Promise.sequence(songs.map { song =>
        for {
          respB <- WS.url(WS_B(song)).get
          artist = Json.fromJson[Artist](respB.json)
        } yield {
          // Then, generate and return something using the song and artist
          generate(song, artist)
        }
      })
    // Then return the result
    } yield {
      Ok(Json.toJson(result))
    }
  }
}

这篇关于一个动作中有多个WS调用,如何处理Promise对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆