⚠️ Use gleam/dynamic
from the Gleam standard library instead! ⚠️
A Gleam library for transforming Erlang or Elixir data into Gleam data.
decode
allows you to build Decoder
s, which can then be used to transform
data from Erlang or Elixir into type-safe Gleam data!
If you're only concerned with decoding data from one of either Elixir or Erlang, skip ahead to the relevant section, and then read the Gleam example.
Let's say that you have an Elixir struct that you'd like to work with in your Gleam code.
%User{name: "Jose Valim", age: 25}
Remember that under the hood, Elixir structs are just maps with a __struct__
field, and module names are just atoms!
%{__struct__: Elixir.User, name: "Jose Valim", age: 25}
So you have an Elixir function that returns one of these User structs, that you'd like to use in your Gleam code.
# user.ex
@spec get_user() :: User.t()
Let's say that you have an Erlang record that you'd like to work with in your Gleam code.
-record(user, {name :: string(), age :: non_neg_integer()}).
Remember that Erlang records are just tagged tuples under the hood!
{user, "Joe Armstrong", 35}
So you have an Erlang function that returns one of these user records.
%% user.erl
-spec get_user() -> user()
In order to translate this Elixir or Erlang data into a format that Gleam can work with, we'll need to explain to Gleam how it maps onto Gleam types, and probably define some custom types in the process.
// user.gleam
import decode.{Decoder, decode_dynamic, atom_field, element, map2, int, string}
// First, we define the Gleam type that we'd like to transform this data into.
pub type User {
User(
name: String,
age: Int
)
};
// Second, we define a decoder that will be used to transform an Elixir User
// struct into our custom Gleam type.
pub fn ex_user_decoder() -> Decoder(User) {
map2(
User,
atom_field("name", string()),
atom_field("age", int())
)
}
// Or an Erlang user record into our custom Gleam type.
pub fn erl_user_decoder() -> Decoder(User) {
map2(
User,
element(1, string()),
element(2, int())
)
}
// Third, we create an external function that calls the Elixir function
// that returns a User struct.
fn external ex_external_get_user() -> Dynamic
= "Elixir.User" "get_user"
// Or the Erlang function that returns a user record.
fn external erl_external_get_user() -> Dynamic
= "user" "get_user"
// And finally, we write the functions that perform the decoding!
pub fn ex_create_user() -> Result(User, String) {
ex_external_create_user()
|> decode_dynamic(ex_user_decoder())
pub fn erl_create_user() -> Result(User, String) {
erl_external_create_user()
|> decode_dynamic(erl_user_decoder())
}
Add gleam_decode
to the deps section of your rebar.config
file.
{deps, [
{gleam_decode, "1.7.0"}
]}.
If you are having trouble understanding how to use this library, or find yourself dealing with a decoding problem that you don't believe is solvable with the current API, please open an issue!
Most of this library is based on the Elm language's JSON decoding library (elm/json), with some attention paid also to the community-driven "JSON extras" library (elm-community/json-extra). Thanks to them for the great ideas!