Categories
engineering

Converting outside (JSON) data into Elixir structs

Introduction

When building an Elixir-powered application, you may need to get some data from the outside and create a proper Elixir Struct from it. Structs are more convenient1 than maps2. If your application grows bigger than a couple of .ex files, you might consider using Structs as they provide a guarantee that only defined fields will be allowed in a Struct. In other words, it's easier to mess up key-value usage in a map, than in a Struct.

Problem

When using the Poison library to parse JSON, you get a map, which looks like this: my_map = %{"my_key" => "my_value"}.

If you want to convert that map to a Struct, this will NOT work:

You will get a ...does not implement the Access behaviour error. Structs in Elixir do not allow the Access behaviour3.

Solutions: options

Option 1

Use String.to_existing_atom/1 and Kernel.struct/2 to convert each key in the map. This requires writing some code:

Code snippet author: Patrick Oscity4.

Option 2

Use the as: [%MyStruct{}] option to Poison.decode!5 as recommended by David Tang6. This option does not require any additional coding. However, it also requires some naming discipline: all the fields of your Struct shall exactly match the fields in the incoming JSON. This will give you an error if the JSON has myKey and your Struct has my_key.

Option 3.

If you get more than one JSON object coming in as input, you can use the %{keys: :atoms!} option to Poison.Parser.parse!. With this you will get all JSON parsed into respective Structs. This requires the same naming discipline as Option 2.

A problem with Options 2 and 3

Poison does not respect7 the @enforce_keys attribute of Elixir's defstruct. That is, it will not check for you if the incoming JSON contains all keys that you need in your Struct.

Option 4.

Use Option 1 with @enforce_keys enabled in your Structs. This will guarantee that JSON data with missing keys will not end up in your Structs.

Not an option:

The ExConstructor library8 seems to be abandonded, I don't recommend using it.


1: Structs

2: Maps

3: Access behaviour

4: Elixir - Convert maps to struct - Stackoverflow

5: Poison - Hexdocs

6: Decoding JSON into Elixir Structs

7: Elixir Trickery: Cheating on Structs, And Why It Pays Off

8: ExConstructor - HexDocs

Leave a Reply

Your email address will not be published. Required fields are marked *