ElixirMpesa.Error exception (ElixirMpesa v0.2.0)
View SourceA single, structured error type for every failure this library can produce.
Every ElixirMpesa function returns either {:ok, ElixirMpesa.Response.t()} or
{:error, ElixirMpesa.Error.t()}. Match on :reason — it is a documented atom,
stable across releases — rather than on the raw M-Pesa response code string.
case ElixirMpesa.c2b(attrs) do
{:ok, response} -> {:ok, response.transaction_id}
{:error, %ElixirMpesa.Error{reason: :insufficient_balance}} -> :ask_customer_to_top_up
{:error, %ElixirMpesa.Error{reason: :duplicate_transaction}} -> :already_processed
{:error, %ElixirMpesa.Error{} = error} -> Logger.error(Exception.message(error))
endFields
:reason- a documented atom. Seereason/0.:category-:config,:crypto,:transport,:httpor:api. Useful for deciding whether a failure is worth retrying at all.:code- the rawoutput_ResponseCodefrom M-Pesa (for example"INS-2006"), ornilfor failures that never reached the API.:message- a human-readable description.:status- the HTTP status code, when there was a response.:operation- the library function that failed, e.g.:c2b.:raw- the full decoded response body, so nothing is ever lost.
This is an exception, so it can be raised — the ! variants such as
ElixirMpesa.c2b!/2 do exactly that.
Summary
Functions
Builds an error from a decoded M-Pesa response body.
Builds an error.
Whether an error means the session key is no longer valid and should be refreshed.
Types
@type category() :: :config | :crypto | :transport | :http | :api
@type reason() ::
:missing_config
| :invalid_config
| :unknown_market
| :invalid_public_key
| :payload_too_large
| :encryption_failed
| :timeout
| :closed
| :nxdomain
| :econnrefused
| :transport_error
| :unauthorized
| :forbidden
| :not_found
| :rate_limited
| :server_error
| :unexpected_status
| :invalid_json
| :insufficient_balance
| :invalid_msisdn
| :duplicate_transaction
| :session_expired
| :invalid_api_key
| :transaction_failed
| :unknown
The stable, matchable failure reason.
Configuration and crypto failures happen before any request is sent. Transport and
HTTP failures mean the request left the machine but no M-Pesa response code came
back. API failures carry a :code.
:unknown means M-Pesa returned a response code this library does not have a
mapping for — :code and :raw still hold the original values.
Functions
Builds an error from a decoded M-Pesa response body.
M-Pesa reports failures in "output_ResponseCode" with a human description in
"output_ResponseDesc". The description is used verbatim as the error message — this
library does not paraphrase it.
Codes without a known mapping become :unknown; :code and :raw still carry the
original values, so error.code == "INS-2006" remains matchable.
Examples
iex> body = %{"output_ResponseCode" => "INS-995", "output_ResponseDesc" => "Customer profile problem"}
iex> error = ElixirMpesa.Error.from_response(body, status: 400)
iex> {error.reason, error.code, error.category}
{:unknown, "INS-995", :api}
iex> Exception.message(error)
"Customer profile problem (INS-995)"
Builds an error.
Examples
iex> error = ElixirMpesa.Error.new(:timeout, :transport, "the request timed out")
iex> error.reason
:timeout
iex> Exception.message(error)
"the request timed out"
Whether an error means the session key is no longer valid and should be refreshed.
ElixirMpesa.Session uses this to decide whether to re-authenticate and retry once.
Examples
iex> ElixirMpesa.Error.session_expired?(ElixirMpesa.Error.new(:unauthorized, :http, "nope"))
true
iex> ElixirMpesa.Error.session_expired?(ElixirMpesa.Error.new(:timeout, :transport, "nope"))
false