# `LightningWeb.API.Errors`
[🔗](https://github.com/OpenFn/lightning/blob/main/lib/lightning_web/api/errors.ex#L1)

Turns an invalid changeset into error entries and a problem.

A context function reports invalid data as a changeset.
`LightningWeb.API.FallbackController` hands it to `problem/3`, which makes one
entry per error and picks the response code from the entries. Each entry
points at the part of the request it is about, such as a body key, a position
in a list, or a path segment, using the request's key names rather than the
schema's. Web code that checks the request itself builds entries with
`entry/2` and returns them through `refuse/1`.

An entry's code comes from the error's `code:` option, or from Ecto's own
options. An error with neither raises. There is no fallback code.

# `entry`

```elixir
@type entry() :: %{
  :code =&gt; atom(),
  :detail =&gt; String.t(),
  optional(:pointer | :parameter | :header | :path) =&gt; String.t()
}
```

# `location`

```elixir
@type location() ::
  [segment()]
  | {:parameter, String.t()}
  | {:header, String.t()}
  | {:path, String.t()}
```

# `segment`

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

# `entry`

```elixir
@spec entry(location(), {String.t(), keyword()}) :: entry()
```

One entry, for a producer that validates the request itself.

`error` is shaped as a changeset error, `{message, opts}`, and is coded and
interpolated the same way. `location` is a list of the request's keys and
positions, or `{:parameter, name}`, or `{:header, name}`, or `{:path, name}`
for a path segment, named by its route parameter. A `path` names a segment,
never carries its text.

# `from_changeset`

```elixir
@spec from_changeset(Ecto.Changeset.t(), %{required(atom()) =&gt; atom()}, [
  {:path, [atom()]}
]) :: [
  entry()
]
```

Every error in `changeset` and its children, as entries.

`renames` maps an Ecto field to the request's key, at any depth:
`%{project_users: :members}`. An error whose options carry `key:` is placed
there instead of at its field: one request key, or a list of the request's
keys and positions below the error's level.

`path:` lists the top-level request keys the request sent as path segments
rather than in its body, so their errors name the segment: `path: [:key]`.

Raises `ArgumentError` for an error with no code, and for an error on a
child the request didn't send, since neither can be placed in the request.

# `not_visible`

```elixir
@spec not_visible() :: {String.t(), keyword()}
```

The error for a reference in the body that matches nothing the caller can
see. Something missing and something hidden get the same error.

# `parameters`

```elixir
@spec parameters(Ecto.Changeset.t()) :: LightningWeb.API.Problem.t()
```

The 400 `invalid_parameter` problem for a refused changeset over a route's
query parameters, with one entry per error, each naming its parameter.

# `pointer`

```elixir
@spec pointer([segment()]) :: String.t()
```

An RFC 6901 JSON Pointer in URI-fragment form: each key has `~` written
`~0` and `/` written `~1`, then the whole is percent-encoded wherever a
character isn't allowed in a fragment.

# `problem`

```elixir
@spec problem(Ecto.Changeset.t(), %{required(atom()) =&gt; atom()}, [{:path, [atom()]}]) ::
  LightningWeb.API.Problem.t()
```

The problem for a refused changeset. The first rule that matches wins:

  1. any error coded `storage_failed`: 500 `internal`, since the server
     failed, not the request;
  2. any error coded `not_ready`: 503 `not_ready`, with no entries;
  3. every error `exceeds_limit`: 402 `exceeds_limit`;
  4. otherwise 422 `invalid`, without any `exceeds_limit` entries.

A value in the body that must be unique and is already in use is a `taken`
entry in the 422 like any other problem with the body. 409 is only for the
state of the record the URL names.

# `refuse`

```elixir
@spec refuse([entry()]) :: :ok | {:error, LightningWeb.API.Problem.t()}
```

`:ok` when there are no entries, otherwise a 422 `invalid` problem holding
them all, for a producer that checks the request itself.

# `refuse_parameters`

```elixir
@spec refuse_parameters({:ok, value} | {:error, Ecto.Changeset.t()}) ::
  {:ok, value} | {:error, LightningWeb.API.Problem.t()}
when value: term()
```

`{:ok, value}` passed through, or `{:error, changeset}` over a route's query
parameters turned into its 400 `invalid_parameter` problem.

---

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