Akka HTTP:根据抽象类型创建HTTPResponse

时间:2018-08-08 11:54:12

标签: json scala akka akka-http

我们正在使用akka-http,并且需要根据逻辑返回多个响应。这就是为什么在我们的应用程序中有这样的响应层次:

object CustomHttpResponse extends DefaultJsonProtocol {
    implicit val formatter = new RootJsonWriter[CustomHttpResponse] {
        override def write(obj : CustomHttpResponse) : JsValue = obj match
        {
            case success : Success =>
                JsObject("type" -> "success".toJson, "value" -> success.toJson)
            case failure : Failure =>
                JsObject("type" -> "failure".toJson, "value" -> failure.toJson)
        }
    }
}

sealed trait CustomHttpResponse {
    def status : Boolean
}

object Success extends SprayJsonSupport with DefaultJsonProtocol {
    implicit val Formatter : RootJsonFormat[Success] = jsonFormat1(Success.apply)
}
case class Success(override val status : Boolean) extends CustomHttpResponse

object Failure extends SprayJsonSupport with DefaultJsonProtocol {
    implicit val Formatter : RootJsonFormat[Failure] = jsonFormat3(Failure.apply)
}
case class Failure(override val status : Boolean, cause : String) extends CustomHttpResponse

这些响应是根据我的条件生成的,并通过我的控制器帮助器方法生成的,如下所示:

def generateResponse(param1: String, param2: String): HttpResponse[CustomHttpResponse] = { .... }

HttpResponse类的正文是自定义的,例如:

case class HttpResponse[T <: CustomHttpResponse](statusCode : Int, body : T)

HttpResponse类只是DTO的一种,它实际上从控制器帮助程序获取值并返回到控制器。在控制器中,我们尝试从控制器帮助器方法中获取值,并将其设置为akka http complele(.. )方法,如下所示:

val response = generateResponse("data", "data2")
complete(response.statusCode, response.body)

在将主体传递给完整方法时,我们得到的是:

[ERROR] too many arguments for method complete: (m: => akka.http.scaladsl.marshalling.ToResponseMarshallable)akka.http.scaladsl.server.StandardRoute
[ERROR]  complete(responseMessage.statusCode,  responseMessage.body )

搜索后,发生此错误的原因是我们的HttpResponse类包含抽象类型,并且当我们将抽象类型值放入complete方法时,它将无法弄清楚是什么是CustomHttpResponse的格式化程序。甚至我们都在CustomHttpResponse随播对象中创建了所有格式化程序。引用来自:

akka http (un)marshall traitsJsonFormat for abstract class with generic parameter

我觉得,我们缺少了一些东西。那么,有人知道这到底是什么问题吗?处理这些鼻窦炎的方便方法是什么?

1 个答案:

答案 0 :(得分:0)

间接解决方案

我不知道与问题中提供的错误消息相关的根本问题的原因。但是,我认为您要解决的总体问题有一个更简单的解决方案。

创建“自定义” HttpResponse值的方式本质上是面向对象的。我认为可以消除所有自定义层次结构,并使用akka提供的标准HttpResponse类以及一种功能方法来代替它。

您可以编写响应操纵器函数,以根据条件更新响应:

val setStatus : HttpResponse => HttpResponse = 
  if(someCondition)
    (httpResponse) => httpResponse withStatus 200
  else
    (httpResponse) => httpResponse withStatus 500

val setHeaders : (Boolean) => HttpResponse => HttpResponse =
  (conditionProvided) => 
    if(conditionProvided)
      (httpResponse) => httpResponse withHeaders Seq(...)
    else
      (httpResponse) => httpResponse withHeaders Seq.empty[HttpHeader]

def defaultResponse : () => HttpResponse = HttpResponse()

然后可以在Route中使用它们来创建自定义响应:

val route : Route = {
  val internalCondition : Boolean = ???

  val responsePipeline : () => HttpResponse = 
    defaultResponse andThen setStatus andThen setHeaders(internalCondition)

  complete(responsePipeline())
}