If I have a struct (with maybe some nested structs), and it has atom keys, what’s the most idiomatic way to get from user input in the form of a JSON request body to that struct? In my day job I use Scala + Play Framework and this is really easy to do, but I think in Elixir I’m getting caught up on the fact that user input -> atom is a DoS vector.
So Phoenix presents my JSON body to my controller function in conn.body_params, nicely parsed into a map - with string keys. I can’t parse this to a struct using Kernel.struct because the string keys are ignored - and I can’t convert them to atoms without a potential DoS.
The only thing I can think of that would probably work is converting that map back into JSON, and then decoding it using Poison’s as parameter. But that seems really wasteful because Plug already converted it from JSON -> map, then I’m doing map -> JSON -> struct.
I guess I’m wondering if there’s anything more idiomatic/automated/safe than just doing something like this in the controller:
Structs are actually just maps with a additional key __struct__, so %User{a: 1} is simply a map %{__struct__: User, a: 1} underneath. You can hack the map you have, by converting keys from strings to atoms, and then adding the proper __struct__ key.
From my experience, it’s just easier and more readable, when you have specialized functions in your module that declares that struct. and invoke them whenever you have need to create that struct from params map, You can add there proper validation etc with Ecto embeded schemas etc.
Thanks - I had left Ecto out when I started the Phoenix app because I’m not using a database but it looks like changeset is still the best approach here.