使用Poison将映射编码到JSON以与Slack一起使用

时间:2016-07-16 19:15:46

标签: elixir slack-api elixir-poison

我正在使用Poison将地图编码为JSON,并将其发送到Slack API。这就是Poison给我的东西:

"{\"text\":\"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296\"}"

当我把它放入JSON lint时,它说它是有效的JSON,但是Slack响应“无效的有效载荷”。

如果我将JSON更改为这样

{"text":"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296"}

然后它有效。有谁知道我在哪里出错?我是否需要对编码的JSON进行额外处理,或者是否需要设置一些标头?

这是我的控制器

def create(conn, opts) do
    message = Message.create_struct(opts)
    response = Slack.Messages.send(message)

    case response do
      {:ok, data} ->
        render conn, json: Poison.encode!(data)
      {:error, reason} ->
        render conn, json: reason
    end
end

以下是发送消息的库的一部分

defmodule Slack.Messages do

  def format_simple_message(map) do
    text = map.description <> " " <> map.commits
    message = %{text: text}
  end

  def post_to_slack(map) do
    Slack.post(:empty, map)
  end

  def send(map) do
    map
    |> format_simple_message
    |> post_to_slack
  end

end

我的HTTPoison处理

defmodule Slack do
  use HTTPoison.Base

  @endpoint "http://url.com"

  def process_url() do
    @endpoint
  end

  def process_response_body(body) do
    body
    |> Poison.decode! # Turns JSON into map
  end

  def process_request_body(body) do
    body
    |> Poison.encode! # Turns map into JSON
  end
end

创建JSON的部分位于最后一个块中。

1 个答案:

答案 0 :(得分:2)

您的请求有效负载似乎是两次JSON编码: 首先它返回输出字符串{"text":"..."},然后再次编码该字符串。 JSON不仅可以对对象进行编码,还可以对字符串进行编码,因此再次对上面的编码将提供"{\"text\":\"...\"}"的输出。 也就是说,包含对象的JSON编码表示的字符串。

但是,Slack API需要{"text": "..."}形式的对象,而不是字符串"..."。后者仍然是有效的JSON,但就API而言,它不是有效的请求。这就是为什么你得到“无效的有效载荷”错误。

我不完全确定对象是第二次编码的位置。您上面的代码看起来没问题,但也许还有其他处理步骤不在这些代码段中。我建议您仔细检查代码,看看有两个Poison.encode!调用应用于某些数据的路径。

但是,有一个解决方法 - 尽管我强烈建议您找到并修复根本原因,即双JSON编码。在process_request_body/1中,您可以匹配参数 - 如果它已经是字符串,则跳过Poison.encode!。为此,请使用以下代码:

def process_request_body(body) when is_binary(body), do: body
def process_request_body(body)
  body
  |> Poison.encode! # Turns map into JSON
end

这将通过逐字传递字符串,并对其他任何内容进行JSON编码。 但是,这可能很危险,因为字符串仍然是JSON编码的有效输入,因此如果要通过API发送纯JSON编码的字符串,则必须小心。同样,我建议修复根本原因,但根据您的情况,这种解决方法也可能是可行的。