diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 57d55628..ef35ac14 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -17,7 +17,8 @@ (-open-model [this model] "Returns a new model which allows extra keys in maps") (-encode-error [this error] "Converts error in to a serializable format") (-request-coercer [this type model] "Returns a `value format => value` request coercion function") - (-response-coercer [this model] "Returns a `value format => value` response coercion function")) + (-response-coercer [this model] "Returns a `value format => value` response coercion function") + (-route-data-merge [this acc k v])) #?(:clj (defmethod print-method ::coercion [coercion ^Writer w] diff --git a/modules/reitit-core/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc index 8b62909a..bcd54ac4 100644 --- a/modules/reitit-core/src/reitit/core.cljc +++ b/modules/reitit-core/src/reitit/core.cljc @@ -360,8 +360,7 @@ | `:validate` | Function of `routes opts => ()` to validate route (data) via side-effects | `:conflicts` | Function of `{route #{route}} => ()` to handle conflicting routes | `:exception` | Function of `Exception => Exception ` to handle creation time exceptions (default `reitit.exception/exception`) - | `:router` | Function of `routes opts => router` to override the actual router implementation - | `:merge` | Function of `route-data key value` to add new kv pair to route-data map. Default uses merge-merge." + | `:router` | Function of `routes opts => router` to override the actual router implementation" ([raw-routes] (router raw-routes {})) ([raw-routes opts] diff --git a/modules/reitit-core/src/reitit/impl.cljc b/modules/reitit-core/src/reitit/impl.cljc index 7bd7bb70..65554238 100644 --- a/modules/reitit-core/src/reitit/impl.cljc +++ b/modules/reitit-core/src/reitit/impl.cljc @@ -63,18 +63,30 @@ (defn default-route-data-merge [acc k v] (mm/meta-merge acc {k v})) -(defn merge-data [route-data-merge p x] - (reduce - (fn [acc [k v]] - (try - (route-data-merge acc k v) - (catch #?(:clj Exception, :cljs js/Error) e - (ex/fail! ::merge-data {:path p, :left acc, :right {k v}, :exception e})))) - {} x)) +(defn merge-data [p x] + (let [;; Find last the effective :coercion value + ;; for the route, and then use the cocercion + ;; instance for route data merge implementation. + coercion (->> x + reverse + (some (fn [[k v]] + (when (= :coercion k) + v)))) + route-data-merge (if coercion + #((resolve 'reitit.coercion/-route-data-merge) coercion %1 %2 %3) + default-route-data-merge)] + (reduce + (fn [acc [k v]] + (try + (route-data-merge acc k v) + (catch #?(:clj Exception, :cljs js/Error) e + (ex/fail! ::merge-data {:path p, :left acc, :right {k v}, :exception e})))) + {} + x))) -(defn resolve-routes [raw-routes {:keys [coerce _merge] :as opts}] +(defn resolve-routes [raw-routes {:keys [coerce] :as opts}] (cond->> (->> (walk raw-routes opts) - (map-data (partial merge-data (or (:merge opts) default-route-data-merge)))) + (map-data merge-data)) coerce (into [] (keep #(coerce % opts))))) (defn path-conflicting-routes [routes opts] diff --git a/modules/reitit-malli/src/reitit/coercion/malli.cljc b/modules/reitit-malli/src/reitit/coercion/malli.cljc index 9c06a518..3a12531b 100644 --- a/modules/reitit-malli/src/reitit/coercion/malli.cljc +++ b/modules/reitit-malli/src/reitit/coercion/malli.cljc @@ -180,11 +180,10 @@ (-request-coercer [_ type schema] (-coercer (compile schema options) type transformers :decode opts)) (-response-coercer [_ schema] - (-coercer (compile schema options) :response transformers :encode opts)))))) + (-coercer (compile schema options) :response transformers :encode opts)) + (-route-data-merge [_ acc k v] + (case k + :parameters (assoc acc :parameters (merge-with mu/merge (:parameters acc) v)) + (mm/meta-merge acc {k v}))))))) (def coercion (create default-options)) - -(defn route-data-merge [acc k v] - (case k - :parameters (assoc acc :parameters (merge-with mu/merge (:parameters acc) v)) - (mm/meta-merge acc {k v}))) diff --git a/modules/reitit-schema/src/reitit/coercion/schema.cljc b/modules/reitit-schema/src/reitit/coercion/schema.cljc index 1985ba72..2a31f123 100644 --- a/modules/reitit-schema/src/reitit/coercion/schema.cljc +++ b/modules/reitit-schema/src/reitit/coercion/schema.cljc @@ -7,7 +7,8 @@ [schema-tools.coerce :as stc] [schema-tools.swagger.core :as swagger] [reitit.coercion :as coercion] - [clojure.set :as set])) + [clojure.set :as set] + [reitit.impl :as impl])) (def string-coercion-matcher stc/string-coercion-matcher) @@ -94,6 +95,8 @@ value)))) (-response-coercer [this schema] (if (coerce-response? schema) - (coercion/-request-coercer this :response schema))))) + (coercion/-request-coercer this :response schema))) + (-route-data-merge [this acc k v] + (impl/default-route-data-merge acc k v)))) (def coercion (create default-options)) diff --git a/modules/reitit-spec/src/reitit/coercion/spec.cljc b/modules/reitit-spec/src/reitit/coercion/spec.cljc index bac09a25..8e19f4db 100644 --- a/modules/reitit-spec/src/reitit/coercion/spec.cljc +++ b/modules/reitit-spec/src/reitit/coercion/spec.cljc @@ -4,6 +4,7 @@ [spec-tools.data-spec :as ds #?@(:cljs [:refer [Maybe]])] [spec-tools.swagger.core :as swagger] [reitit.coercion :as coercion] + [reitit.impl :as impl] [clojure.set :as set]) #?(:clj (:import (spec_tools.core Spec) @@ -135,6 +136,8 @@ value)))) (-response-coercer [this spec] (if (coerce-response? spec) - (coercion/-request-coercer this :response spec))))) + (coercion/-request-coercer this :response spec))) + (-route-data-merge [this acc k v] + (impl/default-route-data-merge acc k v)))) (def coercion (create default-options)) diff --git a/test/cljc/reitit/impl_test.cljc b/test/cljc/reitit/impl_test.cljc index 48cfe5bf..cc0405c0 100644 --- a/test/cljc/reitit/impl_test.cljc +++ b/test/cljc/reitit/impl_test.cljc @@ -176,8 +176,7 @@ (deftest merge-data-test (is (= {:view 'b :controllers [1 2]} - (impl/merge-data impl/default-route-data-merge - "/" + (impl/merge-data "/" [[:view 'a] [:controllers [1]] [:view 'b] @@ -185,8 +184,7 @@ (is (= {:view 'b :controllers [2]} - (impl/merge-data impl/default-route-data-merge - "/" + (impl/merge-data "/" [[:view 'a] [:controllers [1]] [:view 'b] @@ -194,8 +192,7 @@ (is (= {:a schema/Str :b schema/Str} - (-> (impl/merge-data rcm/route-data-merge - "/" + (-> (impl/merge-data "/" [[:parameters {:path {:a schema/Str}}] [:parameters {:path {:b schema/Str}}]]) :parameters @@ -204,9 +201,9 @@ (is (= [:map [:a 'string?] [:b 'int?]] - (-> (impl/merge-data rcm/route-data-merge - "/" - [[:parameters {:path [:map [:a 'string?]]}] + (-> (impl/merge-data "/" + [[:coercion rcm/coercion] + [:parameters {:path [:map [:a 'string?]]}] [:parameters {:path [:map [:b 'int?]]}]]) :parameters :path