Starchoice.Decoder behaviour (starchoice v0.1.1) View Source

This module can be used from two different ways:

As a macro

To be defining decoders as macro, you need to use the Starchoice.Decoder module in your struct. It's declaration is highly (like totally) inspired by Ecto's schemas.

To see available options, take a look at put_field/3's documentation

Examples

defmodule User do
  use Starchoice.Decoder
  defstruct first_name: nil, age: nil

  defdecoder do
    field(:first_name)
    field(:age)
  end
end

User.__decoder__() # %Decoder{}
User.__decoder__(:default) # %Decoder{}

When you don't pass a name to the defdecoder/2 function, it defaults to default. So calling defdecoder do and defdecoder :default do is identical. This is because you might be interested in creating multiple decoders for the same struct like below:

defmodule User do
  use Starchoice.Decoder
  defstruct first_name: nil, last_name: nil, email: nil, age: nil

  defdecoder do
    field(:first_name)
    field(:age)
  end

  defdecoder :full do
    field(:first_name)
    field(:last_name)
    field(:email)
    field(:age)
  end
end

User.__decoder__() # %Decoder{fields: [{:first_name, _}, {:age, _}]}
User.__decoder__(:default) # %Decoder{fields: [{:first_name, _}, {:age, _}]}
User.__decoder__(:full) # %Decoder{fields: [{:first_name, _}, {:last_name, _}, {:email, _}, {:age, _}]}

And you can now use the module directly when calling Starchoice.decode/3 like:

iex> Starchoice.decode(input, User)
iex> Starchoice.decode(input, {User, :full})

Manually

You could also build decoder manually like the following:

defmodule User do
  defstruct email: nil, password: nil

  def mask_password(_), do: "MASKED"
end

User
|> Decoder.new()
|> Decoder.put_field(:email)
|> Decoder.put_field(:password, with: &User.mask_password/1)

# or

Decoder.new(User, [
  {:email, []},
  {:password, with: &User.mask_password/1}
])

To see available options, take a look at put_field/3's documentation

Link to this section Summary

Functions

Initiates a new Decoder, you can pass a list of fields with options.

Puts a field decoding in the decoder. Available options are

Link to this section Types

Specs

decoder_struct() :: module() | :map

Specs

field_definition() :: {atom(), [field_option()]}

Specs

field_option() ::
  {:required, boolean()}
  | {:with, Starchoice.decoder()}
  | {:default, any()}
  | {:sanitize, function()}

Specs

t() :: %Starchoice.Decoder{fields: [field_definition()], struct: module()}

Link to this section Functions

Link to this macro

defdecoder(name \\ :default, list)

View Source (macro)

Specs

defdecoder(atom(), [{:do, Macro.t()}]) :: Macro.t()
Link to this macro

field(name, opts \\ [])

View Source (macro)

Specs

field(atom(), [field_option()]) :: Macro.t()
Link to this function

new(struct, fields \\ [])

View Source

Specs

new(decoder_struct(), [field_definition()]) :: t()

Initiates a new Decoder, you can pass a list of fields with options.

To see available options, take a look at put_field/3's documentation

Link to this function

put_field(decoder, field, options \\ [])

View Source

Specs

put_field(t(), atom(), [field_option()]) :: t()

Puts a field decoding in the decoder. Available options are:

  • :required: Defines if a field is required, will caused a raise (or {:error, _} tuple) when the required field isn't present
  • :default: Specifies a fallback value in case the field is missing (can't be used with required: true)
  • :with: Specifies a decoder the decode the given field. Like the Starchoice.decode/3 call, it can support any valid decoder in Module, {Module, :decoder} and a function.
  • :sanitize: Specifies a sanitizer. By default, the value is sanitized by trimming the value and casting to nil if the value is "". Can either be a boolean or a function.

Link to this section Callbacks

Specs

__decoder__(atom()) :: t()