Skip to content

Commit

Permalink
ref: duct module structure
Browse files Browse the repository at this point in the history
  • Loading branch information
kkharji committed Jan 6, 2022
1 parent 663a8de commit 6a8e8af
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 93 deletions.
38 changes: 22 additions & 16 deletions src/duct/reitit.clj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
(ns duct.reitit
(:require [duct.core :as core :refer [merge-configs]]
[duct.core.merge :as m]
[duct.reitit.handler]
[duct.reitit.util :as util :refer [get-namespaces resolve-registry with-registry spy]]
[integrant.core :refer [init-key] :as ig]))
[integrant.core :refer [init-key] :as ig]
[duct.logger :as logger]))

(def ^:private base-config
{:duct.core/handler-ns 'handler
Expand All @@ -29,30 +29,36 @@
:requests? true
:pretty? false}}})

(defn- merge-to-options [configs]
(defn- merge-to-options [config]
(reduce-kv
(fn [acc k v]
(if (= "duct.reitit" (namespace k))
(assoc-in acc [::options (keyword (name k))] v)
(assoc acc k v)))
{} configs))
{} config))

(defmethod init-key ::log [_ {{:keys [enable logger pretty? exceptions? coercions?]} :logging}]
(when (and enable (or exceptions? coercions?))
(if (and logger (not pretty?))
(fn [level message]
(logger/log logger level message))
println)))

(defmethod init-key :duct.module/reitit [_ _]
(fn [{:duct.reitit/keys [registry routes]
:duct.core/keys [environment] :as config}]
:duct.core/keys [environment] :as user-config}]
(let [env-config (or (configs environment) {})
config (merge-to-options (merge-configs base-config env-config config))
config (merge-to-options (merge-configs base-config env-config user-config))
namespaces (get-namespaces config)
registry (resolve-registry namespaces registry)
regrefs (reduce-kv (fn [m k v] (assoc m k (ig/ref (first v)))) {} registry)
merge (partial with-registry config registry)]
(merge
{::logging (ig/ref ::options)
::middleware {:options (ig/ref ::options) :logging (ig/ref ::logging)}
::registry regrefs
:duct.handler/root {:options (ig/ref ::options) :router (ig/ref :duct.router/reitit)}
:duct.router/reitit {:routes routes
:middleware (ig/ref ::middleware)
:registry (ig/ref ::registry)
:options (ig/ref ::options)
:namespaces namespaces}}))))
{::registry (reduce-kv (fn [m k v] (assoc m k (ig/ref (first v)))) {} registry)
::log (ig/ref ::options)
:duct.handler/root {:options (ig/ref ::options)
:router (ig/ref :duct.router/reitit)}
:duct.router/reitit {:routes routes
:log (ig/ref ::log)
:registry (ig/ref ::registry)
:options (ig/ref ::options)
:namespaces namespaces}}))))
31 changes: 13 additions & 18 deletions src/duct/reitit/middleware.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
(ns duct.reitit.middleware
"Construct Ring-Reitit Global Middleware"
(:require [integrant.core :refer [init-key]]
[duct.reitit.util :refer [compact defm spy]]
(:require [duct.reitit.util :refer [compact defm spy]]
[reitit.ring.middleware.muuntaja :refer [format-middleware]]
[reitit.ring.middleware.parameters :refer [parameters-middleware]]
[duct.reitit.middleware.exception :as exception]
Expand All @@ -17,23 +16,19 @@
(defn- get-format-middleware [muuntaja]
(when muuntaja format-middleware))

(defn- create-middleware [extras]
(fn [& defaults]
(->> (conj extras defaults)
(apply concat)
(vec) (compact))))
(defn- merge-middlewares [{:keys [middleware] :as options}]
(let [coercion-middlewares (coercion/get-middleware options)]
(fn [& defaults]
(-> (concat defaults coercion-middlewares middleware)
(vec)
(compact)))))

(defmethod init-key :duct.reitit/middleware
[_ {:keys [logging] {:keys [muuntaja middleware coercion exception]} :options}]
(let [{:keys [coerce-response coerce-request coerce-exceptions]} (coercion/get-middleware coercion logging)
format-middleware (get-format-middleware muuntaja)
exception-middleware (exception/get-middleware logging coercion exception)
create-middleware (create-middleware middleware)]
(create-middleware parameters-middleware
(defn create-router-middleware [{:keys [muuntaja] :as options}]
(let [format-middleware (get-format-middleware muuntaja)
exception-middleware (exception/get-middleware options)
merge-middlewares (merge-middlewares options)]
(merge-middlewares parameters-middleware
environment-middleware
format-middleware
exception-middleware
coerce-exceptions
coerce-request
coerce-response)))
exception-middleware)))

22 changes: 10 additions & 12 deletions src/duct/reitit/middleware/coercion.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,18 @@
(fn [exception request]
(handler exception request))))

;; should be nil when 1. logging is enabled and 2. customized message)
(defn- get-coercion-exception [should-use]
(when-not should-use rcc/coerce-exceptions-middleware))
(defn get-exception-handler
[{:keys [with-formatted-message?] :as _coercion}]
(when with-formatted-message?
{:reitit.coercion/request-coercion (get-coercion-exception-handler 400)
:reitit.coercion/response-coercion (get-coercion-exception-handler 500)}))

(defn get-middleware
[{:keys [enable with-formatted-message?]}
{:keys [coercions? exceptions?]}]
[{{:keys [enable with-formatted-message?]} :coercion
{:keys [coercions? exceptions?]} :logging}]
(when enable
(let [with-exception (or coercions? exceptions? with-formatted-message?)]
{:coerce-exceptions (get-coercion-exception with-exception)
:coerce-request rcc/coerce-request-middleware
:coerce-response rcc/coerce-response-middleware})))
[(when-not with-exception rcc/coerce-exceptions-middleware)
rcc/coerce-request-middleware
rcc/coerce-response-middleware])))

(defn get-exception-handler [{:keys [with-formatted-message?] :as _config} enabled?]
(when (or enabled? with-formatted-message?)
{:reitit.coercion/request-coercion (get-coercion-exception-handler 400)
:reitit.coercion/response-coercion (get-coercion-exception-handler 500)}))
30 changes: 18 additions & 12 deletions src/duct/reitit/middleware/exception.clj
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
(ns duct.reitit.middleware.exception
(:require [reitit.ring.middleware.exception :as exception :refer [create-exception-middleware default-handlers]]
[duct.reitit.middleware.coercion :as coercion]))
[duct.reitit.middleware.coercion :as coercion]
[duct.reitit.middleware.format :refer [ex-format]]
[duct.reitit.util :refer [spy]]))

(defn- create-middleware [& handlers]
(->> (cons default-handlers handlers)
(apply merge)
(create-exception-middleware)))
(defn ^:private get-exception-wrapper [log config]
(let [config (merge config {:with-req-info? true})]
(fn [handler exception request]
(log :error (ex-format exception request config))
(handler exception request))))

(defn get-middleware
"Create custom exception middleware."
[{:keys [enable ex-logger coercions? exceptions?]} coercion exception]
(let [should-wrap (or (and enable coercions?) (and enable ex-logger exceptions?))
coercion-handlers (coercion/get-exception-handler coercion coercions?)
exception-wrapper (when should-wrap {::exception/wrap ex-logger})]
(create-middleware exception-wrapper
coercion-handlers
exception)))
[{:keys [coercion exception log logging]}]
(let [{:keys [enable coercions? exceptions?]} logging
should-wrap (or (and enable coercions?) (and enable exceptions?))
coercion-handlers (when coercions? (coercion/get-exception-handler coercion))
exception-wrapper (when should-wrap {::exception/wrap (get-exception-wrapper log logging)})
create-middleware #(create-exception-middleware (apply merge default-handlers %))]
(create-middleware
[exception-wrapper
coercion-handlers
exception])))
2 changes: 1 addition & 1 deletion src/duct/reitit/middleware/logging.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[duct.reitit.middleware.format :refer [ex-format]]
[duct.logger :as logger]))

(defmethod init-key :duct.reitit/logging
(defmethod init-key :ffduct.reitit/logging
[_ {{:keys [enable logger pretty? exceptions? coercions?] :as config} :logging}]
(when (and enable (or exceptions? coercions?))
(let [enabled {:coercions? coercions? :exceptions? exceptions?}
Expand Down
28 changes: 14 additions & 14 deletions src/duct/reitit/router.clj
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
(ns duct.reitit.router
(:require [clojure.walk :refer [postwalk]]
[duct.logger :as logger]
[duct.reitit.util :as util :refer [compact member? resolve-key]]
[duct.reitit.util :as util :refer [compact member? resolve-key spy]]
[integrant.core :as ig :refer [init-key]]
[muuntaja.core :refer [instance] :rename {instance muuntaja-instance}]
#_[reitit.coercion :refer [compile-request-coercers]]
[reitit.coercion.malli :as malli]
[reitit.coercion.schema :as schema]
[reitit.coercion.spec :as spec]
[reitit.ring :as ring]))
[reitit.ring :as ring]
[duct.reitit.middleware :refer [create-router-middleware]]))

(def ^:private coercion-index
{:malli malli/coercion :spec spec/coercion :schema schema/coercion})
Expand All @@ -17,20 +17,20 @@
(let [resolve (partial resolve-key namespaces)
member? (partial member? (keys registry))
valid? (fn [x] (and (keyword? x) (member? x)))]
(fn [x]
(cond (symbol? x) (or (resolve x) x)
(valid? x) (get registry x)
:else x))))
(fn [x] (cond (symbol? x) (or (resolve x) x)
(valid? x) (get registry x)
:else x))))

; :compile coercion/compile-request-coercers?
(defn process-options [{:keys [muuntaja environment coercion]}]
(defn process-options [{:keys [muuntaja environment coercion] :as options}]
{:data (compact
{:environment environment
:muuntaja (cond (boolean? muuntaja) muuntaja-instance (nil? muuntaja) nil :else muuntaja)
:coercion (some-> coercion :coercer keyword coercion-index)})})
:coercion (some-> coercion :coercer keyword coercion-index)
:middleware (create-router-middleware options)})})

(defmethod init-key :duct.router/reitit [_ {:keys [logger registry middleware routes namespaces options]}]
(when logger (logger/log logger :report ::init))
(ring/router
(postwalk (get-resolver registry namespaces) routes)
(assoc-in (process-options options) [:data :middleware] middleware)))
(defmethod init-key :duct.router/reitit
[_ {:keys [registry routes namespaces options log]}]
; (log :report ::initializing)
(ring/router (postwalk (get-resolver registry namespaces) routes)
(process-options (assoc options :log log))))
40 changes: 20 additions & 20 deletions test/duct/reitit_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,28 @@
(let [config (core/prep-config base-config)
in-options (new-config-handling base-config)]

;; Reitit Module keys used for futher processing
(is (->> (keys config)
(filterv #(= "duct.reitit" (namespace %)))
(mapv #(keyword (name %)))
(= [:options :registry :middleware :logging])))
;; Reitit Module keys used for futher processing
(is (= [:options :registry :log]
(->> (keys config)
(filterv #(= "duct.reitit" (namespace %)))
(mapv #(keyword (name %))))))

(are [key value] (= value (key config))
;; Defaulhandler middleware namespace
;; Defaulhandler middleware namespace
:duct.core/handler-ns 'handler
;; Default middleware namespace
;; Default middleware namespace
:duct.core/middleware-ns 'middleware
;; Configuration Pass it reitit router to initialize it
;; Configuration Pass it reitit router to initialize it
:duct.router/reitit {:routes nil,
:middleware (ig/ref :duct.reitit/middleware)
:log (ig/ref :duct.reitit/log)
:registry (ig/ref :duct.reitit/registry)
:options (ig/ref :duct.reitit/options)
:namespaces ["foo.handler" "foo.middleware"]}
;; Configuration Pass it ring handler to initialize it
;; Configuration Pass it ring handler to initialize it
:duct.handler/root {:router (ig/ref :duct.router/reitit)
:options (ig/ref :duct.reitit/options)})

;; Configuration Values
;; Configuration Values
(are [path value] (= (in-options path) value)
[:logging :exceptions?] true ;; default types supported by default
[:logging :pretty?] false ;; No pretty logging by default.
Expand All @@ -106,9 +106,9 @@
(let [in-options (-> (assoc base-config :duct.profile/dev {})
(new-config-handling [:duct.profile/dev]))]
(are [path value] (= (in-options path) value)
[:logging :exceptions?] true ;; default types supported by default
[:logging :coercions?] true ;; default types supported by default
[:logging :requests?] true ;; default types supported by default
[:logging :exceptions?] true ;; exceptions enabled by default
[:logging :coercions?] true ;; coercions enabled by default
[:logging :requests?] true ;; requests enabled by default
[:logging :pretty?] true ;; pretty logging by default.
[:logging :logger] nil ;; No logger by default.
:muuntaja true ;; Muuntaja formatting is enabled by default
Expand All @@ -129,7 +129,7 @@
:muuntaja true ;; Muuntaja formatting is enabled by default
:environment {} ;; Empty Environment
:middleware [] ;; Empty Middleware
:cross-origin nil))) ;; No Cross-origin
:cross-origin nil))) ;; No Cross-origin

(deftest test-foo-module
(let [extra {::coercion {:enable true :coercer 'spec}}
Expand All @@ -138,13 +138,13 @@
routes (routes router)
handler (config :duct.handler/root)]

(testing "Registry Merge"
(testing "Registry-Merge:"
(are [x] (not= nil (x config))
:foo.handler/ping
:foo.handler/index
:foo.handler.plus/with-body))

(testing "Resulting Router"
(testing "Resulting-Router:"
(is (= :reitit.core/router (type router)))
(is (= 5 (count routes)))
(is (vector? (-> (get routes "/") :environment :db)))
Expand All @@ -164,7 +164,7 @@
:get "/plus" {:query-params {:y 3 :x 6}} [:total] 9
:get "/author" {} [:author] "tami5"))

(testing "Custom Error Handling Repsonse"
(testing "Custom-Error-Repsonse:"
(let [divide-by-zero-response (to-edn (handler (request :get "/divide" {:body-params {:y 0 :x 0}})))
no-params-response (to-edn (handler (request :get "/divide" {})))]

Expand All @@ -173,7 +173,7 @@
(is (= {:y 0 :x 0} (:data divide-by-zero-response)))
(is (= "No parameters received" (:cause no-params-response)))))))

(deftest module-behavior
(deftest test-logging-behavior
(testing "Logging:"
(let [does-include* (fn [ptr] (fn [str] (str/includes? str ptr)))
spec-pretty? (does-include* "-- Spec failed --------------------")
Expand All @@ -186,7 +186,7 @@
(->> request handler with-out-str checkfn)))]

(testing "Exception-Logging:"
(let [base {::logging {:enable true :pretty? false :logger nil :exception? true}}]
(let [base {::logging {:enable true :pretty? false :exception? true}}]
(are [checkfn cfg] (test-behavior :get "/divide" {:body-params {:y 0 :x 0}} base cfg checkfn)
;; Enabled
ex-compact? {}
Expand Down

0 comments on commit 6a8e8af

Please sign in to comment.