Snodo.JSONValue (snodo v0.2.0)

Copy Markdown View Source

The JSON value rule every result, content map, and metadata map must satisfy.

A JSON value here is nil, a boolean, a number, a string, a list of JSON values, or a map whose keys are strings and whose values are JSON values. Atom keys and atom values are rejected. The protocol carries these values through untouched, so accepting atoms would mean guessing at encoding and silently resolving collisions between :name and "name".

Elixir domain layers usually return atom-keyed maps and structs, so a value arriving from application code often needs converting first. encodable!/1 does that:

iex> Snodo.JSONValue.encodable!(%{name: "jason", tags: [:json, :parser]})
%{"name" => "jason", "tags" => ["json", "parser"]}

Snodo.Result.structured/2, Snodo.Resource.json/3, and the content builders all validate with valid?/1 and raise on anything else.

Summary

Functions

Converts an Elixir term into a JSON value, raising when it cannot.

Returns whether a term is a JSON value under the rule above.

Functions

encodable!(value)

@spec encodable!(term()) :: term()

Converts an Elixir term into a JSON value, raising when it cannot.

The rules are fixed so the result is predictable:

  • atom keys become strings, and a map that would collide two keys onto one string raises rather than dropping either;
  • atom values become strings, except nil, true, and false;
  • Date, Time, DateTime, NaiveDateTime, URI, and Version become their canonical string forms;
  • any other struct becomes a map of its fields;
  • tuples, PIDs, references, functions, and ports raise, because there is no correct JSON form to pick for them. A keyword list is a list of tuples and therefore raises; convert it with Map.new/1 first.

Strings are returned unchanged and are not checked for UTF-8 validity; encoding catches that later.

valid?(value)

@spec valid?(term()) :: boolean()

Returns whether a term is a JSON value under the rule above.