通用喷雾客户 [英] Generic Spray-Client

查看:107
本文介绍了通用喷雾客户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Spray在Scala中创建通用HTTP客户端.这是类的定义:

I'm trying to create a generic HTTP client in Scala using spray. Here is the class definition:

object HttpClient extends HttpClient

class HttpClient {

  implicit val system = ActorSystem("api-spray-client")
  import system.dispatcher
  val log = Logging(system, getClass)

  def httpSaveGeneric[T1:Marshaller,T2:Unmarshaller](uri: String, model: T1, username: String, password: String): Future[T2] = {
    val pipeline: HttpRequest => Future[T2] = logRequest(log) ~> sendReceive ~> logResponse(log) ~> unmarshal[T2]
    pipeline(Post(uri, model))
  }

  val genericResult = httpSaveGeneric[Space,Either[Failure,Success]](
    "http://", Space("123", IdName("456", "parent"), "my name", "short_name", Updated("", 0)), "user", "password")

}

对象utils.AllJsonFormats具有以下声明.它包含所有模型格式.在另一端"使用了相同的类,即,我还编写了API,并在其中使用了带有Spray-can和spray-json的相同格式化程序.

An object utils.AllJsonFormats has the following declaration. It contains all the model formats. The same class is used on the "other end" i.e. I also wrote the API and used the same formatters there with spray-can and spray-json.

object AllJsonFormats
  extends DefaultJsonProtocol with SprayJsonSupport with MetaMarshallers with MetaToResponseMarshallers with NullOptions {

当然,该对象具有对models.api.Space,models.api.Failure和models.api.Success的序列化的定义.

Of course that object has definitions for the serialization of the models.api.Space, models.api.Failure and models.api.Success.

Space类型看起来不错,即当我告诉通用方法它将接收并返回Space时,没有错误.但是,一旦将Either引入方法调用中,就会出现以下编译器错误:

The Space type seems fine, i.e. when I tell the generic method that it will be receiving and returning a Space, no errors. But once I bring an Either into the method call, I get the following compiler error:

找不到类型为证据的隐式值 spray.httpx.unmarshalling.Unmarshaller [Either [models.api.Failure,models.api.Success]].

could not find implicit value for evidence parameter of type spray.httpx.unmarshalling.Unmarshaller[Either[models.api.Failure,models.api.Success]].

我的期望是,spray.json.DefaultJsonProtocol中隐式的一个,即Spray.json.StandardFormts中的隐式,将覆盖我.

My expectation was that the either implicit in spray.json.DefaultJsonProtocol, i.e. in spray.json.StandardFormts, would have me covered.

以下是我的HttpClient类,尝试最好是通用的: 更新:更清晰/可重复的代码示例

The following is my HttpClient class trying it's best to be generic: Update: Clearer/Repeatable Code Sample

object TestHttpFormats
  extends DefaultJsonProtocol {

  // space formats
  implicit val idNameFormat = jsonFormat2(IdName)
  implicit val updatedByFormat = jsonFormat2(Updated)
  implicit val spaceFormat = jsonFormat17(Space)

  // either formats
  implicit val successFormat = jsonFormat1(Success)
  implicit val failureFormat = jsonFormat2(Failure)
}

object TestHttpClient
  extends SprayJsonSupport {

  import TestHttpFormats._
  import DefaultJsonProtocol.{eitherFormat => _, _ }

  val genericResult = HttpClient.httpSaveGeneric[Space,Either[Failure,Success]](
    "https://api.com/space", Space("123", IdName("456", "parent"), "my name", "short_name", Updated("", 0)), "user", "password")
}

使用上述方法,仍然无法解决解组器的问题.帮助将不胜感激..

With the above, the problem still occurs where the unmarshaller is unresolved. Help would be greatly appreciated..

谢谢.

推荐答案

如果Marshaller[A]Marshaller[B]MetaMarshallers特征内定义的范围内,则Spra​​y为Either[A,B]定义默认的编组器.但是,要执行其他方向则需要Unmarshaller.您将需要为Either[Failure, Success]定义范围内的Unmarshaller.如果没有特定的预期响应以及如何选择是否将响应编组为LeftRight的策略,则无法对此进行编码.例如,假设您要在非200响应上返回失败",并从200 json响应正文中返回成功":

Spray defines a default marshaller for Either[A,B] if a Marshaller[A] and Marshaller[B] are in defined scope inside the MetaMarshallers trait. But, going the other direction requires an Unmarshaller. You will need to define an in-scope Unmarshaller for Either[Failure, Success]. This cannot be coded without specific knowledge of the expected response and what the strategy will be for choosing whether to unmarshall a response as a Left or as a Right. For example, let's say you want to return a Failure on a non-200 response and a Success from a 200 json response body:

type ResultT = Either[Failure,Success]
implicit val resultUnmarshaller: FromResponseUnmarshaller[ResultT] = 
  new FromResponseUnmarshaller[ResultT] {
    def apply(response: HttpResponse): Deserialized[ResultT] = response.status match {
      case StatusCodes.Success(200) => 
        Unmarshaller.unmarshal[Success](response.entity).right.map(Right(_))
      case _ => Right(Left(Failure(...)))
    }
  }

更新

更深入地看,问题似乎在于spray.json.StandardFormats中的默认eitherFormat不是RootJsonFormat,这是spray.httpx.SprayJsonSupport中定义的默认JSON解组器所必需的.定义以下隐式方法应该可以解决该问题:

Looking deeper into this, the problem appears to be that the default eitherFormat in spray.json.StandardFormats is not a RootJsonFormat, which is required by the default JSON unmarshaller defined in spray.httpx.SprayJsonSupport. Defining the following implicit method should solve the issue:

implicit def rootEitherFormat[A : RootJsonFormat, B : RootJsonFormat] = new RootJsonFormat[Either[A, B]] {
  val format = DefaultJsonProtocol.eitherFormat[A, B]

  def write(either: Either[A, B]) = format.write(either)

  def read(value: JsValue) = format.read(value)
}

我有一个可行的示例要点,希望可以解释您将如何使用它. https://gist.github.com/mikemckibben/fad4328de85a79a06bf3

I have an working example gist that hopefully explains how you would use this. https://gist.github.com/mikemckibben/fad4328de85a79a06bf3

这篇关于通用喷雾客户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆