warning: the Jason.Encoder protocol has already been consolidated, an implementation for Any has no effect. If you want to implement protocols after compilation or during tests, check the “Consolidation” section in the documentation for Kernel.defprotocol/2 lib/encoder.ex:1
warning: redefining module Jason.Encoder.Any (current version loaded from /Users/dev/projects/haitracker.com/haitracker-be/_build/dev/lib/jason/ebin/Elixir.Jason.Encoder.Any.beam) lib/encoder.ex:1
with the following encoder
defimpl Jason.Encoder, for: Any do
def encode(%{__struct__: _} = struct, _options) do
skip_keys =
case struct.__struct__ do
Haitracker.User ->
[
:local_password_hash,
:login_status_message
]
# TODO: define skip keys for each model and pass to this function
_whatever ->
[]
end
struct
|> Map.from_struct()
|> sanitize_map(skip_keys)
|> Jason.encode!()
end
defp sanitize_map(map, skip_keys) do
filter = fn {key, val} ->
cond do
key in [:__meta__, :__struct__] ->
false
is_map(val) ->
Ecto.assoc_loaded?(val)
key not in skip_keys ->
true
true ->
false
end
end
map
|> Enum.filter(filter)
|> Enum.into(%{})
end
end
I am wondering if there is a better way to encode all of the schemas I have using Jason with just single encoder config file so that all of the encoding options are defined at one place.
Requirement is to exclude __meta__ and __struct__ fields and if some association is not loaded, we also need to skip these fields. you can call these keys to be global skip keys and values. and I want to exclude few keys per schema/model. i.e local skip_keys
Why not use @derive for each supported type? Sure, it’s not as automatic as what you want, but it’d be less error-prone since it’s more explicit. And it would usually be just a few lines of code, which you can actually automate with a macro for your ecto schemas.
It would be probably more performant than what you’ve shown above as well …
What is the use case here? Are you defining these encoders to return JSON for an HTTP endpoint? If so you probably want to look into json views which deal with a variety of downsides that the encoder approach creates.
Because sometimes lets say I have the associations loaded based on some condition and sometimes not. I need to make it generic so that I can use for admin panel. Using @derive means static.
Can I skip the field completely because if I encode Ecto.Association.NotLoaded and return nil that is totally incorrect. Association is just not loaded, doesn’t mean its having nil value