{"id":22628267,"url":"https://github.com/soundtrackyourbrand/forma","last_synced_at":"2025-04-11T19:03:59.760Z","repository":{"id":62429659,"uuid":"107328332","full_name":"soundtrackyourbrand/forma","owner":"soundtrackyourbrand","description":"Typespec based parsing of JSON-like data for Elixir","archived":false,"fork":false,"pushed_at":"2019-11-29T16:35:24.000Z","size":30,"stargazers_count":27,"open_issues_count":3,"forks_count":1,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-06T00:25:27.851Z","etag":null,"topics":["elixir","json","parsing","typespec"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soundtrackyourbrand.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-17T21:55:58.000Z","updated_at":"2024-05-31T15:51:22.000Z","dependencies_parsed_at":"2022-11-01T20:05:28.669Z","dependency_job_id":null,"html_url":"https://github.com/soundtrackyourbrand/forma","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soundtrackyourbrand%2Fforma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soundtrackyourbrand%2Fforma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soundtrackyourbrand%2Fforma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soundtrackyourbrand%2Fforma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soundtrackyourbrand","download_url":"https://codeload.github.com/soundtrackyourbrand/forma/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248441472,"owners_count":21104000,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","json","parsing","typespec"],"created_at":"2024-12-09T01:19:08.561Z","updated_at":"2025-04-11T19:03:59.725Z","avatar_url":"https://github.com/soundtrackyourbrand.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"**forma**  \n_[swe] verb. /fạ̊r:ma/_  \nto adjust; adapt\n\n[![Build Status](https://travis-ci.org/soundtrackyourbrand/forma.svg?branch=master)](https://travis-ci.org/soundtrackyourbrand/forma)\n\n# forma\n\nApplies typespecs to JSON-like data.\n\nThis module can parse JSON-like data (such as maps with key strings)\ninto a more structured form by trying to map it to conform to a\nmodule's typespec.\n\nThis can generally be useful when interfacing with external data\nsources that provide you data as JSON or MessagePack, but that you\nwish to transform into either proper structs or richer data types\nwithout a native JSON representation (such as dates or sets) in\nyour application.\n\nIt is heavily inspired by Go's way of dealing with JSON data.\n\n\n```elixir\ndefmodule User do\n  defstruct [:id, :name, :age, :gender]\n\n  @type t :: %__MODULE__{\n    id: String.t,\n    name: String.t,\n    age: non_neg_integer(),\n    gender: :male | :female | :other | :prefer_not_to_say\n  }\nend\n\nForma.parse(%{\"id\" =\u003e \"1\", \"name\" =\u003e \"Fredrik\", \"age\" =\u003e 30, \"gender\" =\u003e \"male\"}, User)\n# =\u003e {:ok, %User{id: \"1\", name: \"Fredrik\", age: 30, gender: :male}}\n```\n\nForma tries to figure out how to translate its input to a typespec. However, not all\ntypes have natural representations in JSON, for example dates, or don't want to expose\ntheir internals (opaque types).\n\nIf you're in control of the module defining the type, you can implement the `__forma__/2`\nfunction to handle parsing input to your desired type\n\n```elixir\ndefmodule App.Date do\n  @opaque t :: Date\n\n  # first argument is the type to be parsed in this module\n  def __forma__(:t, input) do\n    case Date.from_iso8601(input) do\n      {:ok, date} -\u003e date\n      {:error, reason} -\u003e raise reason\n    end\n  end\nend\n```\n\nIf you're not in control of the module, you can pass a parser along as an optional\nargument,\n\n```elixir\ndefmodule LogRow do\n  defstruct [:log, :timestamp]\n\n  type t :: %__MODULE__{\n    log: String.t,\n    timestamp: NaiveDateTime.t\n  }\nend\n\ndate = fn input -\u003e\n  case NaiveDateTime.from_iso8601(input) do\n    {:ok, datetime} -\u003e datetime\n    {:error, err} -\u003e raise err\n  end\nend\nparsers = %{{NaiveDateTime, :t} =\u003e date}\nForma.parse(%{\"log\" =\u003e \"An error occurred\", \"timestamp\" =\u003e \"2015-01-23 23:50:07\"}, LogRow, parsers)\n```\n\nThe number of arguments to the parser functions depends on if the type is parameterized\nor not (`MapSet.t` vs `MapSet.t(integer)`).\n\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed\nby adding `forma` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:forma, \"~\u003e 0.7.1\"}\n  ]\nend\n```\n\nDocumentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)\nand published on [HexDocs](https://hexdocs.pm). Once published, the docs can\nbe found at [https://hexdocs.pm/forma](https://hexdocs.pm/forma).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoundtrackyourbrand%2Fforma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoundtrackyourbrand%2Fforma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoundtrackyourbrand%2Fforma/lists"}