# `Rupa.Error`
[🔗](https://github.com/zero-one-group/rupa/blob/v0.1.0/lib/rupa/error.ex#L1)

A structured error: where, what, and the few values the message needs.

Nothing here renders a string until you ask for one. `message/1` builds the sentence from
`code` and `meta` on demand, so a run that produces no errors never builds a message, and a
run that produces a thousand pays for the ones you actually print.

`path` locates the offending node. What it is a path *through* depends on who built the
error: `Rupa.Schema.validate/1` returns paths through the schema, where `:of` is a list's
element, an integer is a tuple position, a string is a tagged branch, and `:defs` leads into
the definitions. Decoding returns paths through the data.

# `segment`

```elixir
@type segment() :: atom() | String.t() | non_neg_integer()
```

# `t`

```elixir
@type t() :: %Rupa.Error{code: atom(), meta: map(), path: [segment()]}
```

# `message`

```elixir
@spec message(t()) :: String.t()
```

Renders the error as a sentence.

    iex> [:name] |> Rupa.Error.new(:unknown_format, %{format: :ssn}) |> Rupa.Error.message()
    ":ssn is not one of Rupa's built-in formats"

# `new`

```elixir
@spec new([segment()], atom(), map()) :: t()
```

Builds an error.

    iex> Rupa.Error.new([:age], :unknown_option, %{option: :fmt})
    %Rupa.Error{path: [:age], code: :unknown_option, meta: %{option: :fmt}}

# `pointer`

```elixir
@spec pointer(t()) :: String.t()
```

The path as an RFC 6901 JSON pointer.

    iex> Rupa.Error.pointer(Rupa.Error.new([:addresses, 0, :street], :min))
    "/addresses/0/street"

    iex> Rupa.Error.pointer(Rupa.Error.new([], :unknown_type))
    ""

A segment is a field name, an index or a wire key. A `map_of` key can be any term when the map
came from Elixir rather than from JSON, so a segment with no string of its own -- a tuple, say
-- is written the way `inspect/1` writes it, escaped like any other.

    iex> Rupa.Error.pointer(Rupa.Error.new([:by, {1, 2}], :type))
    "/by/{1, 2}"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
