# `TerminusDB.Error`
[🔗](https://github.com/thanos/terminusdb-client-elixir/blob/v0.3.3/lib/terminus_db/error.ex#L1)

A structured error returned by all `terminusdb_ex` operations.

Public API functions return `{:error, %TerminusDB.Error{}}` on failure; the
`!/1`-suffixed variants raise this same struct (it implements the `Exception`
behaviour). The `:reason` field classifies the failure so callers can pattern match
without inspecting HTTP status:

| `:reason`   | Meaning                                                |
| ----------- | ----------------------------------------------------- |
| `:transport`| Network/transport failure (connection, timeout, …)    |
| `:http`     | Non-2xx response with a non-JSON or unstructured body |
| `:api`      | TerminusDB API error (structured `api:*` JSON body)  |
| `:decode`   | Response body could not be decoded as JSON           |
| `:config`   | Missing or invalid client configuration               |

## Examples

    iex> error = TerminusDB.Error.api(400, %{
    ...>   "@type" => "api:DbCreateErrorResponse",
    ...>   "api:error" => %{"@type" => "api:DatabaseAlreadyExists"},
    ...>   "api:message" => "Database already exists.",
    ...>   "api:status" => "api:failure"
    ...> })
    iex> error.reason
    :api
    iex> error.api_type
    "api:DatabaseAlreadyExists"
    iex> Exception.message(error)
    "TerminusDB API error 400 (api:DatabaseAlreadyExists): Database already exists."

# `reason`

```elixir
@type reason() :: :transport | :http | :api | :decode | :config
```

# `t`

```elixir
@type t() :: %TerminusDB.Error{
  __exception__: term(),
  api_error: map() | nil,
  api_type: String.t() | nil,
  body: term(),
  cause: Exception.t() | nil,
  message: String.t(),
  reason: reason(),
  status: pos_integer() | nil
}
```

# `api`

```elixir
@spec api(pos_integer(), map()) :: t()
```

Builds an `:api` error from a TerminusDB structured error body.

TerminusDB returns JSON of the shape
`{"@type": "api:*ErrorResponse", "api:error": {...}, "api:message": "...", "api:status": "api:failure"}`.
The `@type` inside `api:error` (if present) is surfaced as `api_type` for easy
pattern matching, e.g. `"api:DatabaseAlreadyExists"`.

# `decode`

```elixir
@spec decode(Exception.t(), binary() | nil) :: t()
```

Builds a `:decode` error when the response body cannot be parsed as JSON.

# `http`

```elixir
@spec http(pos_integer(), term()) :: t()
```

Builds an `:http` error from a non-2xx status with an unstructured body.

## Examples

    iex> error = TerminusDB.Error.http(503, "service unavailable")
    iex> error.reason
    :http

# `transport`

```elixir
@spec transport(Exception.t()) :: t()
```

Builds a `:transport` error from an underlying exception (e.g. `Req.TransportError`).

## Examples

    iex> error = TerminusDB.Error.transport(Req.TransportError.exception(reason: :econnrefused))
    iex> error.reason
    :transport

---

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