View Source IdempotencyPlug (IdempotencyPlug v0.2.1)
Plug that handles Idempotency-Key
HTTP headers.
A single Idempotency-Key
HTTP header is required for POST and PATCH requests.
Handling of requests is based on https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/
idempotency-key
Idempotency Key
The value of the Idempotency-Key
HTTP header is combined with a URI to
produce a unique sha256 hash for the request. This will be used to store the
response for first-time requests. The key is used to fetch this response in
all subsequent requests.
A sha256 hash of the request payload is generated and used to ensure the key is not reused with a different request payload.
error-handling
Error handling
By default, errors are raised and handled by the Plug.Exception
protocol:
- Concurrent requests raises
IdempotencyPlug.ConcurrentRequestError
which sets409 Conflict
HTTP status code. - Mismatch of request payload fingerprint will raise
IdempotencyPlug.RequestPayloadFingerprintMismatchError
which sets422 Unprocessable Entity
HTTP status code. - If the first-time request was unexpectedly terminated a
IdempotencyPlug.HaltedResponseError
which sets a500 Internal Server
error is raised.
Setting :with
option with an MFA will catch and pass the error to the MFA.
cached-responses
Cached responses
Cached responses returns an Expires
header in the response. See
IdempotencyPlug.RequestTracker
for more on expiration.
options
Options
:tracker
- must be a name or PID for theIdempotencyPlug.RequestTracker
GenServer, required.:idempotency_key
- should be a MFA callback to process idempotency key. Defaults to{Elixir.IdempotencyPlug, :idempotency_key}
.:request_payload
- should be a MFA to parse request payload. Defaults to{Elixir.IdempotencyPlug, :request_payload}
.:hash
- should be a MFA to hash an Erlang term. Defaults to{Elixir.IdempotencyPlug, :sha256_hash}
.:with
- should be one of:exception
or MFA. Defaults to:exception
.:exception
- raises an error.{mod, fun, args}
- calls the MFA to process the conn with error, the connection MUST be halted.
examples
Examples
plug IdempotencyPlug,
tracker: IdempotencyPlug.RequestTracker,
idempotency_key: {__MODULE__, :scope_idempotency_key},
request_payload: {__MODULE__, :limit_request_payload},
hash: {__MODULE__, :sha512_hash},
with: {__MODULE__, :handle_error}
def scope_idempotency_key(conn, key) do
{conn.assigns.user.id, key}
end
def limit_request_payload(conn) do
Map.drop(conn.params, ["value"])
end
def sha512_hash(_key, value) do
:sha512
|> :crypto.hash(:erlang.term_to_binary(value))
|> Base.encode16()
|> String.downcase()
end
def handle_error(conn, error) do
conn
|> put_status(error.plug_status)
|> json(%{message: error.message})
|> halt()
end
Link to this section Summary
Functions
Returns the key as-is.
Sorts the request params in a deterministic order.
Encodes the value from an Erlang term to a binary and generates a sha256 hash from it.
Link to this section Functions
Returns the key as-is.
Sorts the request params in a deterministic order.
Encodes the value from an Erlang term to a binary and generates a sha256 hash from it.