为播放框架http响应创建可写[Argonaut.Json]

时间:2015-02-01 14:19:08

标签: scala playframework argonaut

我正在尝试使用播放json库来改变此函数的实现,如此

def apply[T](action: => ApiResponse[T])(implicit tjs: Writes[T], ec: ExecutionContext): Future[Result] = {
    action.fold(
      err =>
        Status(err.statusCode) {
          JsObject(Seq(
            "status" -> JsString("error"),
            "statusCode" -> JsNumber(err.statusCode),
            "errors" -> Json.toJson(err.errors)
          ))
        },
      t =>
        Ok {
          JsObject(Seq(
            "status" -> JsString("ok"),
            "response" -> Json.toJson(t)
          ))
        }
    )
  }

像这样使用argonaut

def apply[T](action: => ApiResponse[T])(implicit encodeJson: EncodeJson[T], ec: ExecutionContext): Future[Result] = {
    action.fold(
      err =>
        Status(err.statusCode) {
          Json(
          "status" -> jString("error"),
          "statusCode" -> jNumber(err.statusCode),
          "errors" -> err.errors.asJson
          )
        },
      t =>
        Ok {
          Json(
          "status" -> jString("ok"),
          "response" -> t.asJson
          )
        }
    )
  }

但我得到

  

无法将argonaut.Json的实例写入HTTP响应。尝试   定义一个可写的[argonaut.Json]

对于Status {}阻止和Ok {}阻止,我在这里得到了一个有用的答案https://groups.google.com/forum/#!topic/play-framework/vBMf72a10Zc

所以我试着像这样创建隐式转换

implicit def writeableOfArgonautJson(implicit codec: Codec): Writeable[Json] = {
      Writeable(jsval => codec.encode(jsval.toString))
    }

我认为将json对象转换为字符串并将其提供给codec.encode,它应该将其转换为Array [Bytes]但是我得到了

  

无法猜测用于argonaut.Json的内容类型。尝试定义   一个ContentTypeOf [argonaut.Json]

jsval.nospaces.getBytes也返回Array [Bytes],所以我不知道是否可以用来帮助

所以虽然我认为最后一条错误消息意味着我只需要告诉它应该使用内容类型application.json我也觉得这可能是一个不必要的兔子洞,应该有一个更简单的方法来做到这一点。

编辑:它不是这样的兔子洞,因为定义contentType至少有东西编译,但我仍然想知道这是否正确

1 个答案:

答案 0 :(得分:3)

您似乎已回答了自己的问题,但要确认,Writable[A]是:

  1. 如何将类型A转换为Array[Bytes]
  2. 响应中使用的内容类型,也需要
  3. 当前字符编码
  4. 字符编码由隐式Codec实例处理,因此您需要隐式ContentTypeOf[A] Aargonaunt.Json

    implicit def contentTypeOf_ArgonautJson(implicit codec: Codec): ContentTypeOf[argonaut.Json] = {
      ContentTypeOf[argonaut.Json](Some(ContentTypes.JSON))
    }
    

    然后Writable[A] A ContentTypeOf[A] implicit def writeableOf_ArgonautJson(implicit codec: Codec): Writeable[argonaut.Json] = { Writeable(jsval => codec.encode(jsval.toString)) } Ok(myArgonautObject)个范围ExtraJsonHelpers(您刚刚定义):< / p>

    {{1}}

    正如你所指出的,那里有一个兔子洞。事实上,当你考虑到现在可以在任意多的动作中{{1}}进行{{1}}而无需进一步转换和标题设置样板时,它肯定会有点转移,但没有多少额外的代码。

    也许您可以将这些含义放在{{1}}特征中并将其混合到您的控制器中,以便更多地减少样板。