Request engine behind every resource module (REST only — no gateway).
Builds the Req call (Authorization: Bot <token>, Discord User-Agent), decodes
JSON, applies the bounded retry policy, and normalizes failures to
%Noizu.Discord.Error{}.
Return shapes
{:ok, decoded_body}— 2xx;decoded_bodyisnilfor empty (204) responses.{:ok, decoded_body, meta}— when the call is made withmeta: true.{:error, %Noizu.Discord.Error{}}.
meta is %{status: integer, attempts: pos_integer, rate_limit: rate_limit} where
rate_limit is built from the X-RateLimit-* headers (see rate_limit_meta/1).
Retry policy
- 429 — always retried (Discord rejects rate-limited requests without
applying them, so this is safe for POST/PATCH too). The delay is the JSON
retry_after(seconds, float), elseX-RateLimit-Reset-After, elseRetry-After, else exponential-ish backoff; clamped to:max_delay_ms. - 5xx — retried only for idempotent methods (
GET,HEAD,PUT,DELETE). - At most
:max_attempts(default 3) total attempts; then the last error is returned (tag: :rate_limitedfor a final 429).
Common per-call options
:meta—trueto receive{:ok, body, meta}.:reason— setsX-Audit-Log-Reason(URL-encoded) for moderation actions.
Summary
Functions
Percent-encodes one path segment (ids, emoji, tokens).
Performs one API call.
Extracts rate-limit info from response headers (X-RateLimit-Bucket, -Limit,
-Remaining, -Reset, -Reset-After, -Scope, -Global). Missing values are nil.
Splits resource-call options into {query_params, request_opts}.
Types
@type meta() :: %{ status: pos_integer(), attempts: pos_integer(), rate_limit: rate_limit() }
@type method() :: :get | :post | :put | :patch | :delete | :head
@type result() :: {:ok, term()} | {:ok, term(), meta()} | {:error, Noizu.Discord.Error.t()}
Functions
Percent-encodes one path segment (ids, emoji, tokens).
@spec perform(Noizu.Discord.Client.t(), method(), String.t(), keyword()) :: result()
Performs one API call.
Options: :json (body), :params (query; nil values dropped), :headers,
:auth (default true; false omits the bot token — webhooks/interactions),
:meta, :reason.
@spec rate_limit_meta(map()) :: rate_limit()
Extracts rate-limit info from response headers (X-RateLimit-Bucket, -Limit,
-Remaining, -Reset, -Reset-After, -Scope, -Global). Missing values are nil.
Splits resource-call options into {query_params, request_opts}.
query_keys are moved to query params; :meta, :reason, :headers stay request
options. Unknown keys are ignored.