我正在尝试调用Google地理编码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(_))
请帮我将结果解析为以下结果案例类:
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
^
答案 0 :(得分:6)
如您的错误消息中所述,您需要提供隐式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))
}
}