RintoError (rinto_error v0.2.0)

Copy Markdown View Source

Defines an application Error with validated kinds, public payloads, and exception text.

Use the guides for design, application usage, Ecto, custom sources, and output and logging.

Catalog

defmodule MyApp.Error do
  use RintoError

  catalog do
    entry :local
    entry :missing, http_status: 404
    entry :broken, as: :unavailable, http_status: 503
  end
end

entry declares a constructable internal kind. entry_for Source, :kind also registers an exact struct type; its module must be available at compile time. Both accept these optional literal values:

  • as: — public name, defaulting to the internal kind. Mapping happens once; output-only names are not constructable unless separately declared.
  • http_status: — integer from 100 to 599, looked up by internal kind. Missing statuses raise ArgumentError only when http_status/1 is called.
  • doc: — string included in catalog details, without affecting error behavior.

Kinds and output names must be atom literals other than nil, true, and false. Variables, module attributes, and computed expressions are rejected, as are duplicate kinds, source registrations, options, and unknown options. A module may have one catalog; an empty or omitted catalog accepts no inputs.

kinds() lists declared kinds; kinds(:full) includes names, statuses, and docs; kinds(:public) groups those details by output name. All preserve declaration order. source_kinds(), payload_kinds(), and statuses() expose source registrations, changed output names, and explicitly configured statuses.

Construction

require MyApp.Error, as: Error
Error.new(:missing)
Error.new(kind: :broken, raw: :db_down, data: %{attempt: 2})

new/2 constructs an Error and records the call site in metadata.origin. It evaluates input and message once; a non-nil message, including "", replaces the existing message. exception/1 and raise Error, opts do not record origin.

Atom input sets both kind and raw. Map/keyword input defaults raw to nil and requires kind unless a registered __source__ supplies it. Unknown fields raise KeyError; missing required fields raise ArgumentError. Registered structs use RintoError.Source; unregistered structs raise ArgumentError.

Undeclared literal kinds passed directly to new fail compilation. Dynamic inputs and builder results are validated at construction, raising ArgumentError for undeclared kinds. Direct struct construction requires kind and raw but, like direct map updates, bypasses catalog validation.

Output

to_payload/1 returns %{kind: atom(), data: map(), errors: [term()]} with the mapped kind, excluding raw, message, metadata, and the source selector. Without a source, data and details are emitted as stored. Source conversion uses RintoError.Source.to_payload/2; details are never recursively converted or mapped.

If JSON.Encoder or Jason.Encoder is loaded when the Error module compiles, the corresponding implementation is generated and encodes through to_payload/1. The library does not send responses or emit logs.

Options

  • inspect_opts: — options for field values in exception text. They merge over config :rinto_error, inspect_opts: [...], which merges over defaults [pretty: true, width: 80, limit: :infinity, printable_limit: :infinity]. Application configuration is read per call; module options are captured at compile time. Empty lists inherit prior options. This does not affect inspect(error) or payloads.

Override message/1 in the Error module to customize exception/log text; super(error) reuses the default formatter. Default text contains kind, message, data, errors, and metadata, excluding raw and the source selector.

Ecto registration is always explicit. Its standard RintoError.Source implementation follows the same protocol contract as custom sources. See RintoError.Source for implementation and build validation details.

Generated types

Reference types on your application module, such as MyApp.Error.t():

  • t() / t(raw_type) — Error with arbitrary / specified raw data. The parameter constrains raw, not kind; the kind field remains atom().
  • known_kind() — union of declared internal kinds; none() for an empty catalog.
  • payload() — public output; kind_detail() — one catalog declaration.
  • origin() / metadata() — construction location / diagnostic context.

Typespecs do not add runtime checks; construction enforces catalog membership.

Migrating earlier APIs

Replace positional declarations and public:, expose_as:, construct:, or status: with entry :kind, as: :name, http_status: 422. Replace changeset: / changeset_kind: with entry_for Ecto.Changeset, :kind. The use RintoError options exclude_default_sources and override_sources are no longer supported. To replace the supplied Changeset implementation, configure config :rinto_error, exclude_default_sources: [Ecto.Changeset] before compiling the dependency, then define your own defimpl. Protocol implementations apply globally per source type; use a wrapper struct for coexisting behaviors.

Replace expand/2 or two-argument builders with build/1 returning attributes. Replace @behaviour RintoError.Payload and to_payload(error) with the protocol function to_payload(_source, error) in the same defimpl. Both protocol functions are required; the first output argument only selects the source type. Manual attributes must set __source__ explicitly instead of relying on raw's type. Ecto type descriptions now use t objects instead of scalar names or composite name keys; see RintoError.Changeset.

Summary

Functions

Declares this module's error table. A module may have only one catalog. The block may contain only entry and entry_for calls.

Functions

catalog(list)

(macro)

Declares this module's error table. A module may have only one catalog. The block may contain only entry and entry_for calls.