Malachi.HTTP.Problem (malachi v0.22.7)

View Source

The one error shape of every HTTP surface, the legacy dashboard (Malachi.Dashboard) and the console (Malachi.Console.Router): an RFC 9457 application/problem+json body whose type is a translation key and whose data travel in extension members, as section 10.3 of docs/design/operator-interfaces.md sets. The body carries no title or detail: Malachi.I18n.locale/0 is node global, so a phrase translated here would come out in the node's language rather than the operator's, and the client translates the key itself.

from_error/1 is the single map from an error a handler meets to its status, key and members, so two endpoints meeting the same error answer it the same way. build/2 and for_error/1 are pure and return the status, the headers and the encoded body, which each endpoint frames with its own transport.

Example

iex> {status, type, members} = Malachi.HTTP.Problem.from_error({:missing_role, :editor, :viewer})
iex> {status, type, members}
{403, "errors.auth.missing_role", %{"required_role" => "editor", "role" => "viewer"}}

Summary

Types

A translation key from types/0.

Functions

The response for type with extension members, as {status, headers, body}. The status comes from types/0, so a key and its status cannot disagree. Headers are the content type plus what the status obliges: WWW-Authenticate on a 401 and Retry-After (whole seconds, rounded up) on a 429 that carries retry_after_ms. Raises on a key that is not in types/0, which a test meets before a client does.

build/2 for the error from_error/1 classifies.

The status, translation key and extension members for an error a handler met. Covers the session and role refusals of Malachi.Console.Access, the user and ACL writes of Malachi.Auth, a machine version refusal (Malachi.Cluster.MachineVersion.refusal?/1) and the policy refusals of Malachi.Policies. Anything else is a control plane that did not answer usefully, a 503 the same request may pass later.

The status type is answered with.

Every translation key a problem response can carry, mapped to its HTTP status.

Types

type()

@type type() :: String.t()

A translation key from types/0.

Functions

build(type, members \\ %{})

@spec build(type(), map()) :: {pos_integer(), [{String.t(), String.t()}], binary()}

The response for type with extension members, as {status, headers, body}. The status comes from types/0, so a key and its status cannot disagree. Headers are the content type plus what the status obliges: WWW-Authenticate on a 401 and Retry-After (whole seconds, rounded up) on a 429 that carries retry_after_ms. Raises on a key that is not in types/0, which a test meets before a client does.

for_error(error)

@spec for_error(term()) :: {pos_integer(), [{String.t(), String.t()}], binary()}

build/2 for the error from_error/1 classifies.

from_error(error)

@spec from_error(term()) :: {pos_integer(), type(), map()}

The status, translation key and extension members for an error a handler met. Covers the session and role refusals of Malachi.Console.Access, the user and ACL writes of Malachi.Auth, a machine version refusal (Malachi.Cluster.MachineVersion.refusal?/1) and the policy refusals of Malachi.Policies. Anything else is a control plane that did not answer usefully, a 503 the same request may pass later.

status(type)

@spec status(type()) :: pos_integer()

The status type is answered with.

types()

@spec types() :: %{required(type()) => pos_integer()}

Every translation key a problem response can carry, mapped to its HTTP status.