Кодирование карты в JSON с использованием Poison для использования со Slack

Я использую 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 ответ

Решение

Похоже, что ваш запрос полезен в 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, поэтому вам следует быть осторожным, если вы хотите отправлять строки, закодированные в чистом JSON, через API. Опять же, я рекомендую устранить основную причину, но в зависимости от вашей ситуации этот обходной путь также может быть жизнеспособным.

Другие вопросы по тегам