2016-07-16 107 views
10

Sto utilizzando Poison per codificare una mappa su JSON che la invierà all'API Slack. Questo è ciò che mi dà Veleno:Codifica della mappa su JSON utilizzando Poison per l'uso con Slack

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

Quando ho messo che in JSON pelucchi si dice che è valida JSON, ma Slack risponde "payload non valido".

Se cambio la JSON per assomigliare a questo

{"text":"changed readme fad996e98e04fd4a861840d92bdcbbcb1e1ec296"} 

allora funziona. Qualcuno sa dove sto andando male con questo? Devo eseguire un'ulteriore elaborazione sul JSON codificato o c'è qualche intestazione che devo impostare?

Ecco il mio controller

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 

Ecco parte della libreria per l'invio dei messaggi

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 

E il mio HTTPoison elaborazione

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 

La parte che crea il JSON è nell'ultimo blocco.

+0

È possibile pubblicare la sorgente della funzione di controllo pertinente? Probabilmente stai chiamando 'json (conn, Poison.encode! (Data))' invece di 'json (conn, data)'. – Dogbert

+0

Aggiunta del codice per dare un'idea migliore di ciò che sto facendo. – humdinger

+0

"Questo è ciò che Poison mi dà: ..." da dove nel codice hai preso questo valore? – Dogbert

risposta

2

Sembra che il carico utile della richiesta sia codificato JSON due volte: Inizialmente restituisce la stringa di output {"text":"..."} e quindi tale stringa viene nuovamente codificata. JSON non può solo codificare oggetti, ma anche stringhe, quindi la codifica sopra riportata darà un'uscita di "{\"text\":\"...\"}". Cioè, una stringa che contiene la rappresentazione codificata JSON di un oggetto.

Tuttavia, l'API Slack si aspetta un oggetto del modulo {"text": "..."}, non una stringa "...". Quest'ultimo è ancora valido JSON, ma non è una richiesta valida per quanto riguarda l'API. Questo è il motivo per cui viene restituito l'errore "payload non valido".

Dove non sono del tutto sicuro è dove l'oggetto è codificato una seconda volta. Il tuo codice sopra sembra ok, ma forse ci sono altri passaggi di elaborazione che non sono in quei frammenti di codice. Ti suggerirei di esaminare attentamente il tuo codice per un percorso in cui vengono applicate due chiamate Poison.encode! ad alcuni dati.

Tuttavia, esiste una soluzione alternativa, anche se consiglio vivamente di trovare e correggere la causa principale, la doppia codifica JSON. In process_request_body/1 è possibile associare l'argomento e, se è già una stringa, saltare lo Poison.encode!. Per fare ciò, utilizzare il seguente codice:

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

questo passerà attraverso le stringhe verbatim e JSON codificare qualsiasi altra cosa. Tuttavia, ciò può essere pericoloso perché una stringa è ancora un input valido per la codifica JSON, quindi è necessario fare attenzione se si desidera inviare stringhe codificate JSON pure sull'API. Ancora una volta, ti consiglio di correggere la causa principale, ma a seconda della situazione, questa soluzione alternativa potrebbe anche essere valida.

Problemi correlati