View Source Errata.DomainError behaviour (Errata v0.1.0)

Support for creating custom domain error types, which can either be returned as error values or raised as exceptions.

Domain errors are named, structured types that represent error conditions within a problem domain or bounded context. Being named types means that errors have a meaningful name within a particular context, and that name should be part of the Ubiquitous Language of the context. Being structured types means that errors can have arbitrary contextual information attached to them for logging or debugging purposes.

Domain errors can be defined by creating an Elixir module that uses the Errata.DomainError module. Error types defined in this way are Elixir Exception structs with the following keys:

  • message - human readable string describing the nature of the error
  • reason - an atom describing the reason for the error, which can be used for pattern matching or classifying the error
  • extra - a map containing arbitrary contextual information or metadata about the error

Because these error types are defined with defexception/1, they can be raised as exceptions with raise/2. However, because they represent domain errors rather than system or infrastructure errors, in most cases it is more appropriate to create instances of the error structs using new/1 or create/1 and use them as return values from domain functions, either directly or wrapped in an error tuple such as {:error, my_domain_error}.

Usage

To define a new custom domain error type, use/2 the Errata.DomainError module in your own error module:

defmodule MyApp.SomeError do
  use Errata.DomainError,
    default_message: "something isn't right"
end

To create instances of the error, to use as an error return value from a function, say, you can use either new/1 or create/1, passing params with extra information as desired. Note that if you use create/1, you must first require the error module, since this callback is implemented as a macro. For example:

defmodule MyApp.SomeModule do
  require MyApp.SomeError, as: SomeError

  def some_function(arg) do
    {:error, SomeError.create(reason: :helpful_tag, extra: %{arbitrary: "metadata", arg: arg})}
  end
end

To raise errors as exceptions, simply use raise/2 passing extra params as the second argument if desired:

defmodule MyApp.SomeModule do
  require MyApp.SomeError, as: SomeError

  def some_function!(arg) do
    raise SomeError reason: :helpful_tag, extra: %{arbitrary: "metadata", arg: arg}
  end
end

Summary

Types

Type to represent the :env field of domain error structs.

Type to represent allowable keys to use in params use for creating domain error structs.

Type to represent allowable values to be passes as params for creating domain error structs.

t()

Type to represent domain error structs as defined by this module.

Callbacks

Invoked to create a new instance of a domain error struct with default values and the current ENV.

Invoked to create a new instance of a domain error struct with the given params and the current ENV.

Invoked to create a new instance of a domain error struct with default values.

Invoked to create a new instance of a domain error struct with the given params.

Invoked to convert a domain error to a plain, JSON-compatible map.

Functions

Creates a new domain error struct of the given error_type using the given params.

Creates a new domain error struct of the given error_type using the given params and env.

Formats the given domain_error as a string.

Returns true if term is a type of Errata.DomainError; otherwise returns false.

Types

@type env() :: %{
  context: Macro.Env.context(),
  context_modules: Macro.Env.context_modules(),
  file: Macro.Env.file(),
  function: Macro.Env.name_arity() | nil,
  line: Macro.Env.line(),
  module: module()
}

Type to represent the :env field of domain error structs.

This struct is a subset of of Macro.Env and contains the following fields:

  • context - the context of the environment; it can be nil (default context), :guard (inside a guard) or :match (inside a match)
  • context_modules - a list of modules defined in the current context
  • file - the current absolute file name as a binary
  • function - a tuple as {atom, integer}, where the first element is the function name and the second its arity; returns nil if not inside a function
  • line - the current line as an integer
  • module - the current module name
@type param() :: :message | :reason | :extra

Type to represent allowable keys to use in params use for creating domain error structs.

See also params/0.

@type params() :: Enumerable.t({param(), any()})

Type to represent allowable values to be passes as params for creating domain error structs.

This effectively allows for using either a map or keyword list with allowable keys defined by param/0.

@type t() :: %{
  :__struct__ => module(),
  :__exception__ => true,
  :message => String.t(),
  :reason => atom() | nil,
  :extra => map() | nil,
  :env => env() | nil,
  optional(atom()) => any()
}

Type to represent domain error structs as defined by this module.

Error structs are Exception structs that have additional fields to contain extra contextual information, such as an error reason or details about the context in which the error occurred.

Callbacks

@macrocallback create() :: Macro.t()

Invoked to create a new instance of a domain error struct with default values and the current ENV.

See create/1.

@macrocallback create(params()) :: Macro.t()

Invoked to create a new instance of a domain error struct with the given params and the current ENV.

Since this is a macro, the __ENV__/0 special form is used to capture the Macro.Env struct for the current environment and the public fields of this struct are placed in the exception struct under the :env key. This provides access to information about the context in which the error was created, such as the module, function, file, and line. See env/0 for further details.

Note that because this is a macro, callers must require/2 the error module to be able to use it.

@callback new() :: t()

Invoked to create a new instance of a domain error struct with default values.

See new/1.

@callback new(params()) :: t()

Invoked to create a new instance of a domain error struct with the given params.

@callback to_map(t()) :: map()

Invoked to convert a domain error to a plain, JSON-compatible map.

Functions

Link to this function

create(error_type, params)

View Source
@spec create(module() | struct(), params()) :: t()

Creates a new domain error struct of the given error_type using the given params.

Link to this function

create(error_type, params, env)

View Source
@spec create(module() | struct(), params(), Macro.Env.t()) :: t()

Creates a new domain error struct of the given error_type using the given params and env.

Link to this function

format_message(domain_error)

View Source
@spec format_message(t()) :: String.t()

Formats the given domain_error as a string.

Uses the :message field of the domain_error and combines the :reason field with it, if it is not nil.

Link to this macro

is_domain_error(term)

View Source (macro)

Returns true if term is a type of Errata.DomainError; otherwise returns false.

Allowed in guard tests.

Link to this function

to_json(domain_error, opts)

View Source