通用喷雾客户端

时间:2014-07-02 08:13:45

标签: scala spray-json spray-client

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

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相同的格式化程序。

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

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

Space类似乎很好,即当我告诉泛型方法它将接收并返回Space时,没有错误。但是一旦我将Either带入方法调用,我就会得到以下编译器错误:

  

无法找到类型的证据参数的隐含值   spray.httpx.unmarshalling.Unmarshaller [要么[models.api.Failure,models.api.Success]。

我的期望是,在spray.json.DefaultJsonProtocol中隐含的,即在spray.json.StandardFormts中,会让我受到覆盖。

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

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")
}

有了上述内容,仍然会出现unmarshaller未解决的问题。非常感谢帮助..

感谢。

1 个答案:

答案 0 :(得分:3)

如果Either[A,B]Marshaller[A]位于Marshaller[B]特征内的定义范围内,则定义MetaMarshallers的默认编组器。但是,走另一个方向需要Unmarshaller。您需要为Unmarshaller定义范围Either[Failure, Success]。如果没有预期响应的具体知识,以及选择是否将响应解组为LeftRight的策略,则无法对此进行编码。例如,让我们假设您想要从非200响应中返回失败,并从200 json响应主体返回成功:

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(...)))
    }
  }

<强>更新

仔细研究一下,问题似乎是eitherFormat中的默认spray.json.StandardFormats不是RootJsonFormat,这是spray.httpx.SprayJsonSupport中定义的默认JSON unmarshaller所必需的}。定义以下隐式方法应该可以解决问题:

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