Provides core utilities for standardizing status and error responses.
This module defines the Malla.Status.t/0 struct and the foundational logic for
converting internal application responses into this standardized structure. It works
in tandem with the Malla.Plugins.Status plugin, which provides an extensible
callback-based system for defining status patterns.
For a complete guide on how to use the status system, including defining custom statuses, see the Status and Error Handling guide.
Summary
Types
@type status_opt() :: {:info, term()} | {:code, integer()} | {:status, term()} | {:data, list() | map()} | {:metadata, list() | map()}
Options for describing a status in callback implementations.
Available options:
:info- Human-readable message (becomes theinfofield):code- Numeric code, typically HTTP status code:status- Override the status identifier string:data- Additional structured data (map or keyword list):metadata- Service metadata (map or keyword list)
If no :status is provided, we try to find one based on original user_status:
- if it was an atom or binary, that is the
:status - if it is a tuple, we check if the first element is an atom or binary, even if nested
- otherwise we set it to "unknown"
Functions
@spec public(user_status()) :: t()
Expands a service response into a t/0 structure for public consumption.
This is a convenience wrapper around public/2 that uses the service ID
from the current process dictionary using Malla.get_service_id!/0.
@spec public(Malla.id(), user_status()) :: t()
Expands a service response into a t/0 structure for public/external use.
Similar to status/2, but provides additional safety to avoid exposing internal
errors to external systems. If we find no result from the Malla.Plugins.Status.status/1
callback, the Malla.Plugins.Status.status_public/1 callback is invoked to handle
the unmatched status.
By default, status_public/2 will:
- Log a warning with the full user_status and a unique reference
- Return a sanitized status with
:statusset to "internal_error" and:infoindicating the reference
Services can override status_public/2 to customize this behavior, such as exposing
certain error patterns or implementing custom logging strategies.
Examples
iex> Malla.Status.public(MyService, :ok)
%Malla.Status{status: "ok"}
iex> Malla.Status.public(MyService, {:badarg, %{some: :internal_data}})
%Malla.Status{status: "internal_error", info: "Internal reference 1234"}
@spec status(user_status()) :: t()
Expands a service response into a t/0 structure for public consumption.
This is a convenience wrapper around status/2 that uses the service ID
from the current process dictionary using Malla.get_service_id!/0.
@spec status(Malla.id(), user_status()) :: t()
Expands a service response into a t/0 structure.
This function converts internal service responses (statuses and errors) into a standardized Status struct for external consumption.
Conversion Process
First we call callback
Malla.Plugins.Status.status/1that must be defined if we included pluginMalla.Plugins.Statusin the indicated service. If we (or our plugins) implemented this function, it will be called first, using, as last resort, the base implementation.Callback function can return:
- an string: we will consider this as
:infofield. We will try to extract:statusfield from the user_status (if it is an atom or string or first element of a tuple) or it will set to "unknown". - a list of options (
status_opt/0). Struct will be populated according to this. If no:statusis provided, we follow same rules as above.
- an string: we will consider this as
If no callback implementation matches this user_status:
- we try to guess
:statuswith same rules as above or it will be set to "unknown". - we include
:infoas a string representation of the whole user_status, unless it is a two-elements tuple, in that case we use only the second part of it.
- we try to guess
Then
:metadatamay be added callingMalla.Plugins.Status.status_metadata/1. If it was provided by theMalla.Plugins.Status.status/1callback, it will be merged.