2012-09-03 56 views
2

我是一個play2.0-Scala初學者,必須調用多個Web服務才能生成HTML頁面。從播放2調用多個網絡服務

閱讀The Play WS API頁面後和非常有趣article from Sadek Drobi我仍然不確定什麼是做到這一點的最好辦法。

該文章顯示了一些代碼片段,我並不完全理解爲Play初學者。

圖2第4頁:

val response: Either[Response,Response] = 
    WS.url("http://someservice.com/post/123/comments").focusOnOk 

val responseOrUndesired: Either[Result,Response] = response.left.map { 
    case Status(4,0,4) => NotFound 
    case Status(4,0,3) => NotAuthorized 
    case _ => InternalServerError 
} 

val comments: Either[Result,List[Comment]] = 
responseOrUndesired.right.map(r => r.json.as[List[Comment]]) 

// in the controller 
comment.fold(identity, cs => Ok(html.showComments(cs))) 

什麼用fold最後一行呢?應該commentcomments?我沒有把Async區塊中的最後一條語句分組嗎?

圖4顯示了怎麼把幾個IO調用帶有一個for -expression:

for { 
    profile <- profilePromise 
    events <- attachedEventsPromise 
    articles <- topArticlesPromise 
} yield Json.obj(
    "profile" -> profile, 
    "events" -> events, 
    "articles" -> articles) 

} 

// in the controller 
def showInfo(...) = Action { rq => 
    Async { 
    actorInfo(...).map(info => Ok(info)) 
    } 
} 

如何使用這個片段? (在for-expression之後,我有點困惑於額外的})。 我應該寫這樣的東西嗎?

var actorInfo = for {    // Model 
    profile <- profilePromise 
    events <- attachedEventsPromise 
    articles <- topArticlesPromise 
} yield Json.obj(
    "profile" -> profile, 
    "events" -> events, 
    "articles" -> articles) 

def showInfo = Action { rq =>   // Controller 
    Async { 
    actorInfo.map(info => Ok(info)) 
    } 
} 

結合圖2和圖4中的片段(錯誤處理+ IO無阻塞調用的組成)的最佳方式是什麼? (f.ex.如果任何被調用的webservice產生錯誤404,我想產生一個錯誤404狀態碼)。

也許有人知道在播放框架中調用web服務的完整示例(在播放示例應用程序或其他任何地方找不到示例)。

回答

2

我必須說這篇文章在圖2所示的例子中是錯誤的。方法focusOnOk在Play 2.0中不存在。我假設文章的作者使用了Play 2的預發佈版本。

關於comment,是的應該是comments。聲明中的fold正在運行Either。它需要2個函數作爲參數。第一個是應用功能,如果它是左值。第二個是適用的功能,如果它是正確的值。更詳細的解釋可以在這裏找到:http://daily-scala.blogspot.com/2009/11/either.html

所以這條線是幹什麼的。如果我有一個左值(這意味着我得到了不想要的響應),則應用內置的identity函數,該函數只會返回值。如果它有一個正確的值(這意味着我得到了一個確定的迴應),那麼可以創建一個以某種方式顯示評論的新結果。

關於Async,它實際上並不是異步的。 focusOnOk是一個阻塞函數(來自Play 1.x的舊Java日子的殘餘)。但請記住,這不是有效的Play 2代碼。

至於圖4,尾隨}實際上是因爲它是圖3中部分替代方案。而不是許多承諾flatMap s。您可以改爲for comprehension。另外,我認爲它應該是userInfo(...).map而不是actorInfo(...).map

您鏈接到的Play documentation實際上已經向您展示了一個完整的示例。

def feedTitle(feedUrl: String) = Action { 
    Async { 
    WS.url(feedUrl).get().map { response => 
     Ok("Feed title: " + (response.json \ "title").as[String]) 
    } 
    } 
} 

會得到什麼是feedUrl,你map它做具有status場,你可以檢查,看它是否是404還是其他什麼東西的東西response

爲此,鏈接文章的圖3和圖4應該爲您提供一個起點。所以你有類似的東西,

def getInfo(...) : Promise[String] = { 
    val profilePromise = WS.url(...).get() 
    val attachedEventsPromise = WS.url(...).get() 
    val topArticlesPromise = WS.url(...).get() 

    for { 
    profile <- profilePromise 
    events <- attachedEventsPromise 
    articles <- topArticlesPromise 
    } yield { 
    // or return whatever you want 
    // remember to change String to something else in the return type 
    profile.name 
    } 
} 

def showInfo(...) = Action { rq => 
    Async { 
    getInfo(...).map { info => 
     // convert your info to a Result 
     Ok(info) 
    } 
    } 
} 
+0

感謝您的回答,它現在更清晰:-)。但是,如何在f.ex中生成錯誤頁面。在''getInfo()''中調用產生一個錯誤500? – Sonson123

+1

在這種情況下,您可以在getInfo中返回一個'Option',如果出現錯誤則返回'None',否則返回包含實際值的'Some'(如果不是錯誤)。然後,您可以在控制器中進行模式匹配,並返回一個InternalServerError,如果它是'None'或Ok否 – thatsmydoing

+0

好的,非常感謝您的詳細解答!我想要兩個不同的錯誤代碼(404,500),所以我會嘗試返回'Either'並在'getInfo'中使用'response.status',並希望這可以工作... – Sonson123