Poison - Encoding issue (tuples)

Hey there,

I am using Poison to encode Elixir datastructures before sending them to a Phoenix API. This mostly works, except for tuples it seems:

** (Poison.EncodeError) unable to encode value: {:propose, "Appeltaart"}
    (poison 5.0.0) lib/poison/encoder.ex:439: Poison.Encoder.Any.encode/2
    (poison 5.0.0) lib/poison/encoder.ex:286: anonymous fn/4 in Poison.Encoder.Map.encode/3
    (poison 5.0.0) lib/poison/encoder.ex:281: Poison.Encoder.Map."-encode/3-lists^foldl/2-0-"/3
    (poison 5.0.0) lib/poison/encoder.ex:281: Poison.Encoder.Map.encode/3
    (poison 5.0.0) lib/poison.ex:44: Poison.encode!/2

After some digging I found out that (weirdly enough) Poison does not support encoding tuples. However, I read both in the documentation and in this GitHub issue that there is a workaround by providing your own implementation.

There is not a lot of explaination on how to do this. I basically made a file called tuple_encoder.ex somewhere in my project with the rest of my code files. In there I put the following code:

defimpl Poison.Encoder, for: Tuple do
  def encode(tuple, options) do
    tuple
    |> Tuple.to_list
    |> Poison.encode!
  end
end

However, I still get the exact same error. Does my custom implementation not get found and do I have to link/mention it somewhere? Is there another, better workaround?

I’m looking forwards to your advice!

Hey @Astarno it’s worth noting that your proposed implementation probably doesn’t do what you want it to do. The tuple you have {:propose, "Appeltaart"} looks like it’s from a keyword list eg: [propose: "Appeltaart"] which has a key value structure.

The implementation you are showing would turn that into a list, so the JSON would be [["propose", "Appeltaart"]]. If that’s what you want, great! If however what you want is a JSON object, then I would suggest just converting the datastructure to be a map.

1 Like

It should work, unless you made some typos somewhere or haven’t recompiled the project so that the protocols could get re-consolidated again. You can also try Jason instead of Posion:

iex(1)> t = {:propose, "Appeltaart"}
{:propose, "Appeltaart"}
iex(2)> Jason.encode t
{:error,
 %Protocol.UndefinedError{
   protocol: Jason.Encoder,
   value: {:propose, "Appeltaart"},
   description: "Jason.Encoder protocol must always be explicitly implemented"
 }}
iex(3)> Jason.encode (Tuple.to_list t)
{:ok, "[\"propose\",\"Appeltaart\"]"}

Although, as Ben noted above, it all depends on what kind of JSON you want to see at the end of the day.

Thanks for your replies @cloudytoday and @benwilson512!

The solution seemed to be that I forgot to add .ex to the end of my file. Code was indeed fine :slight_smile:

1 Like

I would try doing an rm -rf _build deps and then compiling everything.