Reputation: 1291
Disclaimer: I've checked the question here and it does not answer mine.
I am trying to come up with a way for nested struct parsing of JSONs. Example:
{"name": "blah blah", "address": {"street": "smthing"}}
I want to reach this result:
%User{name: "blah blah", address: %Address{street: "smthing"}}
Because then it would be easier to plug validation (using Vex for exapmle).
I know that Poison supports the "as struct" option but it does not provide nesting. The above would be parsed:
%User{name: "blah blah", address: %{"street" => "smthing"}}.
I know I could write a decoder implementation for module User
but I guess that is not the intended use case and it would not be generic.
When wondering about an implementation I could not find a way to tell if an atom is a module... maybe I have to go with :code.is_loaded(module_name)
?
Anyway, before trying an implementation I would like to know if there is something I am not seeing.
Upvotes: 12
Views: 6237
Reputation: 1404
I believe the above is now possible with Poison:
defmodule User do
@derive [Poison.Encoder]
defstruct [:address]
end
defmodule Address do
@derive [Poison.Encoder]
defstruct [:street]
end
Poison.decode(response, as: %User{address: %Address{}})
Upvotes: 12
Reputation: 54674
Currently, the only option that I am aware of is to provide your own implementation for the Poison.Decoder
(note the trailing r
) protocol. This has the added benefit that you can have these conversions in one place and just need to write as: User
to get the address converted properly. For example:
defimpl Poison.Decoder, for: User do
def decode(task_list, options) do
Map.update! task_list, :address, fn address ->
Poison.Decode.decode(address, Keyword.merge(options, as: [Address]))
end
end
end
Note that the inner call to decode
is not from Poison.Decoder
, but Poison.Decode
, without the trailing r
in the module name. You will not get an error if you do use the wrong one, it just won't work, which can be a pain to debug.
In the long run, I think a bit of work needs to be done in Poison to make all of this more fun to use. Maybe a macro that will make it easier to write Poison.Decoder
implementations for custom structs. Maybe also support for nested struct options like as: %User{address: Address}
, that should not be too hard to implement. Also I think the module names Decode
and Decoder
are too easy to confuse and one of them should be renamed. If I have the time, maybe I will make those suggestions and set up a PR with Poison.
Upvotes: 5