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

Copy Markdown View Source

Plugin that provides status and error response management with extensible callbacks.

This plugin works with Malla.Status to provide a complete status handling system. To use the system, include this plugin in your service's plugin list, and use Malla.Status.status/2 or Malla.Status.public/2 to convert statuses.

This plugin provides default implementations for the the following callbacks:

See Malla.Status for details.

Summary

Callbacks

Converts a status term into a standardized status description.

Adds or modifies metadata in a generated status structure.

Handles unmatched statuses when using Malla.Status.public/1.

Types

span_id()

@type span_id() :: String.t() | [atom()]

status_return()

@type status_return() :: String.t() | [Malla.Status.status_opt()] | :cont

Callbacks

status(user_status)

(optional)
@callback status(Malla.Status.user_status()) :: status_return()

Converts a status term into a standardized status description.

This callback receives any term representing a status or error and returns either a status description or :cont to delegate to the next plugin.

Return Values

The callback can return:

  1. Keyword list with status description options:

    • :info (string) - Human-readable message (becomes info field)
    • :code (integer) - Numeric code, typically HTTP status code
    • :status (string/atom) - Override the status identifier
    • :data (map/keyword) - Additional structured data
    • :metadata (map/keyword) - Service metadata
  2. String - Sets the info field directly (simple case)

  3. :cont - Skip this handler and try the next plugin

Examples

# Simple message
defcb status(:not_found), do: [info: "Resource not found", code: 404]

# With data
defcb status({:invalid_field, field}),
  do: [info: "Invalid field", code: 400, data: [field: field]]

# String return
defcb status(:timeout), do: "Operation timed out"

# Continue to next plugin
defcb status(_), do: :cont

Remember to always include a catch-all clause returning :cont to allow other plugins to handle unknown statuses.

Implemented Status Codes

This base implementation provides out-of-the-box a number of status patterns that are converted to statuses, but you can implement it too to support new ones or override the default ones.

Status PatternHTTP CodeMessage
:ok200Success
{:ok_data, data}200Success (with data)
:created201Created
:deleted200Deleted
:normal_termination200Normal termination
:redirect307Redirect
:bad_request400Bad Request
:content_type_invalid400Content type is invalid
{:field_invalid, field}400Field is invalid
{:field_missing, field}400Field is missing
{:field_unknown, field}400Field is unknown
:file_too_large400File too large
:invalid_parameters400Invalid parameters
{:parameter_invalid, param}400Invalid parameter
{:parameter_missing, param}400Missing parameter
{:request_op_unknown, op}400Request OP unknown
:request_body_invalid400The request body is invalid
{:syntax_error, field}400Syntax error
:token_invalid400Token is invalid
:token_expired400Token is expired
:unauthorized401Unauthorized
:forbidden403Forbidden
:not_found404Not found
:resource_invalid404Invalid resource
{:method_not_allowed, method}405Method not allowed
:verb_not_allowed405Verb is not allowed
:timeout408Timeout
:conflict409Conflict
:not_allowed409Not allowed
:service_not_found409Service not found
{:service_not_found, service}409Service not found (specific)
:gone410Gone
:unprocessable422Unprocessable
:internal_error500Internal error
{:internal_error, ref}500Internal error (with ref)
:service_not_available500RPC service unavailable
:not_implemented501Not implemented
{:service_not_available, service}503Service not available (specific)

status_metadata(t)

(optional)
@callback status_metadata(Malla.Status.t()) :: Malla.Status.t()

Adds or modifies metadata in a generated status structure.

This callback is invoked after a status has been fully constructed, allowing plugins to inject additional metadata based on the service context or status content.

Examples

# Conditional metadata based on status
defcb status_metadata(%{status: "internal_error"} = status) do
  metadata = Map.put(status.metadata, "support_contact", "support@example.com")
  %{status | metadata: metadata}
end

# Add service information to metadata
defcb status_metadata(status) do
  metadata = Map.merge(status.metadata, %{
    "service" => "MyService",
    "version" => "1.0.0",
    "node" => to_string(node())
  })
  %{status | metadata: metadata}
end

defcb status_metadata(status), do: status

Use Cases

  • Adding service identification (name, version, node)
  • Including timestamps or request IDs
  • Adding environment information (production, staging, etc.)
  • Injecting support contact information for errors
  • Adding trace IDs for distributed tracing

status_public(user_status)

(optional)
@callback status_public(Malla.Status.user_status()) :: Malla.Status.t() | :cont

Handles unmatched statuses when using Malla.Status.public/1.

This callback is invoked when public/2 encounters a status that has no matching status/1 callback implementation. It allows services to customize how internal errors are exposed to external consumers.

By default, this callback:

  1. Generates a unique reference number
  2. Logs a warning with the full status details and reference
  3. Returns a sanitized status struct with "internal_error" and the reference

Examples

# Default behavior (log and hide details)
defcb status_public(user_status) do
  ref = rem(:erlang.phash2(:erlang.make_ref()), 10000)
  Logger.warning("Internal error: #{inspect(ref)}: #{inspect(user_status)} (#{srv_id})")
  %Malla.Status{
    status: "internal_error",
    info: "Internal reference #{ref}",
    code: 500
  }
end

defcb status_public(user_status) do
  # Fall back to default for everything else
  :cont
end

Use Cases

  • Customizing which errors are safe to expose externally
  • Adding custom logging or monitoring for unhandled statuses
  • Providing different sanitization strategies per service
  • Routing certain error patterns to external error tracking services