2012-04-03 38 views
11

Tôi phát triển một máy chủ nhỏ trong PlayFramework2/Scala để truy xuất dữ liệu từ nhiều WS (REST/JSON), thao tác dữ liệu từ WS, sau đó soạn và trả về kết quả.Nhiều cuộc gọi WS trong một hành động, cách xử lý các đối tượng Promise?

Tôi biết cách gọi một WS, thao tác dữ liệu và trả về phản hồi Không đồng bộ. Nhưng tôi không biết cách gọi liên tiếp một số dịch vụ web, xử lý dữ liệu giữa mọi cuộc gọi và tạo câu trả lời tổng hợp.

dụ:

  • Fetch danh sách các bài hát ưa thích của tôi từ WebService Một
  • sau đó, đối với mỗi bài hát, lấy các chi tiết nghệ sĩ từ WS B (một cuộc gọi bằng cách hát)
  • sau đó, tạo và trả về một cái gì đó (danh sách tổng hợp chẳng hạn) bằng cách sử dụng các mặt nạ AB ses
  • sau đó, trả lại kết quả

Tôi đang bị chặn bởi processings không đồng bộ của WS API (WS.url(url).get => Promise[Response]). Tôi có phải dựa vào Akka để giải quyết vấn đề này không?

Cảm ơn bạn.

Trả lời

19

flatMapmap là bạn của bạn! Hai phương pháp này của loại Promise cho phép chuyển đổi kết quả của một Promise[A] thành một số khác Promise[B].

Đây là một ví dụ đơn giản của họ trong chiến tranh (tôi cố tình viết một cách rõ ràng hơn chú thích loại hơn cần thiết, chỉ để giúp đỡ để hiểu nơi biến đổi xảy ra):

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

Nếu không có chú thích loại không cần thiết và sử dụng “ để hiểu ”, bạn có thể viết mã biểu cảm sau đây:

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

Cảm ơn câu trả lời của bạn. Tôi phân tích và kiểm tra giải pháp này càng sớm càng tốt. – YoT

+0

@julien Điều gì sẽ xảy ra nếu bất kỳ dịch vụ web nào hết thời gian chờ hoặc trả lại 500? getOrElse? –

+1

Lời hứa sẽ được đổi bằng giá trị [Thrown] (http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/concurrent/Thrown.html). Bạn có thể xử lý trường hợp này bằng cách sử dụng [mở rộng] (http://www.playframework.org/documentation/api/2.0/scala/index.html#play.api.libs.concurrent.Promise) chẳng hạn. –

Các vấn đề liên quan