json - 如何使用 json4s 从 akka-http 响应实体读取 json 响应

标签 json scala json4s akka-http

我正在尝试调用 google geocoding api 并检索响应。

lazy val geoCodingConnectionFlow: Flow[HttpRequest, HttpResponse, Any] =
  Http().outgoingConnectionHttps(config.getString("services.geoCodingApiHost"), config.getInt("services.geoCodingApiPort"))

def geoCodingRequest(request: HttpRequest): Future[HttpResponse] = Source.single(request).via(geoCodingConnectionFlow).runWith(Sink.head)
/**
 * This call to google service is limited
 * @see https://developers.google.com/maps/documentation/geocoding/#Limits
 */
def ?(l: GeoLocation)(implicit ec: ExecutionContext): Future[Either[String, List[Result]]] = {
  val latlang = s"17.3644264,78.3896741"
  import org.json4s.native.Serialization
  import org.json4s.NoTypeHints
  import akka.http.scaladsl.model._
  import akka.http.scaladsl.unmarshalling._
  implicit val materializer = ActorMaterializer()
  implicit val executor = system.dispatcher
  implicit val formats = Serialization.formats(NoTypeHints)
  geoCodingRequest(RequestBuilding.Get(s"${config.getString("services.geoCodingApiUrlPart")}?latlng=$latlang&key=${config.getString("services.geoCodingApiKey")}")).flatMap { response =>
    val nonBinaryType = ContentTypes.`application/json`
    def responseEntity: HttpEntity = response.entity
    response.status match {
      case OK if (response.entity.contentType == ContentTypes.`application/json`) => Unmarshal(response.entity).to[List[Result]].map(Right(_)) 
      case BadRequest => Future.successful(Left(s"$latlang: incorrect Latitude and Longitude format"))
      case _ => Unmarshal(response.entity).to[String].flatMap { entity =>
        val error = s"Google GeoCoding request failed with status code ${response.status} and entity $entity"
        Future.failed(new IOException(error))
      }
    }
  }
}

}

尝试执行此操作时出现以下编译错误!
Service.scala:78: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.Unmarshaller[akka.http.scaladsl.model.ResponseEntity,List[com.thenewmotion.geocode.Result]]
          case OK if(response.entity.contentType ==  ContentTypes.`application/json`)=> Unmarshal(response.entity).to[List[Result]].map(Right(_))

请帮助我将结果解析为以下 Result 案例类:
package com.thenewmotion.geocode

case class Address(
  long_name: String,
  short_name: String,
  types: List[String]
)

case class Result(
  address_components: List[Address],
  formatted_address: String,
  types: List[String]
)

case class Response(
  results: List[Result],
  status: Status
) {
  def allResults = status match {
    case Ok => Right(results)
    case e: Error => Left(e)
  }
}

/** @see https://developers.google.com/maps/documentation/geocoding/#StatusCodes */
sealed trait Status

case object Ok extends Status

sealed trait Error extends Status
case object ZeroResults    extends Error
case object OverQuotaLimit extends Error
case object Denied         extends Error
case object InvalidRequest extends Error
case class OtherError(description: String) extends Error

                                                                                                                     ^

最佳答案

如您的错误消息所述,您需要提供一个隐式 Unmarshaller[akka.http.scaladsl.model.ResponseEntity,List[com.thenewmotion.geocode.Result]]否则框架将不知道如何将响应实体转换为您的模型 List[com.thenewmotion.geocode.Result] .

或者,您可以先使用内置的 unmarshaller 将实体转换为 String,然后使用 spray-json 将 json 字符串解析为目标模型:

import akka.http.scaladsl.unmarshalling.Unmarshal
import spray.json._

implicit val modelJsonReader = new JsonReader[List[com.thenewmotion.geocode.Result]] {
// See https://github.com/spray/spray-json on how to implement JsonReader
}

def parseJson(str: String): List[com.thenewmotion.geocode.Result] = {
  // parse using spray-json
  str.parseJson.convertTo[List[com.thenewmotion.geocode.Result]]
}

response.status match {
  case OK if (response.entity.contentType == ContentTypes.`application/json`) =>
    Unmarshal(response.entity).to[String].map { jsonString =>
      Right(parseJson(jsonString))
    }
  case BadRequest => Future.successful(Left(s"$latlang: incorrect Latitude and Longitude format"))
  case _ => Unmarshal(response.entity).to[String].flatMap { entity =>
    val error = s"Google GeoCoding request failed with status code ${response.status} and entity $entity"
    Future.failed(new IOException(error))
  }
}

关于json - 如何使用 json4s 从 akka-http 响应实体读取 json 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35541738/

相关文章:

java输出一个格式的树

scala - 从对象中的 val 定义列表

scala - 带有无序字段的 Json4s 自定义序列化程序

json - scala - 使用 json4s 分解时如何更改字段名称?

python - 访问和替换 json 中的子类别对象

json - 如何使用nodejs cloudant模块更新cloudant中的数据?

javascript - 动态嵌套对象循环js

java - 从 Java 调用可变长度参数 Scala 函数的语法?

windows - Spark 发射 : find version

json - json4s中 `render`的用途