Change keyword list to map for json encoding

Hi,
I have this structure:

[%{"next" => "http://www.example.com/test?foo=bar&page=4"},
%{"prev" => "http://www.example.com/test?foo=bar&page=2"},
%{"first" => "http://www.example.com/test?foo=bar&page=1"},
%{"last" => "http://www.example.com/test?foo=bar&page=5"}]

With Poison.encode! I get following:

"[{\"next\":\"http://www.example.com/test?foo=bar&page=4\"},
{\"prev\":\"http://www.example.com/test?foo=bar&page=2\"},
{\"first\":\"http://www.example.com/test?foo=bar&page=1\"},
{\"last\":\"http://www.example.com/test?foo=bar&page=5\"}]"

After parsing in JS with JSON.parse I recieve an array with 4 fields. What I need is a simple struct without an array, so I can access it in JS via struct.next, sruct.prev

How can I transform the keyword list to a struct, which gives me the JSON I need?
Any idea?

Which keywordlist? I only see a list of maps. And how should the struct look like?

What is the JSON you need?

Can you post an example JSON how it should look like?

Oh, thought [{:a, 1}, {:b, 2}] is a keyword list. But right, I have maps, aiiii.

The JSON I would like to get should look this way:

{
  "next":"http://www.example.com/test?foo=bar&page=4",
  "prev":"http://www.example.com/test?foo=bar&page=2",
  "first":"http://www.example.com/test?foo=bar&page=1",
  "last":"http://www.example.com/test?foo=bar&page=5"
}

From a map:

%{
  "next" => "http://www.example.com/test?foo=bar&page=4",
  "prev" => "http://www.example.com/test?foo=bar&page=2",
  "first" => "http://www.example.com/test?foo=bar&page=1",
  "last" => "http://www.example.com/test?foo=bar&page=5"
}

That should totally do it.

Of course you can also create a proper struct and implement Poison.Encoder and Poison.Decoder as needed, if that is necessary or not, you need to decide by yourself.

But encoding a keyword list isn’t possible, AFAIK, as poison always tries to make an elixir list a JSON array.

For your example Enum.reduce(list, &Map.merge/2) should work, but I’d first consider why you’re having that list in the first place.

1 Like

Hmmm, so I have to rewrite the code I am using. Thought I could transform the list, so Poison.encode could work.

Thanks,
will change my code to give me the structure I need.

You can transform the list, as shown by @LostKobrakai, but you really should consider using a map on the elixir side from the beginning.

A list of maps, one key each feels wrong, especially when you say, that you consider this a single entity at the other end of the application.

2 Likes

Yep, think this is not the best idea. Will change the code.

Edit: Changed it now to a simple map, was not that difficult as I thought. Tank you both for your answers :slight_smile:

This was really the core issue because had they been tuples:

iex(1)> key_values = [
...(1)>   {"next","http://www.example.com/test?foo=bar&page=4"},
...(1)>   {"prev","http://www.example.com/test?foo=bar&page=2"},
...(1)>   {"first","http://www.example.com/test?foo=bar&page=1"},
...(1)>   {"last","http://www.example.com/test?foo=bar&page=5"}
...(1)> ]
[
  {"next", "http://www.example.com/test?foo=bar&page=4"},
  {"prev", "http://www.example.com/test?foo=bar&page=2"},
  {"first", "http://www.example.com/test?foo=bar&page=1"},
  {"last", "http://www.example.com/test?foo=bar&page=5"}
]
iex(2)> my_map = Map.new(key_values)
%{
  "first" => "http://www.example.com/test?foo=bar&page=1",
  "last" => "http://www.example.com/test?foo=bar&page=5",
  "next" => "http://www.example.com/test?foo=bar&page=4",
  "prev" => "http://www.example.com/test?foo=bar&page=2"
}
iex(3)>
1 Like