Malla.Status (malla v0.0.1-rc.1)

Copy Markdown View Source

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

Options for describing a status in callback implementations.

t()

Functions

Expands a service response into a t/0 structure for public consumption.

Expands a service response into a t/0 structure for public/external use.

Expands a service response into a t/0 structure for public consumption.

Expands a service response into a t/0 structure.

Types

status_opt()

@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 the info field)
  • :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"

t()

@type t() :: %Malla.Status{
  code: integer(),
  data: map(),
  info: String.t(),
  metadata: map(),
  status: String.t()
}

user_status()

@type user_status() :: any() | t()

Functions

public(status)

@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.

public(srv_id, t)

@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 :status set to "internal_error" and :info indicating 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"}

status(status)

@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.

status(srv_id, t)

@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

  1. First we call callback Malla.Plugins.Status.status/1 that must be defined if we included plugin Malla.Plugins.Status in the indicated service. If we (or our plugins) implemented this function, it will be called first, using, as last resort, the base implementation.

  2. Callback function can return:

    • an string: we will consider this as :info field. We will try to extract :status field 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 :status is provided, we follow same rules as above.
  3. If no callback implementation matches this user_status:

    • we try to guess :status with same rules as above or it will be set to "unknown".
    • we include :info as 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.
  4. Then :metadata may be added calling Malla.Plugins.Status.status_metadata/1. If it was provided by the Malla.Plugins.Status.status/1 callback, it will be merged.