Define your application's error vocabulary with a reusable Elixir error struct.
RintoError validates declared kinds, builds transport-independent public payloads,
and formats exception and log text. Public names and HTTP statuses are optional;
registered custom structs and Ecto changesets can supply their own error details.
Both use defimpl RintoError.Source with build/1 and to_payload/2 through
protocol dispatch. The supplied Changeset implementation can be excluded at
compile time so your application can provide its own (see the Ecto guide).
Why start at 0.2.0?
RintoError's first public release is 0.2.0. This is a deliberate release decision: the core error model, integration paths, tests, and bilingual guides form the baseline we have chosen to publish and maintain. The version marks that starting point; it does not imply a previously published 0.1.0 or a 1.0 API stability guarantee.
Installation
Requires Elixir ~> 1.17. Add RintoError to your dependencies and run mix deps.get:
def deps do
[
{:rinto_error, "~> 0.2.0"}
]
endAdd :rinto_error to import_deps in .formatter.exs for catalog formatting:
[
import_deps: [:rinto_error]
]Minimal usage
Return a business error
Declare only the kinds your application needs. Public names and HTTP statuses are optional:
defmodule MyApp.Error do
use RintoError
catalog do
entry :payment_timeout
end
end
defmodule MyApp.Payments do
require MyApp.Error, as: Error
def interpret_result({:ok, receipt}), do: {:ok, receipt}
def interpret_result({:error, :timeout}), do: {:error, Error.new(:payment_timeout)}
endThe function returns an ordinary error tuple containing your Error struct, so callers can match on its kind:
{:error, %MyApp.Error{kind: :payment_timeout}} =
MyApp.Payments.interpret_result({:error, :timeout})Error.new/1 validates the kind and records the construction location. This
example needs no HTTP or payload configuration and does not raise or log.
Respond to an error in Phoenix
For an HTTP application, extend the catalog with an optional public name and status (use this definition in place of the one above):
defmodule MyApp.Error do
use RintoError
catalog do
entry :payment_timeout, as: :payment_unavailable, http_status: 503
end
endIn an existing Phoenix application, a fallback controller can turn the same
{:error, error} result into an HTTP response:
defmodule MyAppWeb.FallbackController do
use MyAppWeb, :controller
alias MyApp.Error
def call(conn, {:error, %Error{} = error}) do
conn
|> put_status(Error.http_status(error))
|> json(Error.to_payload(error))
end
endSet action_fallback MyAppWeb.FallbackController in the calling controller and
return {:error, error} from its action. For the timeout above, the response has
status 503 and this JSON body:
{"kind":"payment_unavailable","data":{},"errors":[]}Business code still sees :payment_timeout; as: changes only the public name.
RintoError supplies the status and payload, while Phoenix sends the response.
Guides / 使用指南
Read these guides in order, or jump to the integration you need. Each guide is available in English and Chinese.
| Guide | English | 中文 |
|---|---|---|
| 1. Design and error model | English | 设计思想与错误模型 |
| 2. Application errors | English | 定义与使用应用错误 |
| 3. Ecto validation | English | Ecto 校验错误实践 |
| 4. Custom error structs | English | 接入自定义错误 struct |
| 5. Output and logging | English | 输出、日志与应用边界 |
For API contracts and options, see RintoError, RintoError.Source,
and RintoError.Changeset in the
API documentation.
License
MIT.