一个动作中有多个WS调用,如何处理Promise对象? [英] Multiple WS call in one action, how to handle Promise objects?
问题描述
我在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?
谢谢.
推荐答案
flatMap
和map
是您的朋友! 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屋!