How to not encode nil field from Struct using Jason

Background

I have a TypedStruct with an optional field, :rank. This field is sometimes present and sometimes not.

  @derive Jason.Encoder
  typedstruct enforce: true do
    @typedoc "An order."

    field(:item_id, String.t())
    field(:rank, non_neg_integer(), enforce: false)
  end

The ideal situation here would be to generate the struct without the field, should the :rank parameter be missing. However, since I am dealing with structs, this is not possible, so I have to contempt with the nil value representing the absence of :rank.

The problem here is that when I use Jason.encode(...) , I am going to get a "rank": null in the result json object. I really don’t want this.

Question

Is there an option in Jason that allows me to not encode nil values, other than manually implementing the Encode Protocol myself?

other than manually implementing the Encode Protocol myself

From the “Deriving” section of the Jason.Encoder docs, there doesn’t appear to be a way.

However, Jason.Encode.map/2 appears to make it incredibly simple to implement Jason.Encoder on your own maps. It seems like something like this would do the trick:

defimpl Jason.Encoder do
  def encode(value, opts) do
    value
    |> Map.from_struct() # or take exactly the keys you want
    |> Map.reject(fn {_k, v} -> is_nil(v) end) # since 1.13
    |> Jason.Encode.map(opts)
  end
end
1 Like