Skip to content

Instantly share code, notes, and snippets.

@siefca
Last active February 4, 2021 10:15
Show Gist options
  • Save siefca/d49fd8e4777627663ec99a275ac4a678 to your computer and use it in GitHub Desktop.
Save siefca/d49fd8e4777627663ec99a275ac4a678 to your computer and use it in GitHub Desktop.
Short-circuiting Clojure errors with exceptions
(defrecord XError [reason message response])
(def default-messages
{:blabla "This is blabla"
:unknown "Unknown error"
:empty "Empty response"})
(defn new-error
"Forms an error response when something goes wrong."
([reason response]
(new-error reason nil response))
([reason message response]
(let [reason (if (nil? reason) :unknown reason)]
(->XError reason
(if (some? message) message (default-messages reason))
response))))
(defn ^Boolean error?
"Returns true if the response is an error."
[response]
(instance? XError response))
(defn error->ex
"When the response is an error it will throw an exception with message and
exception info set to the response object. This should be usually used
to short-circuit on errors and avoid multi-level, nested conditionals."
[resp]
(if (error? resp)
(throw (ex-info (.message resp) resp))
resp))
(defn ex->error
"Transforms an exception into the error data object by extracting the
exception data if its of type XError. Otherwise it re-throws the original
exception."
[e]
(let [ed (ex-data e)]
(if (error? ed) ed (throw e))))
(def new-error->ex
"Creates a new error object and throws it as an exception.
The original error is attached as the exception data."
(comp error->ex new-error))
(let [resp {:some "response"}]
(try
(new-error->ex :blabla resp)
:all-good
(catch clojure.lang.ExceptionInfo e (ex->error e))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment