defmodule Rabbit.SerializerError do
@moduledoc false
defexception [:message]
end
defmodule Rabbit.Serializer do
@moduledoc """
A behaviour to implement serializers.
To create a serializer, you just need to implement the `c:encode/1` and `c:decode/1`
callbacks,
## Example
defmodule MySerializer do
@behaviour Rabbit.Serializer
@impl true
def encode(data) do
# Create a binary from data
end
@impl true
def decode(binary) do
# Create data from a binary
end
end
## Default Serializers
By default, Rabbit comes with serializers for the following content types:
* `"application/etf"` - built in erlang term format.
* `"application/json"` - requires the `Jason` library to be added.
You can modify the available serializers through application config:
config :rabbit,
serializers: %{
"application/custom-type" => MySerializer
}
"""
@type t :: module()
@doc """
Callback invoked to encode the given data to a binary.
"""
@callback encode(any()) :: {:ok, binary()} | {:error, Exception.t()}
@doc """
Callback invoked to decode the given binary to data.
"""
@callback decode(binary()) :: {:ok, any()} | {:error, Exception.t()}
@defaults %{
"application/json" => Rabbit.Serializers.JSON,
"application/etf" => Rabbit.Serializers.ETF
}
@doc false
@spec encode(Rabbit.Serializer.t(), any()) :: {:ok, any()} | {:error, Exception.t()}
def encode(serializer, data) do
do_serialize(serializer, :encode, data)
end
@doc false
@spec encode!(Rabbit.Serializer.t(), any()) :: any
def encode!(serializer, data) do
case encode(serializer, data) do
{:ok, data} -> data
{:error, error} -> raise Rabbit.SerializerError, Exception.message(error)
end
end
@doc false
@spec decode(Rabbit.Serializer.t(), any()) :: {:ok, any()} | {:error, Exception.t()}
def decode(serializer, data) do
do_serialize(serializer, :decode, data)
end
@doc false
@spec decode!(Rabbit.Serializer.t(), any()) :: any
def decode!(serializer, data) do
case decode(serializer, data) do
{:ok, data} -> data
{:error, error} -> raise Rabbit.SerializerError, Exception.message(error)
end
end
@doc false
@spec defaults() :: map()
def defaults do
@defaults
end
defp do_serialize(serializer, fun, data) do
apply(serializer, fun, [data])
end
end