Elixir - Nested JSON parsing to structs

江枫思渺然 提交于 2020-02-18 09:53:55

问题


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.


回答1:


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{}})



回答2:


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.



来源:https://stackoverflow.com/questions/30855638/elixir-nested-json-parsing-to-structs

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!