Akka Http - 如何将ResponseEntity解组为CustomClass?

时间:2017-01-30 06:33:09

标签: scala akka unmarshalling akka-http

我正在使用Akka Http向第三方API发出请求。响应是“application / json”,我想使用Akka Http将它们转换为自定义案例类。我想做这样的事情:

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]”的隐式unmarshaller“

我不清楚用akka http执行此操作的惯用方法是什么。我知道我可以使用spray-json,但我想了解如何在不导入其他库的情况下执行此操作。似乎有可能与Akka Http,但文件不清楚(至少对我来说)。

2 个答案:

答案 0 :(得分:4)

最简单的方法是使用spray-json作为Akka 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)

这应该使您现有的代码编译。

答案 1 :(得分: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 (k@ "uid",x: String) => k -> x
          case (k@ "realm",x: String) => k -> x
          case (k@ "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")
    }}
  }
}

我选择使用Scala中的util.parsing.json。另一种选择只是正则表达式,但在这种情况下,我要么修复预期的字段顺序,要么代码可能变得复杂。