Current section
Files
Jump to
Current section
Files
README.md
**forma** _[swe] verb. /fạ̊r:ma/_ to adjust; adapt[](https://travis-ci.org/soundtrackyourbrand/forma)# formaApplies typespecs to JSON-like data.This module can parse JSON-like data (such as maps with key strings)into a more structured form by trying to map it to conform to amodule's typespec.This can generally be useful when interfacing with external datasources that provide you data as JSON or MessagePack, but that youwish to transform into either proper structs or richer data typeswithout a native JSON representation (such as dates or sets) inyour application.It is heavily inspired by Go's way of dealing with JSON data.```elixirdefmodule User do defstruct [:id, :name, :age, :gender] @type t :: %__MODULE__{ id: String.t, name: String.t, age: non_neg_integer(), gender: :male | :female | :other | :prefer_not_to_say }endForma.parse(%{"id" => "1", "name" => "Fredrik", "age" => 30, "gender" => "male"}, User)# => {:ok, %User{id: "1", name: "Fredrik", age: 30, gender: :male}}```Forma tries to figure out how to translate its input to a typespec. However, not alltypes have natural representations in JSON, for example dates, or don't want to exposetheir internals (opaque types).If you're in control of the module defining the type, you can implement the `__forma__/2`function to handle parsing input to your desired type```elixirdefmodule App.Date do @opaque t :: Date # first argument is the type to be parsed in this module def __forma__(:t, input) do case Date.from_iso8601(input) do {:ok, date} -> date {:error, reason} -> raise reason end endend```If you're not in control of the module, you can pass a parser along as an optionalargument,```elixirdefmodule LogRow do defstruct [:log, :timestamp] type t :: %__MODULE__{ log: String.t, timestamp: NaiveDateTime.t }enddate = fn input -> case NaiveDateTime.from_iso8601(input) do {:ok, datetime} -> datetime {:error, err} -> raise err endendparsers = %{{NaiveDateTime, :t} => date}Forma.parse(%{"log" => "An error occurred", "timestamp" => "2015-01-23 23:50:07"}, LogRow, parsers)```The number of arguments to the parser functions depends on if the type is parameterizedor not (`MapSet.t` vs `MapSet.t(integer)`).## InstallationIf [available in Hex](https://hex.pm/docs/publish), the package can be installedby adding `forma` to your list of dependencies in `mix.exs`:```elixirdef deps do [ {:forma, "~> 0.7.1"} ]end```Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)and published on [HexDocs](https://hexdocs.pm). Once published, the docs canbe found at [https://hexdocs.pm/forma](https://hexdocs.pm/forma).