2017-01-30 91 views
3

我正在使用Akka Http向第三方API發出請求。答案是「application/json」,我想使用Akka Http將它們轉換爲自定義案例類。我願做這樣的事情:Akka Http - 如何解開ResponseEntity到CustomClass?

val request = RequestBuilding.Get("https://service.com/v1/api/items") 

val response : Future[ItemsResponse] = http.singleRequest(request).flatMap({ response => 
    Unmarshal(response.entity).to[ItemsResponse] 
}) 

這編譯失敗,因爲我缺少類型akka.http.scaladsl.unmarshalling.Unmarshaller的」隱式解組[akka.http.scaladsl.model.ResponseEntity ,com.mycompany.models.ItemsResponse]「

目前還不清楚這是什麼與akka http做這種慣用的方式是。我知道我可以使用spray-json,但我想了解如何在不導入其他庫的情況下執行此操作。 Akka Http似乎有可能,但文檔不清楚(至少對我而言)。

回答

4

最簡單的方法是使用噴霧JSON作爲它作爲阿卡HTTP的一部分:

import spray.json._ 
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport 

// change 2 to the number of attributes of ItemsResponse 
implicit val ItemsResponseFormat = jsonFormat2(ItemsResponse) 

這應該使你的現有代碼的編譯。

+0

謝謝!我沒有意識到spray-json現在是akka圖書館的一部分。這個伎倆。 –

+0

它實際上並不是作爲akka-http的一部分,我認爲Johan的問題非常有效。雖然akka-http-spray-json是akka-http的一部分,但底層的spray.json仍然需要單獨提供。我認爲。 https://doc.akka.io/docs/akka-http/current/common/json-support.html – akauppi

0

我認爲你的問題是有效的,有些情況下避免額外的依賴是有意義的。我從創建一個認證庫,在那裏我不想強制我的JSON庫偏好給這樣的庫的用戶。該庫需要使用JSON解組來理解令牌信息響應。

給代碼! :)

case class TokenInfo private (uid: String, realm: String, scope: Seq[String]) 

object TokenInfo { 
    private 
    def parseOpt(s: String): Option[TokenInfo] = { 

    util.parsing.json.JSON.parseFull(s) match { 
     case Some(map: Map[String,Any] @unchecked) => 

     val tmp: Map[String,Any] = map.collect { 
      case ([email protected] "uid",x: String) => k -> x 
      case ([email protected] "realm",x: String) => k -> x 
      case ([email protected] "scope",x: Seq[String] @unchecked) => k -> x 
      // other keys are ignored 
     }.toMap 

     if (tmp.size == 3) { 
      Some(TokenInfo(tmp("uid").asInstanceOf[String], tmp("realm").asInstanceOf[String], tmp("scope").asInstanceOf[Seq[String]])) 
     } else { 
      None 
     } 

     case _ => None 
    } 
    } 

    implicit 
    val unm: FromEntityUnmarshaller[TokenInfo] = { 
    PredefinedFromEntityUnmarshallers.stringUnmarshaller.map{ s => parseOpt(s).getOrElse{ 
     throw new RuntimeException(s"Unknown TokenInfo: $s") 
    }} 
    } 
} 

我選擇使用util.parsing.json它屬於斯卡拉。另一種選擇只是正則表達式的,但在這種情況下,我要麼修復預期的字段順序,要麼代碼可能變得複雜。