2012-04-03 84 views
11

我在PlayFramework2/Scala中开发一个小服务器,它必须从多个WS(REST/JSON)中检索数据,操作来自这些WS的数据,然后撰写并返回结果。多个WS调用一个动作,如何处理Promise对象?

我知道如何调用一个 WS,操纵数据并返回一个异步响应。但我不知道如何通过连续拨打几个网络服务,处理每次通话之间的数据并生成一个汇总答案。

例:

  • 从WebService的取我的首选歌曲列表中
  • 然后,每首歌曲,从WS获取艺术家详细(一个由歌曲调用)
  • 然后,生成并返回东西(汇总列表例如)使用AB respon SES
  • 然后,返回结果

我已被WS API(WS.url(url).get => Promise[Response])的异步处理。我是否需要靠阿卡解决这个问题?

谢谢。

回答

19

flatMapmap是你的朋友! Promise类型的这两种方法允许将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)) 
    } 
    } 
} 

没有不必要的类型注释,并使用“理解“符号,你可以写下面更富有表现力的代码:

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)) 
    } 
    } 
} 
+0

谢谢你的回答。我尽快分析和测试这个解决方案。 – YoT 2012-04-03 13:35:47

+0

@ julien如果任何Web服务调用超时或返回500,会发生什么情况? getOrElse? – 2012-04-25 08:06:52

+1

该承诺将以[Thrown](http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/concurrent/Thrown.html)值进行兑换。例如,您可以通过使用[extend](http://www.playframework.org/documentation/api/2.0/scala/index.html#play.api.libs.concurrent.Promise)来处理这种情况。 – 2012-04-25 13:28:50