2012-04-03 82 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