Normandy.JSON (normandy v2.2.0)

View Source

The one place Normandy encodes and decodes JSON.

Library

Normandy encodes and decodes with Jason, which is a hard dependency. There is no :adapter setting. decode/1 returns string-keyed maps for objects.

Structs

Before Jason sees a term, every struct in it, at any depth, is either kept or replaced by a plain map:

  • A struct with its own Jason.Encoder implementation (@derive Jason.Encoder, a defimpl, or one Jason ships: Date, DateTime, Decimal, ...) is kept, and that implementation decides its fields. Its fields are not walked.
  • Any other struct becomes its map without :__struct__ and :__meta__ (an Ecto schema's, whose encoder raises), and its values are walked the same way.

A term JSON cannot express (a tuple, a pid, a reference, a function) is left as it is: Jason raises on it, and encode/2 returns that exception.

Text for the model

The JSON text Normandy writes into a message for the model (a tool result's text, a map given as message content) lists every plain map's keys sorted by their text, at any depth, so the same value is the same text on every node and after a restart (on OTP 26+ a small atom-keyed map iterates its keys in atom-creation order). Values and list order are unchanged. A struct without its own Jason.Encoder is written as its fields, sorted like a plain map. A struct with its own encoder is encoded by that encoder, whose output is its own, and a Jason.OrderedObject keeps its order (the plain maps among its values are sorted).

Summary

Functions

Decodes a JSON string; objects become string-keyed maps.

Decodes a JSON string; raises Jason's exception when it is not JSON.

Encodes term, returning {:error, exception} with whatever Jason raised (Protocol.UndefinedError or Jason.EncodeError), or what walking term raised (an improper list).

Encodes term; raises Jason's exception when it cannot.

Functions

decode(json)

@spec decode(String.t()) :: {:ok, term()} | {:error, Exception.t()}

Decodes a JSON string; objects become string-keyed maps.

decode!(json)

@spec decode!(String.t()) :: term()

Decodes a JSON string; raises Jason's exception when it is not JSON.

encode(term, opts \\ [])

@spec encode(
  term(),
  keyword()
) :: {:ok, String.t()} | {:error, Exception.t()}

Encodes term, returning {:error, exception} with whatever Jason raised (Protocol.UndefinedError or Jason.EncodeError), or what walking term raised (an improper list).

encode!(term, opts \\ [])

@spec encode!(
  term(),
  keyword()
) :: String.t()

Encodes term; raises Jason's exception when it cannot.