2016-07-16 10 views
10

Poisonを使用してスラックAPIに送信するJSONのマップをエンコードしています。これは私を与えるもの毒である:私は、JSONの糸くずの中にあることを置くときスラック用にPoisonを使用してJSONにエンコードする

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

それが有効なJSONであると言いますが、スラックは「無効なペイロード」を応答します。

私はこの

{"text":"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296"} 

に見えるようにJSONを変更した場合、それは動作します。誰が私がこれで間違っているのか知っていますか?エンコードされた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 

はJSONを作成する部分である

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 

を処理するメッセージ

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を送信するためのライブラリの一部であります最後のブロックで

+0

関連するコントローラ機能のソースを投稿することはできますか?おそらく 'json(conn、data)'の代わりに 'json(conn、Poison.encode!(data))'を呼び出すでしょう。 – Dogbert

+0

私がやっていることをよりよく理解するためのコードをいくつか追加しました。 – humdinger

+0

"これはPoisonが私に与えるものです:..."コードのどこからこの値を得ましたか? – Dogbert

答えて

2

リクエストペイロードはJSONが2回エンコードされているようです: 最初に出力文字列{"text":"..."}を返し、その文字列が再びエンコードされます。 JSONはオブジェクトだけでなく文字列もエンコードすることができるので、上記のエンコードでは"{\"text\":\"...\"}"の出力が得られます。 これは、オブジェクトのJSONエンコード表現を含む文字列です。

ただし、Slack APIでは、"..."の文字列ではなく、{"text": "..."}という形式のオブジェクトが必要です。後者は引き続き有効なJSONですが、APIに関しては有効なリクエストではありません。そのため、「無効なペイロード」エラーが返されます。

ここでは、オブジェクトが2度目にエンコードされる場所は完全にわかりません。上記のコードは大丈夫ですが、おそらく他の処理ステップがこれらのコードスニペットにありません。私はあなたのコードを慎重に2つのPoison.encode!呼び出しがいくつかのデータに適用されるパスのために調べることをお勧めします。

しかし、これを回避する方法がありますが、根本原因の2つの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で送信する場合は注意が必要です。繰り返しますが、根本的な原因を修正することをお勧めしますが、状況に応じて、この回避策も実行可能です。