From d1b000dcc640ca8eaacf3302a9852871430675e7 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 26 Nov 2019 13:34:37 +0100 Subject: [PATCH] :sparkles: Improved error handling and add specs to emails. --- backend/src/user.clj | 1 + backend/src/uxbox/emails.clj | 6 ++++- backend/src/uxbox/http.clj | 6 ++--- backend/src/uxbox/http/errors.clj | 34 +++++++----------------- backend/src/uxbox/http/handlers.clj | 36 +++++++++++--------------- backend/src/uxbox/util/emails.clj | 3 +++ backend/src/vertx/web/interceptors.clj | 14 ++++++++++ 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/backend/src/user.clj b/backend/src/user.clj index 2a811c26a..43ebae5ab 100644 --- a/backend/src/user.clj +++ b/backend/src/user.clj @@ -6,6 +6,7 @@ (ns user (:require + [clojure.spec.alpha :as s] [clojure.tools.namespace.repl :as repl] [clojure.walk :refer [macroexpand-all]] [clojure.pprint :refer [pprint]] diff --git a/backend/src/uxbox/emails.clj b/backend/src/uxbox/emails.clj index 1719f2dfb..e65649b16 100644 --- a/backend/src/uxbox/emails.clj +++ b/backend/src/uxbox/emails.clj @@ -21,9 +21,13 @@ {:static media/resolve-asset :comment (constantly nil)}) +(s/def ::name ::us/string) +(s/def ::register + (s/keys :req-un [::name])) + (def register "A new profile registration welcome email." - (emails/build :register default-context)) + (emails/build ::register default-context)) (defn render [email context] diff --git a/backend/src/uxbox/http.clj b/backend/src/uxbox/http.clj index 4f153007a..75e87000e 100644 --- a/backend/src/uxbox/http.clj +++ b/backend/src/uxbox/http.clj @@ -41,11 +41,11 @@ (vxi/params) (vxi/cors cors-opts) interceptors/parse-request-body - interceptors/format-response-body] + interceptors/format-response-body + (vxi/errors errors/handle)] routes [["/api" {:interceptors interceptors} - ["/echo" {:interceptors [(session/auth)] - :all handlers/echo-handler}] + ["/echo" {:all handlers/echo-handler}] ["/login" {:post handlers/login-handler}] ["/logout" {:post handlers/logout-handler}] ["/register" {:post handlers/register-handler}] diff --git a/backend/src/uxbox/http/errors.clj b/backend/src/uxbox/http/errors.clj index b08ad4121..328ecac3c 100644 --- a/backend/src/uxbox/http/errors.clj +++ b/backend/src/uxbox/http/errors.clj @@ -6,7 +6,9 @@ (ns uxbox.http.errors "A errors handling for the http server." - (:require [io.aviso.exception :as e])) + (:require + [clojure.tools.logging :as log] + [io.aviso.exception :as e])) (defmulti handle-exception #(:type (ex-data %))) @@ -30,32 +32,14 @@ (defmethod handle-exception :default [err] - (println "--- START REQ EXCEPTION ---") - (e/write-exception err) - (println "--- END REQ EXCEPTION ---") + (log/error err "Unhandled exception on request:") {:status 500 :body {:type :exception :message (ex-message err)}}) -(defn- handle-data-access-exception - [err] - (let [err (.getCause err) - state (.getSQLState err) - message (.getMessage err)] - (case state - "P0002" {:status 412 ;; precondition-failed - :body {:message message - :type :occ}} - (handle-exception err)))) - (defn handle - [error] - (cond - (or (instance? java.util.concurrent.CompletionException error) - (instance? java.util.concurrent.ExecutionException error)) - (handle (.getCause error)) - - ;; (instance? org.jooq.exception.DataAccessException error) - ;; (handle-data-access-exception error) - - :else (handle-exception error))) + [error req] + (if (or (instance? java.util.concurrent.CompletionException error) + (instance? java.util.concurrent.ExecutionException error)) + (handle-exception (.getCause error)) + (handle-exception error))) diff --git a/backend/src/uxbox/http/handlers.clj b/backend/src/uxbox/http/handlers.clj index 1df4eab7c..b86fe9e51 100644 --- a/backend/src/uxbox/http/handlers.clj +++ b/backend/src/uxbox/http/handlers.clj @@ -8,6 +8,7 @@ (:require [clojure.tools.logging :as log] [promesa.core :as p] + [uxbox.emails :as emails] [uxbox.http.errors :as errors] [uxbox.http.session :as session] [uxbox.services.core :as sv] @@ -20,11 +21,9 @@ {::sv/type (keyword type) :user (:user req)})] (-> (sv/query (with-meta data {:req req})) - (p/handle (fn [result error] - (if error - (errors/handle error) - {:status 200 - :body result})))))) + (p/then' (fn [result] + {:status 200 + :body result}))))) (defn mutation-handler [req] @@ -35,10 +34,8 @@ {::sv/type (keyword type) :user (:user req)})] (-> (sv/mutation (with-meta data {:req req})) - (p/handle (fn [result error] - (if error - (errors/handle error) - {:status 200 :body result})))))) + (p/then' (fn [result] + {:status 200 :body result}))))) (defn login-handler [req] @@ -46,22 +43,20 @@ user-agent (get-in req [:headers "user-agent"])] (-> (sv/mutation (assoc data ::sv/type :login)) (p/then #(session/create % user-agent)) - (p/then (fn [token] - {:status 204 - :cookies {"auth-token" {:value token}} - :body ""})) - (p/catch errors/handle)))) + (p/then' (fn [token] + {:status 204 + :cookies {"auth-token" {:value token}} + :body ""}))))) (defn logout-handler [req] (let [token (get-in req [:cookies "auth-token"]) token (uuid/from-string token)] (-> (session/delete token) - (p/then (fn [token] - {:status 204 - :cookies {"auth-token" {:value nil}} - :body ""})) - (p/catch errors/handle)))) + (p/then' (fn [token] + {:status 204 + :cookies {"auth-token" {:value nil}} + :body ""}))))) (defn register-handler [req] @@ -74,8 +69,7 @@ (p/then' (fn [token] {:status 204 :cookies {"auth-token" {:value token}} - :body ""})) - (p/catch' errors/handle)))) + :body ""}))))) (defn echo-handler [req] diff --git a/backend/src/uxbox/util/emails.clj b/backend/src/uxbox/util/emails.clj index 5a9735132..02534840a 100644 --- a/backend/src/uxbox/util/emails.clj +++ b/backend/src/uxbox/util/emails.clj @@ -91,6 +91,9 @@ (s/assert keyword? id) (fn [context] (s/assert ::context context) + (when-let [spec (s/get-spec id)] + (s/assert spec context)) + (let [context (merge extra-context context) email (impl-build-email id context)] (when-not email diff --git a/backend/src/vertx/web/interceptors.clj b/backend/src/vertx/web/interceptors.clj index c2c0b00d2..41d08b659 100644 --- a/backend/src/vertx/web/interceptors.clj +++ b/backend/src/vertx/web/interceptors.clj @@ -108,6 +108,20 @@ (.fileUploads ^RoutingContext context))] (update data :request assoc attr (persistent! uploads))))})) +;; --- Errors + +(defn errors + "A error handling interceptor." + [handler-fn] + {:error + (fn [data] + (let [request (:request data) + error (:error data) + response (handler-fn error request)] + (-> data + (assoc :response response) + (dissoc :error))))}) + ;; --- CORS (s/def ::origin string?)