繁体   English   中英

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

[英]How to read a json response from a akka-http response entity using json4s

我正在尝试调用谷歌地理编码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))
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM