Skip to content

Instantly share code, notes, and snippets.

@hantuzun
Last active August 18, 2016 06:46
Show Gist options
  • Save hantuzun/e44feb103396b1c34c047c6fbac446fd to your computer and use it in GitHub Desktop.
Save hantuzun/e44feb103396b1c34c047c6fbac446fd to your computer and use it in GitHub Desktop.
Error Handling Structure for SuggestGrid

All errors responses can have a format like the following:

{
    "error": "short_description",
    "error_description": "longer description, human-readable",
    "error_uri": "URI to a detailed error description on the API developer website"
}

taken from: http://blog.octo.com/en/design-a-rest-api/ which references to https://tools.ietf.org/html/rfc6749#page-45

Below is an architecture proposal that ensures returning detailed documented responses on each error, including all unexpected exceptions caused by requests.

Basically we can throw ex-info exceptions with a simple error-key instead of returning errors and maintain an edn file for documentations of these error-keys.

First, we can create an error description file in the following format:

errors.edn
{
  :model-not-found {
    :error-code          555
    :error-description   "The required recommendation model does not exists."
    :error-documentation "This error happens when at least one recommendation model required for the response is not available on SuggestGrid.
                          This is mostly the case when application is just set up the model is not created yet.
                          In this case you can wait until the model generated or trigger a model generation manually from the dashboard.
                          If you think that there is an error on our side, please write to us on https://www.suggestgrid.com/contact or support@suggestgrid.com."
  }
  :unexpected-error {
    :error-code          500
    :error-description   "SuggestGrid encountered an unexpected error."
    :error-documentation "Apologies for getting this error. 
                          This is not an expected and handled error. 
                          We would really appreciate if you can report this error.
                          Please write to us on https://www.suggestgrid.com/contact or support@suggestgrid.com."
  }
}

Then, https://suggestgrid.com/docs/errors page should be rendered from the content of this description file with references like https://suggestgrid.com/docs/errors#model_not_found.

We can then create the following functions in util/errors.clj or put them in util/common.clj.

util/errors.clj
(defn throw-error [error-key]
  (throw (ex-info (str error-key) {:error-key error-key})))

(defn return-error [error-key]
  (let [error-key (or error-key :unexpected-error)
        error (->snake_case error-key)
        error-code (get-in errors [error-key :error-code]
        error-description (get-in errors [error-key :error-description])
        error-uri (str "https://suggestgrid.com/docs/errors#" error)]
    (#(map-response error-code
                    {:error error
                     :error_description error-description
                     :error_uri error-uri})))))

The interface for throwing errors will be as simple as following:

(errors/throw-error :model-not-found)

Finally, we can have a wrapper for these thrown errors which should wrap all the endpoints after all other wrappers.

util/rest.clj
(defn return-error  
  [handler]
  (fn [request]
    (try
      (handler request)
      (catch Throwable e
        (let [error-code (:error-code (ex-data e))]
          (errors/return-error error-code))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment