Codat.Idempotency (codat v1.0.0)

Copy Markdown View Source

Helpers for idempotent write operations.

When you supply an Idempotency-Key header, Codat returns the same response for any duplicate request with the same key, preventing accidental double-writes.

Usage

key = Codat.Idempotency.key()

{:ok, push_op} = Codat.Accounting.Invoices.create(
  client, company_id, conn_id, invoice_body,
  idempotency_key: key
)

# Safe to retry with the same key — Codat returns the original response
{:ok, push_op} = Codat.Accounting.Invoices.create(
  client, company_id, conn_id, invoice_body,
  idempotency_key: key
)

Summary

Functions

Returns the header tuple for use in HTTP requests.

Generates a new UUID v4 idempotency key.

Generates an idempotency key derived deterministically from input data.

Returns true if the string is a valid idempotency key (1–255 chars).

Functions

header(key)

@spec header(String.t()) :: {String.t(), String.t()}

Returns the header tuple for use in HTTP requests.

Example

{name, value} = Codat.Idempotency.header("my-key")
# => {"idempotency-key", "my-key"}

key()

@spec key() :: String.t()

Generates a new UUID v4 idempotency key.

Example

iex> key = Codat.Idempotency.key()
iex> String.length(key) == 36
true

key_for(namespace, data)

@spec key_for(term(), term()) :: String.t()

Generates an idempotency key derived deterministically from input data.

The key is an HMAC-SHA256 of the inputs, hex-encoded. Use when the same logical operation should always produce the same key.

Example

key = Codat.Idempotency.key_for("create_invoice", company_id, invoice_number)
# Always returns the same key for the same three inputs

key_for(namespace, data1, data2)

@spec key_for(term(), term(), term()) :: String.t()

key_for(namespace, data1, data2, data3)

@spec key_for(term(), term(), term(), term()) :: String.t()

valid?(key)

@spec valid?(String.t()) :: boolean()

Returns true if the string is a valid idempotency key (1–255 chars).

Example

iex> Codat.Idempotency.valid?("abc-123")
true
iex> Codat.Idempotency.valid?("")
false