I have been trying to JSON-encode structs defined in ExTwitter, such as ExTwitter.Model.Relationship for instance (the goal is to serialise them in a format which can be parsed from any language, or by a human easily), in a Mix.install/2
script.
I first learned that structs must be handled a bit specifically in such scripts (see Mix.install and structs).
After following the advice given, I had the expected error message:
(Protocol.UndefinedError) protocol Jason.Encoder not implemented for #ExTwitter.Model.Relationship<connections: nil, id: nil, id_str: nil, name: nil, screen_name: "TOTO", ...> of type ExTwitter.Model.Relationship (a struct), Jason.Encoder protocol must always be explicitly implemented.
If you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:
@derive {Jason.Encoder, only: [....]}
defstruct ...
It is also possible to encode all fields, although this should be used carefully to avoid accidentally leaking private information when new fields are added:
@derive Jason.Encoder
defstruct ...
Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(Jason.Encoder, NameOfTheStruct)
. This protocol is implemented for the following type(s): Any, Atom, BitString, Date, DateTime, Decimal, Float, Integer, Jason.Fragment, Jason.OrderedObject, List, Map, NaiveDateTime, Time
Since I do not own the struct I want to encode, I attempted to run Protocol.derive(Jason.Encoder, ExTwitter.Model.Relationship)
from inside a compiled method, but this does not work either (and the error message remains).
What works, so far, is leveraging Map.from_struct
.
Is this a caveat we want to see in the documentation, or is there maybe a way to make it work without Map.from_struct
, which I didn’t see?
Thanks!