多个WS调用一个动作,如何处理Promise对象?

YoT*_*YoT 11 web-services scala promise akka playframework-2.0

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

我知道如何调用一个 WS,操纵数据并返回异步响应.但我不知道如何连续调用多个Web服务,在每次调用之间处理数据并生成聚合答案.

例如:

  • 从WebService A获取我喜欢的歌曲列表
  • 然后,对于每首歌曲,从WS B中获取艺术家的详细信息(通过歌曲进行一次调用)
  • 然后,使用AB响应生成并返回一些内容(例如聚合列表)
  • 然后,返回结果

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

谢谢.

Jul*_*Foy 19

flatMap并且map是你的朋友!这两种Promise类型的方法允许将a的结果转换Promise[A]为另一种Promise[B].

这是一个简单的实例示例(我故意明确地写了比需要更多的类型注释,只是为了帮助理解转换发生的位置):

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))
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

如果没有不必要的类型注释并使用"for comprehension"表示法,您可以编写以下更具表现力的代码:

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))
    }
  }
}
Run Code Online (Sandbox Code Playgroud)