This commit is contained in:
Tommi Reiman 2022-02-12 22:34:26 +02:00
parent b7cc420fde
commit 5d4c886d35
52 changed files with 1686 additions and 1690 deletions

View file

@ -43,28 +43,28 @@
(defn ^:no-doc request-coercion-failed! [result coercion value in request] (defn ^:no-doc request-coercion-failed! [result coercion value in request]
(throw (throw
(ex-info (ex-info
(str "Request coercion failed: " (pr-str result)) (str "Request coercion failed: " (pr-str result))
(merge (merge
(into {} result) (into {} result)
{:type ::request-coercion {:type ::request-coercion
:coercion coercion :coercion coercion
:value value :value value
:in [:request in] :in [:request in]
:request request})))) :request request}))))
(defn ^:no-doc response-coercion-failed! [result coercion value request response] (defn ^:no-doc response-coercion-failed! [result coercion value request response]
(throw (throw
(ex-info (ex-info
(str "Response coercion failed: " (pr-str result)) (str "Response coercion failed: " (pr-str result))
(merge (merge
(into {} result) (into {} result)
{:type ::response-coercion {:type ::response-coercion
:coercion coercion :coercion coercion
:value value :value value
:in [:response :body] :in [:response :body]
:request request :request request
:response response})))) :response response}))))
(defn extract-request-format-default [request] (defn extract-request-format-default [request]
(-> request :muuntaja/request :format)) (-> request :muuntaja/request :format))
@ -109,9 +109,9 @@
(defn coerce-request [coercers request] (defn coerce-request [coercers request]
(reduce-kv (reduce-kv
(fn [acc k coercer] (fn [acc k coercer]
(impl/fast-assoc acc k (coercer request))) (impl/fast-assoc acc k (coercer request)))
{} coercers)) {} coercers))
(defn coerce-response [coercers request response] (defn coerce-response [coercers request response]
(if response (if response
@ -147,13 +147,13 @@
:multipart :formData}] :multipart :formData}]
(case specification (case specification
:swagger (->> (update :swagger (->> (update
data data
:parameters :parameters
(fn [parameters] (fn [parameters]
(->> parameters (->> parameters
(map (fn [[k v]] [(swagger-parameter k) v])) (map (fn [[k v]] [(swagger-parameter k) v]))
(filter first) (filter first)
(into {})))) (into {}))))
(-get-apidocs coercion specification))))) (-get-apidocs coercion specification)))))
;; ;;

View file

@ -61,7 +61,7 @@
(if-not (partial-match? match) (if-not (partial-match? match)
match match
(impl/throw-on-missing-path-params (impl/throw-on-missing-path-params
(:template match) (:required match) path-params))))) (:template match) (:required match) path-params)))))
(defn match->path (defn match->path
([match] ([match]
@ -87,15 +87,15 @@
(let [compiler (::trie/trie-compiler opts (trie/compiler)) (let [compiler (::trie/trie-compiler opts (trie/compiler))
names (impl/find-names compiled-routes opts) names (impl/find-names compiled-routes opts)
[pl nl] (reduce [pl nl] (reduce
(fn [[pl nl] [p {:keys [name] :as data} result]] (fn [[pl nl] [p {:keys [name] :as data} result]]
(let [{:keys [path-params] :as route} (impl/parse p opts) (let [{:keys [path-params] :as route} (impl/parse p opts)
f #(if-let [path (impl/path-for route %)] f #(if-let [path (impl/path-for route %)]
(->Match p data result (impl/url-decode-coll %) path) (->Match p data result (impl/url-decode-coll %) path)
(->PartialMatch p data result (impl/url-decode-coll %) path-params))] (->PartialMatch p data result (impl/url-decode-coll %) path-params))]
[(conj pl (-> (trie/insert nil p (->Match p data result nil nil) opts) (trie/compile))) [(conj pl (-> (trie/insert nil p (->Match p data result nil nil) opts) (trie/compile)))
(if name (assoc nl name f) nl)])) (if name (assoc nl name f) nl)]))
[[] {}] [[] {}]
compiled-routes) compiled-routes)
lookup (impl/fast-map nl) lookup (impl/fast-map nl)
matcher (trie/linear-matcher compiler pl true) matcher (trie/linear-matcher compiler pl true)
match-by-path (trie/path-matcher matcher compiler) match-by-path (trie/path-matcher matcher compiler)
@ -133,18 +133,18 @@
([compiled-routes opts] ([compiled-routes opts]
(when-let [wilds (seq (filter (impl/->wild-route? opts) compiled-routes))] (when-let [wilds (seq (filter (impl/->wild-route? opts) compiled-routes))]
(exception/fail! (exception/fail!
(str "can't create :lookup-router with wildcard routes: " wilds) (str "can't create :lookup-router with wildcard routes: " wilds)
{:wilds wilds {:wilds wilds
:routes compiled-routes})) :routes compiled-routes}))
(let [names (impl/find-names compiled-routes opts) (let [names (impl/find-names compiled-routes opts)
[pl nl] (reduce [pl nl] (reduce
(fn [[pl nl] [p {:keys [name] :as data} result]] (fn [[pl nl] [p {:keys [name] :as data} result]]
[(assoc pl p (->Match p data result {} p)) [(assoc pl p (->Match p data result {} p))
(if name (if name
(assoc nl name #(->Match p data result % p)) (assoc nl name #(->Match p data result % p))
nl)]) nl)])
[{} {}] [{} {}]
compiled-routes) compiled-routes)
data (impl/fast-map pl) data (impl/fast-map pl)
lookup (impl/fast-map nl) lookup (impl/fast-map nl)
routes (impl/uncompile-routes compiled-routes)] routes (impl/uncompile-routes compiled-routes)]
@ -183,15 +183,15 @@
(let [compiler (::trie/trie-compiler opts (trie/compiler)) (let [compiler (::trie/trie-compiler opts (trie/compiler))
names (impl/find-names compiled-routes opts) names (impl/find-names compiled-routes opts)
[pl nl] (reduce [pl nl] (reduce
(fn [[pl nl] [p {:keys [name] :as data} result]] (fn [[pl nl] [p {:keys [name] :as data} result]]
(let [{:keys [path-params] :as route} (impl/parse p opts) (let [{:keys [path-params] :as route} (impl/parse p opts)
f #(if-let [path (impl/path-for route %)] f #(if-let [path (impl/path-for route %)]
(->Match p data result (impl/url-decode-coll %) path) (->Match p data result (impl/url-decode-coll %) path)
(->PartialMatch p data result (impl/url-decode-coll %) path-params))] (->PartialMatch p data result (impl/url-decode-coll %) path-params))]
[(trie/insert pl p (->Match p data result nil nil) opts) [(trie/insert pl p (->Match p data result nil nil) opts)
(if name (assoc nl name f) nl)])) (if name (assoc nl name f) nl)]))
[nil {}] [nil {}]
compiled-routes) compiled-routes)
matcher (trie/compile pl compiler) matcher (trie/compile pl compiler)
match-by-path (trie/path-matcher matcher compiler) match-by-path (trie/path-matcher matcher compiler)
lookup (impl/fast-map nl) lookup (impl/fast-map nl)
@ -229,8 +229,8 @@
([compiled-routes opts] ([compiled-routes opts]
(when (or (not= (count compiled-routes) 1) (some (impl/->wild-route? opts) compiled-routes)) (when (or (not= (count compiled-routes) 1) (some (impl/->wild-route? opts) compiled-routes))
(exception/fail! (exception/fail!
(str ":single-static-path-router requires exactly 1 static route: " compiled-routes) (str ":single-static-path-router requires exactly 1 static route: " compiled-routes)
{:routes compiled-routes})) {:routes compiled-routes}))
(let [[n :as names] (impl/find-names compiled-routes opts) (let [[n :as names] (impl/find-names compiled-routes opts)
[[p data result]] compiled-routes [[p data result]] compiled-routes
p #?(:clj (.intern ^String p) :cljs p) p #?(:clj (.intern ^String p) :cljs p)

View file

@ -10,8 +10,8 @@
(map (fn [provide] (map (fn [provide]
(when (contains? acc provide) (when (contains? acc provide)
(exception/fail! (exception/fail!
(str "multiple providers for: " provide) (str "multiple providers for: " provide)
{::multiple-providers provide})) {::multiple-providers provide}))
[provide dependent])) [provide dependent]))
(get-provides dependent))) (get-provides dependent)))
{} nodes)) {} nodes))
@ -22,8 +22,8 @@
(if (contains? providers k) (if (contains? providers k)
(get providers k) (get providers k)
(exception/fail! (exception/fail!
(str "provider missing for dependency: " k) (str "provider missing for dependency: " k)
{::missing-provider k}))) {::missing-provider k})))
(defn post-order (defn post-order
"Put `nodes` in post-order. Can also be described as a reverse topological sort. "Put `nodes` in post-order. Can also be described as a reverse topological sort.

View file

@ -31,20 +31,20 @@
path " " (not-empty (select-keys route-data [:conflicting]))))] path " " (not-empty (select-keys route-data [:conflicting]))))]
(apply str "Router contains conflicting route paths:\n\n" (apply str "Router contains conflicting route paths:\n\n"
(mapv (mapv
(fn [[[path route-data] vals]] (fn [[[path route-data] vals]]
(str (resolve-str path route-data) (str (resolve-str path route-data)
"\n" "\n"
(str/join "\n" (mapv (fn [[path route-data]] (str/join "\n" (mapv (fn [[path route-data]]
(resolve-str path route-data)) vals)) (resolve-str path route-data)) vals))
"\n\n")) "\n\n"))
conflicts)))) conflicts))))
(defmethod format-exception :name-conflicts [_ _ conflicts] (defmethod format-exception :name-conflicts [_ _ conflicts]
(apply str "Router contains conflicting route names:\n\n" (apply str "Router contains conflicting route names:\n\n"
(mapv (mapv
(fn [[name vals]] (fn [[name vals]]
(str name "\n-> " (str/join "\n-> " (mapv first vals)) "\n")) (str name "\n-> " (str/join "\n-> " (mapv first vals)) "\n"))
conflicts))) conflicts)))
(defmethod format-exception :reitit.impl/merge-data [_ _ data] (defmethod format-exception :reitit.impl/merge-data [_ _ data]
(str "Error merging route-data\n\n" (pr-str data))) (str "Error merging route-data\n\n" (pr-str data)))

View file

@ -28,33 +28,33 @@
Also works on vectors. Maintains key for maps, order for vectors." Also works on vectors. Maintains key for maps, order for vectors."
[f coll] [f coll]
(reduce-kv (reduce-kv
(fn [coll k v] (fn [coll k v]
(if-some [v' (f v)] (if-some [v' (f v)]
(assoc coll k v') (assoc coll k v')
coll)) coll))
coll coll
coll)) coll))
(defn walk [raw-routes {:keys [path data routes expand] (defn walk [raw-routes {:keys [path data routes expand]
:or {data [], routes []} :or {data [], routes []}
:as opts}] :as opts}]
(letfn (letfn
[(walk-many [p m r] [(walk-many [p m r]
(reduce #(into %1 (walk-one p m %2)) [] r)) (reduce #(into %1 (walk-one p m %2)) [] r))
(walk-one [pacc macc routes] (walk-one [pacc macc routes]
(if (vector? (first routes)) (if (vector? (first routes))
(walk-many pacc macc routes) (walk-many pacc macc routes)
(when (string? (first routes)) (when (string? (first routes))
(let [[path & [maybe-arg :as args]] routes (let [[path & [maybe-arg :as args]] routes
[data childs] (if (or (vector? maybe-arg) [data childs] (if (or (vector? maybe-arg)
(and (sequential? maybe-arg) (and (sequential? maybe-arg)
(sequential? (first maybe-arg))) (sequential? (first maybe-arg)))
(nil? maybe-arg)) (nil? maybe-arg))
[{} args] [{} args]
[maybe-arg (rest args)]) [maybe-arg (rest args)])
macc (into macc (expand data opts)) macc (into macc (expand data opts))
child-routes (walk-many (str pacc path) macc (keep identity childs))] child-routes (walk-many (str pacc path) macc (keep identity childs))]
(if (seq childs) (seq child-routes) [[(str pacc path) macc]])))))] (if (seq childs) (seq child-routes) [[(str pacc path) macc]])))))]
(walk-one path (mapv identity data) raw-routes))) (walk-one path (mapv identity data) raw-routes)))
(defn map-data [f routes] (defn map-data [f routes]
@ -62,25 +62,25 @@
(defn merge-data [p x] (defn merge-data [p x]
(reduce (reduce
(fn [acc [k v]] (fn [acc [k v]]
(try (try
(mm/meta-merge acc {k v}) (mm/meta-merge acc {k v})
(catch #?(:clj Exception, :cljs js/Error) e (catch #?(:clj Exception, :cljs js/Error) e
(ex/fail! ::merge-data {:path p, :left acc, :right {k v}, :exception e})))) (ex/fail! ::merge-data {:path p, :left acc, :right {k v}, :exception e}))))
{} x)) {} x))
(defn resolve-routes [raw-routes {:keys [coerce] :as opts}] (defn resolve-routes [raw-routes {:keys [coerce] :as opts}]
(cond->> (->> (walk raw-routes opts) (map-data merge-data)) (cond->> (->> (walk raw-routes opts) (map-data merge-data))
coerce (into [] (keep #(coerce % opts))))) coerce (into [] (keep #(coerce % opts)))))
(defn path-conflicting-routes [routes opts] (defn path-conflicting-routes [routes opts]
(let [parts-and-routes (mapv (fn [[s :as r]] [(trie/split-path s opts) r]) routes)] (let [parts-and-routes (mapv (fn [[s :as r]] [(trie/split-path s opts) r]) routes)]
(-> (into {} (comp (map-indexed (fn [index [p r]] (-> (into {} (comp (map-indexed (fn [index [p r]]
[r (reduce [r (reduce
(fn [acc [p' r']] (fn [acc [p' r']]
(if (trie/conflicting-parts? p p') (if (trie/conflicting-parts? p p')
(conj acc r') acc)) (conj acc r') acc))
#{} (subvec parts-and-routes (inc index)))])) #{} (subvec parts-and-routes (inc index)))]))
(filter (comp seq second))) parts-and-routes) (filter (comp seq second))) parts-and-routes)
(not-empty)))) (not-empty))))
@ -123,13 +123,13 @@
(defn path-for [route path-params] (defn path-for [route path-params]
(if (:path-params route) (if (:path-params route)
(if-let [parts (reduce (if-let [parts (reduce
(fn [acc part] (fn [acc part]
(if (string? part) (if (string? part)
(conj acc part) (conj acc part)
(if-let [p (get path-params (:value part))] (if-let [p (get path-params (:value part))]
(conj acc p) (conj acc p)
(reduced nil)))) (reduced nil))))
[] (:path-parts route))] [] (:path-parts route))]
(apply str parts)) (apply str parts))
(:path route))) (:path route)))
@ -138,8 +138,8 @@
(let [defined (-> path-params keys set) (let [defined (-> path-params keys set)
missing (set/difference required defined)] missing (set/difference required defined)]
(ex/fail! (ex/fail!
(str "missing path-params for route " template " -> " missing) (str "missing path-params for route " template " -> " missing)
{:path-params path-params, :required required})))) {:path-params path-params, :required required}))))
(defn fast-assoc (defn fast-assoc
#?@(:clj [[^clojure.lang.Associative a k v] (.assoc a k v)] #?@(:clj [[^clojure.lang.Associative a k v] (.assoc a k v)]
@ -178,10 +178,10 @@
(if s (if s
#?(:clj (if (.contains ^String s "%") #?(:clj (if (.contains ^String s "%")
(URLDecoder/decode (URLDecoder/decode
(if (.contains ^String s "+") (if (.contains ^String s "+")
(.replace ^String s "+" "%2B") (.replace ^String s "+" "%2B")
^String s) ^String s)
"UTF-8")) "UTF-8"))
:cljs (js/decodeURIComponent s)))) :cljs (js/decodeURIComponent s))))
(defn url-decode [s] (defn url-decode [s]

View file

@ -37,36 +37,36 @@
(if-let [interceptor (if registry (registry this))] (if-let [interceptor (if registry (registry this))]
(into-interceptor interceptor data opts) (into-interceptor interceptor data opts)
(throw (throw
(ex-info (ex-info
(str (str
"Interceptor " this " not found in registry.\n\n" "Interceptor " this " not found in registry.\n\n"
(if (seq registry) (if (seq registry)
(str (str
"Available interceptors in registry:\n" "Available interceptors in registry:\n"
(with-out-str (with-out-str
(pprint/print-table [:id :description] (for [[k v] registry] {:id k :description v})))) (pprint/print-table [:id :description] (for [[k v] registry] {:id k :description v}))))
"see [reitit.interceptor/router] on how to add interceptor to the registry.\n") "\n") "see [reitit.interceptor/router] on how to add interceptor to the registry.\n") "\n")
{:id this {:id this
:registry registry})))) :registry registry}))))
#?(:clj clojure.lang.APersistentVector #?(:clj clojure.lang.APersistentVector
:cljs cljs.core.PersistentVector) :cljs cljs.core.PersistentVector)
(into-interceptor [[f & args :as form] data opts] (into-interceptor [[f & args :as form] data opts]
(when (and (seq args) (not (fn? f))) (when (and (seq args) (not (fn? f)))
(exception/fail! (exception/fail!
(str "Invalid Interceptor form: " form "") (str "Invalid Interceptor form: " form "")
{:form form})) {:form form}))
(into-interceptor (apply f args) data opts)) (into-interceptor (apply f args) data opts))
#?(:clj clojure.lang.Fn #?(:clj clojure.lang.Fn
:cljs function) :cljs function)
(into-interceptor [this data opts] (into-interceptor [this data opts]
(into-interceptor (into-interceptor
{:name ::handler {:name ::handler
::handler this ::handler this
:enter (fn [ctx] :enter (fn [ctx]
(assoc ctx :response (this (:request ctx))))} (assoc ctx :response (this (:request ctx))))}
data opts)) data opts))
#?(:clj clojure.lang.PersistentArrayMap #?(:clj clojure.lang.PersistentArrayMap
:cljs cljs.core.PersistentArrayMap) :cljs cljs.core.PersistentArrayMap)
@ -86,13 +86,13 @@
opts (assoc opts ::compiled (inc ^long compiled))] opts (assoc opts ::compiled (inc ^long compiled))]
(when (>= ^long compiled ^long *max-compile-depth*) (when (>= ^long compiled ^long *max-compile-depth*)
(exception/fail! (exception/fail!
(str "Too deep Interceptor compilation - " compiled) (str "Too deep Interceptor compilation - " compiled)
{:this this, :data data, :opts opts})) {:this this, :data data, :opts opts}))
(if-let [interceptor (into-interceptor (compile data opts) data opts)] (if-let [interceptor (into-interceptor (compile data opts) data opts)]
(map->Interceptor (map->Interceptor
(merge (merge
(dissoc this :compile) (dissoc this :compile)
(impl/strip-nils interceptor))))))) (impl/strip-nils interceptor)))))))
nil nil
(into-interceptor [_ _ _])) (into-interceptor [_ _ _]))
@ -122,9 +122,9 @@
([[_ {:keys [interceptors handler] :as data}] {::keys [queue] :as opts} _] ([[_ {:keys [interceptors handler] :as data}] {::keys [queue] :as opts} _]
(let [chain (chain (into (vec interceptors) [handler]) data opts)] (let [chain (chain (into (vec interceptors) [handler]) data opts)]
(map->Endpoint (map->Endpoint
{:interceptors chain {:interceptors chain
:queue ((or queue identity) chain) :queue ((or queue identity) chain)
:data data})))) :data data}))))
(defn transform-butlast (defn transform-butlast
"Returns a function to that takes a interceptor transformation function and "Returns a function to that takes a interceptor transformation function and
@ -132,8 +132,8 @@
[f] [f]
(fn [interceptors] (fn [interceptors]
(concat (concat
(f (butlast interceptors)) (f (butlast interceptors))
[(last interceptors)]))) [(last interceptors)])))
(defn router (defn router
"Creates a [[reitit.core/Router]] from raw route data and optionally an options map with "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with

View file

@ -21,17 +21,17 @@
(if-let [middleware (if registry (registry this))] (if-let [middleware (if registry (registry this))]
(into-middleware middleware data opts) (into-middleware middleware data opts)
(throw (throw
(ex-info (ex-info
(str (str
"Middleware " this " not found in registry.\n\n" "Middleware " this " not found in registry.\n\n"
(if (seq registry) (if (seq registry)
(str (str
"Available middleware in registry:\n" "Available middleware in registry:\n"
(with-out-str (with-out-str
(pprint/print-table [:id :description] (for [[k v] registry] {:id k :description v})))) (pprint/print-table [:id :description] (for [[k v] registry] {:id k :description v}))))
"see [reitit.middleware/router] on how to add middleware to the registry.\n") "\n") "see [reitit.middleware/router] on how to add middleware to the registry.\n") "\n")
{:id this {:id this
:registry registry})))) :registry registry}))))
#?(:clj clojure.lang.APersistentVector #?(:clj clojure.lang.APersistentVector
:cljs cljs.core.PersistentVector) :cljs cljs.core.PersistentVector)
@ -43,7 +43,7 @@
:cljs function) :cljs function)
(into-middleware [this _ _] (into-middleware [this _ _]
(map->Middleware (map->Middleware
{:wrap this})) {:wrap this}))
#?(:clj clojure.lang.PersistentArrayMap #?(:clj clojure.lang.PersistentArrayMap
:cljs cljs.core.PersistentArrayMap) :cljs cljs.core.PersistentArrayMap)
@ -63,13 +63,13 @@
opts (assoc opts ::compiled (inc ^long compiled))] opts (assoc opts ::compiled (inc ^long compiled))]
(when (>= ^long compiled ^long *max-compile-depth*) (when (>= ^long compiled ^long *max-compile-depth*)
(exception/fail! (exception/fail!
(str "Too deep Middleware compilation - " compiled) (str "Too deep Middleware compilation - " compiled)
{:this this, :data data, :opts opts})) {:this this, :data data, :opts opts}))
(if-let [middeware (into-middleware (compile data opts) data opts)] (if-let [middeware (into-middleware (compile data opts) data opts)]
(map->Middleware (map->Middleware
(merge (merge
(dissoc this :compile) (dissoc this :compile)
(impl/strip-nils middeware))))))) (impl/strip-nils middeware)))))))
nil nil
(into-middleware [_ _ _])) (into-middleware [_ _ _]))
@ -77,10 +77,10 @@
(defn- ensure-handler! [path data scope] (defn- ensure-handler! [path data scope]
(when-not (:handler data) (when-not (:handler data)
(exception/fail! (exception/fail!
(str "path \"" path "\" doesn't have a :handler defined" (str "path \"" path "\" doesn't have a :handler defined"
(if scope (str " for " scope))) (if scope (str " for " scope)))
(merge {:path path, :data data} (merge {:path path, :data data}
(if scope {:scope scope}))))) (if scope {:scope scope})))))
(defn- expand-and-transform (defn- expand-and-transform
[middleware data {::keys [transform] :or {transform identity} :as opts}] [middleware data {::keys [transform] :or {transform identity} :as opts}]
@ -116,9 +116,9 @@
(ensure-handler! path data scope) (ensure-handler! path data scope)
(let [middleware (expand-and-transform middleware data opts)] (let [middleware (expand-and-transform middleware data opts)]
(map->Endpoint (map->Endpoint
{:handler (compile-handler middleware handler) {:handler (compile-handler middleware handler)
:middleware middleware :middleware middleware
:data data})))) :data data}))))
(defn router (defn router
"Creates a [[reitit.core/Router]] from raw route data and optionally an options map with "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with

View file

@ -16,9 +16,9 @@
(s/def ::raw-route (s/def ::raw-route
(s/nilable (s/nilable
(s/cat :path ::path (s/cat :path ::path
:arg (s/? ::arg) :arg (s/? ::arg)
:childs (s/* (s/and (s/nilable ::raw-routes)))))) :childs (s/* (s/and (s/nilable ::raw-routes))))))
(s/def ::raw-routes (s/def ::raw-routes
(s/or :route ::raw-route (s/or :route ::raw-route
@ -60,19 +60,19 @@
(s/def ::opts (s/def ::opts
(s/nilable (s/nilable
(s/keys :opt-un [:reitit.router/path (s/keys :opt-un [:reitit.router/path
:reitit.router/routes :reitit.router/routes
:reitit.router/data :reitit.router/data
:reitit.router/expand :reitit.router/expand
:reitit.router/coerce :reitit.router/coerce
:reitit.router/compile :reitit.router/compile
:reitit.router/conflicts :reitit.router/conflicts
:reitit.router/router]))) :reitit.router/router])))
(s/fdef r/router (s/fdef r/router
:args (s/or :1arity (s/cat :data (s/spec ::raw-routes)) :args (s/or :1arity (s/cat :data (s/spec ::raw-routes))
:2arity (s/cat :data (s/spec ::raw-routes), :opts ::opts)) :2arity (s/cat :data (s/spec ::raw-routes), :opts ::opts))
:ret ::router) :ret ::router)
;; ;;
;; coercion ;; coercion
@ -128,15 +128,15 @@
(defn validate [routes {:keys [spec] ::keys [wrap] :or {spec ::default-data, wrap identity}}] (defn validate [routes {:keys [spec] ::keys [wrap] :or {spec ::default-data, wrap identity}}]
(when-let [problems (validate-route-data routes wrap spec)] (when-let [problems (validate-route-data routes wrap spec)]
(exception/fail! (exception/fail!
::invalid-route-data ::invalid-route-data
{:problems problems}))) {:problems problems})))
(defmethod exception/format-exception :reitit.spec/invalid-route-data [_ _ {:keys [problems]}] (defmethod exception/format-exception :reitit.spec/invalid-route-data [_ _ {:keys [problems]}]
(apply str "Invalid route data:\n\n" (apply str "Invalid route data:\n\n"
(mapv (mapv
(fn [{:keys [path scope data spec]}] (fn [{:keys [path scope data spec]}]
(str "-- On route -----------------------\n\n" (str "-- On route -----------------------\n\n"
(pr-str path) (if scope (str " " (pr-str scope))) "\n\n" (pr-str path) (if scope (str " " (pr-str scope))) "\n\n"
(pr-str data) "\n\n" (pr-str data) "\n\n"
(s/explain-str spec data) "\n")) (s/explain-str spec data) "\n"))
problems))) problems)))

View file

@ -90,12 +90,12 @@
(defn join-path [xs] (defn join-path [xs]
(reduce (reduce
(fn [s x] (fn [s x]
(str s (cond (str s (cond
(string? x) x (string? x) x
(instance? Wild x) (str "{" (-> x :value str (subs 1)) "}") (instance? Wild x) (str "{" (-> x :value str (subs 1)) "}")
(instance? CatchAll x) (str "{*" (-> x :value str (subs 1)) "}")))) (instance? CatchAll x) (str "{*" (-> x :value str (subs 1)) "}"))))
"" xs)) "" xs))
(defn normalize [s opts] (defn normalize [s opts]
(-> s (split-path opts) (join-path))) (-> s (split-path opts) (join-path)))
@ -172,25 +172,25 @@
:else :else
(or (or
(reduce (reduce
(fn [_ [p n]] (fn [_ [p n]]
(if-let [cp (common-prefix p path)] (if-let [cp (common-prefix p path)]
(if (= cp p) (if (= cp p)
;; insert into child node ;; insert into child node
(let [n' (-insert n (conj ps (subs path (count p))) fp params data)] (let [n' (-insert n (conj ps (subs path (count p))) fp params data)]
(reduced (assoc-in node [:children p] n'))) (reduced (assoc-in node [:children p] n')))
;; split child node ;; split child node
(let [rp (subs p (count cp)) (let [rp (subs p (count cp))
rp' (subs path (count cp)) rp' (subs path (count cp))
n' (-insert (-node {}) ps fp params data) n' (-insert (-node {}) ps fp params data)
n'' (-insert (-node {:children {rp n, rp' n'}}) nil nil nil nil)] n'' (-insert (-node {:children {rp n, rp' n'}}) nil nil nil nil)]
(reduced (update node :children (fn [children] (reduced (update node :children (fn [children]
(-> children (-> children
(dissoc p) (dissoc p)
(assoc cp n''))))))))) (assoc cp n'')))))))))
nil (:children node)) nil (:children node))
;; new child node ;; new child node
(assoc-in node [:children path] (-insert (-node {}) ps fp params data))))] (assoc-in node [:children path] (-insert (-node {}) ps fp params data))))]
(if-let [child (get-in node' [:children ""])] (if-let [child (get-in node' [:children ""])]
;; optimize by removing empty paths ;; optimize by removing empty paths
(-> (merge-with merge (dissoc node' :data) child) (-> (merge-with merge (dissoc node' :data) child)
@ -202,10 +202,10 @@
(if percent? (if percent?
#?(:cljs (js/decodeURIComponent param) #?(:cljs (js/decodeURIComponent param)
:clj (URLDecoder/decode :clj (URLDecoder/decode
(if (.contains ^String param "+") (if (.contains ^String param "+")
(.replace ^String param "+" "%2B") (.replace ^String param "+" "%2B")
param) param)
"UTF-8")) "UTF-8"))
param))) param)))
;; ;;
@ -313,13 +313,13 @@
(def record-parameters (def record-parameters
"Memoized function to transform parameters into runtime generated Record." "Memoized function to transform parameters into runtime generated Record."
(memoize (memoize
(fn [keys] (fn [keys]
(if (some qualified-keyword? keys) (if (some qualified-keyword? keys)
(map-parameters keys) (map-parameters keys)
(let [sym (gensym "PathParams") (let [sym (gensym "PathParams")
ctor (symbol (str "map->" sym))] ctor (symbol (str "map->" sym))]
(binding [*ns* (find-ns 'user)] (binding [*ns* (find-ns 'user)]
(eval `(do (defrecord ~sym ~(mapv (comp symbol name) keys)) (~ctor {})))))))))) (eval `(do (defrecord ~sym ~(mapv (comp symbol name) keys)) (~ctor {}))))))))))
(defn insert (defn insert
"Returns a trie with routes added to it." "Returns a trie with routes added to it."
@ -327,9 +327,9 @@
(insert nil routes)) (insert nil routes))
([node routes] ([node routes]
(reduce (reduce
(fn [acc [p d]] (fn [acc [p d]]
(insert acc p d)) (insert acc p d))
node routes)) node routes))
([node path data] ([node path data]
(insert node path data nil)) (insert node path data nil))
([node path data {::keys [parameters] :or {parameters map-parameters} :as opts}] ([node path data {::keys [parameters] :or {parameters map-parameters} :as opts}]
@ -355,12 +355,12 @@
(cond-> data (conj (data-matcher compiler params data))) (cond-> data (conj (data-matcher compiler params data)))
(into (for [[p c] children] (static-matcher compiler p (compile c compiler (conj cp p))))) (into (for [[p c] children] (static-matcher compiler p (compile c compiler (conj cp p)))))
(into (into
(for [[p c] wilds] (for [[p c] wilds]
(let [pv (:value p) (let [pv (:value p)
ends (ends c)] ends (ends c)]
(if (next ends) (if (next ends)
(ex/fail! ::multiple-terminators {:terminators ends, :path (join-path (conj cp p))}) (ex/fail! ::multiple-terminators {:terminators ends, :path (join-path (conj cp p))})
(wild-matcher compiler pv (ffirst ends) (compile c compiler (conj cp pv))))))) (wild-matcher compiler pv (ffirst ends) (compile c compiler (conj cp pv)))))))
(into (for [[p c] catch-all] (catch-all-matcher compiler (:value p) params (:data c)))))] (into (for [[p c] catch-all] (catch-all-matcher compiler (:value p) params (:data c)))))]
(cond (cond
(> (count matchers) 1) (linear-matcher compiler matchers false) (> (count matchers) 1) (linear-matcher compiler matchers false)
@ -387,61 +387,61 @@
(comment (comment
(-> (->
[["/v2/whoami" 1] [["/v2/whoami" 1]
["/v2/users/:user-id/datasets" 2] ["/v2/users/:user-id/datasets" 2]
["/v2/public/projects/:project-id/datasets" 3] ["/v2/public/projects/:project-id/datasets" 3]
["/v1/public/topics/:topic" 4] ["/v1/public/topics/:topic" 4]
["/v1/users/:user-id/orgs/:org-id" 5] ["/v1/users/:user-id/orgs/:org-id" 5]
["/v1/search/topics/:term" 6] ["/v1/search/topics/:term" 6]
["/v1/users/:user-id/invitations" 7] ["/v1/users/:user-id/invitations" 7]
["/v1/users/:user-id/topics" 9] ["/v1/users/:user-id/topics" 9]
["/v1/users/:user-id/bookmarks/followers" 10] ["/v1/users/:user-id/bookmarks/followers" 10]
["/v2/datasets/:dataset-id" 11] ["/v2/datasets/:dataset-id" 11]
["/v1/orgs/:org-id/usage-stats" 12] ["/v1/orgs/:org-id/usage-stats" 12]
["/v1/orgs/:org-id/devices/:client-id" 13] ["/v1/orgs/:org-id/devices/:client-id" 13]
["/v1/messages/user/:user-id" 14] ["/v1/messages/user/:user-id" 14]
["/v1/users/:user-id/devices" 15] ["/v1/users/:user-id/devices" 15]
["/v1/public/users/:user-id" 16] ["/v1/public/users/:user-id" 16]
["/v1/orgs/:org-id/errors" 17] ["/v1/orgs/:org-id/errors" 17]
["/v1/public/orgs/:org-id" 18] ["/v1/public/orgs/:org-id" 18]
["/v1/orgs/:org-id/invitations" 19] ["/v1/orgs/:org-id/invitations" 19]
["/v1/users/:user-id/device-errors" 22] ["/v1/users/:user-id/device-errors" 22]
["/v2/login" 23] ["/v2/login" 23]
["/v1/users/:user-id/usage-stats" 24] ["/v1/users/:user-id/usage-stats" 24]
["/v2/users/:user-id/devices" 25] ["/v2/users/:user-id/devices" 25]
["/v1/users/:user-id/claim-device/:client-id" 26] ["/v1/users/:user-id/claim-device/:client-id" 26]
["/v2/public/projects/:project-id" 27] ["/v2/public/projects/:project-id" 27]
["/v2/public/datasets/:dataset-id" 28] ["/v2/public/datasets/:dataset-id" 28]
["/v2/users/:user-id/topics/bulk" 29] ["/v2/users/:user-id/topics/bulk" 29]
["/v1/messages/device/:client-id" 30] ["/v1/messages/device/:client-id" 30]
["/v1/users/:user-id/owned-orgs" 31] ["/v1/users/:user-id/owned-orgs" 31]
["/v1/topics/:topic" 32] ["/v1/topics/:topic" 32]
["/v1/users/:user-id/bookmark/:topic" 33] ["/v1/users/:user-id/bookmark/:topic" 33]
["/v1/orgs/:org-id/members/:user-id" 34] ["/v1/orgs/:org-id/members/:user-id" 34]
["/v1/users/:user-id/devices/:client-id" 35] ["/v1/users/:user-id/devices/:client-id" 35]
["/v1/users/:user-id" 36] ["/v1/users/:user-id" 36]
["/v1/orgs/:org-id/devices" 37] ["/v1/orgs/:org-id/devices" 37]
["/v1/orgs/:org-id/members" 38] ["/v1/orgs/:org-id/members" 38]
["/v2/orgs/:org-id/topics" 40] ["/v2/orgs/:org-id/topics" 40]
["/v1/whoami" 41] ["/v1/whoami" 41]
["/v1/orgs/:org-id" 42] ["/v1/orgs/:org-id" 42]
["/v1/users/:user-id/api-key" 43] ["/v1/users/:user-id/api-key" 43]
["/v2/schemas" 44] ["/v2/schemas" 44]
["/v2/users/:user-id/topics" 45] ["/v2/users/:user-id/topics" 45]
["/v1/orgs/:org-id/confirm-membership/:token" 46] ["/v1/orgs/:org-id/confirm-membership/:token" 46]
["/v2/topics/:topic" 47] ["/v2/topics/:topic" 47]
["/v1/messages/topic/:topic" 48] ["/v1/messages/topic/:topic" 48]
["/v1/users/:user-id/devices/:client-id/reset-password" 49] ["/v1/users/:user-id/devices/:client-id/reset-password" 49]
["/v2/topics" 50] ["/v2/topics" 50]
["/v1/login" 51] ["/v1/login" 51]
["/v1/users/:user-id/orgs" 52] ["/v1/users/:user-id/orgs" 52]
["/v2/public/messages/dataset/:dataset-id" 53] ["/v2/public/messages/dataset/:dataset-id" 53]
["/v1/topics" 54] ["/v1/topics" 54]
["/v1/orgs" 55] ["/v1/orgs" 55]
["/v1/users/:user-id/bookmarks" 56] ["/v1/users/:user-id/bookmarks" 56]
["/v1/orgs/:org-id/topics" 57] ["/v1/orgs/:org-id/topics" 57]
["/command1 {arg1} {arg2}" ::cmd1] ["/command1 {arg1} {arg2}" ::cmd1]
["/command2 {arg1} {arg2} {arg3}" ::cmd2]] ["/command2 {arg1} {arg2} {arg3}" ::cmd2]]
(insert) (insert)
(compile) (compile)
(pretty))) (pretty)))

View file

@ -152,13 +152,13 @@
(printer nil)) (printer nil))
([options] ([options]
(map->EdnPrinter (map->EdnPrinter
(merge (merge
{:width 80 {:width 80
:symbols {} :symbols {}
:print-length *print-length* :print-length *print-length*
:print-level *print-level* :print-level *print-level*
:print-meta *print-meta*} :print-meta *print-meta*}
options)))) options))))
(defn pprint (defn pprint
([x] (pprint x {})) ([x] (pprint x {}))
@ -209,13 +209,13 @@
(defn exception-str [message source printer] (defn exception-str [message source printer]
(with-out-str (with-out-str
(print-doc (print-doc
[:group [:group
(title "Router creation failed" source printer) (title "Router creation failed" source printer)
[:break] [:break] [:break] [:break]
message message
[:break] [:break]
(footer printer)] (footer printer)]
printer))) printer)))
(defmulti format-exception (fn [type _ _] type)) (defmulti format-exception (fn [type _ _] type))
@ -231,11 +231,11 @@
(defn de-expound-colors [^String s mappings] (defn de-expound-colors [^String s mappings]
(let [s' (reduce (let [s' (reduce
(fn [s [from to]] (fn [s [from to]]
(.replace ^String s (.replace ^String s
^String (expound.ansi/esc [from]) ^String (expound.ansi/esc [from])
^String (-start (colors to)))) ^String (-start (colors to))))
s mappings)] s mappings)]
(.replace ^String s' (.replace ^String s'
^String (expound.ansi/esc [:none]) ^String (expound.ansi/esc [:none])
(str (expound.ansi/esc [:none]) (-start (colors :text)))))) (str (expound.ansi/esc [:none]) (-start (colors :text))))))
@ -254,9 +254,9 @@
(def expound-printer (def expound-printer
(expound.alpha/custom-printer (expound.alpha/custom-printer
{:theme :figwheel-theme {:theme :figwheel-theme
:show-valid-values? false :show-valid-values? false
:print-specs? false})) :print-specs? false}))
;; ;;
;; Formatters ;; Formatters
@ -276,18 +276,18 @@
" ") " ")
(edn (not-empty (select-keys route-data [:conflicting])))])] (edn (not-empty (select-keys route-data [:conflicting])))])]
(into (into
[:group] [:group]
(mapv (mapv
(fn [[[path route-data] vals]] (fn [[[path route-data] vals]]
[:group [:group
(path-report path route-data) (path-report path route-data)
(into (into
[:group] [:group]
(map (map
(fn [[path route-data]] (path-report path route-data)) (fn [[path route-data]] (path-report path route-data))
vals)) vals))
[:break]]) [:break]])
conflicts))) conflicts)))
[:span (text "Either fix the conflicting paths or disable the conflict resolution") [:span (text "Either fix the conflicting paths or disable the conflict resolution")
[:break] (text "by setting route data for conflicting route: ") [:break] [:break] [:break] (text "by setting route data for conflicting route: ") [:break] [:break]
(edn {:conflicting true} {:margin 3}) (edn {:conflicting true} {:margin 3})
@ -302,19 +302,19 @@
(text "Router contains conflicting route names:") (text "Router contains conflicting route names:")
[:break] [:break] [:break] [:break]
(into (into
[:group] [:group]
(mapv (mapv
(fn [[name vals]] (fn [[name vals]]
[:group [:group
[:span (text name)] [:span (text name)]
[:break] [:break]
(into (into
[:group] [:group]
(map (map
(fn [p] [:span (color :grey "-> " p) [:break]]) (fn [p] [:span (color :grey "-> " p) [:break]])
(mapv first vals))) (mapv first vals)))
[:break]]) [:break]])
conflicts)) conflicts))
(color :white "https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-conflicts") (color :white "https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-conflicts")
[:break]]) [:break]])
@ -323,22 +323,22 @@
(text "Invalid route data:") (text "Invalid route data:")
[:break] [:break] [:break] [:break]
(into (into
[:group] [:group]
(map (map
(fn [{:keys [data path spec scope]}] (fn [{:keys [data path spec scope]}]
[:group [:group
[:span (color :grey "-- On route -----------------------")] [:span (color :grey "-- On route -----------------------")]
[:break] [:break]
[:break] [:break]
(text path) (if scope [:span " " (text scope)]) (text path) (if scope [:span " " (text scope)])
[:break] [:break]
[:break] [:break]
(-> (s/explain-data spec data) (-> (s/explain-data spec data)
(expound-printer) (expound-printer)
(with-out-str) (with-out-str)
(fippify)) (fippify))
[:break]]) [:break]])
problems)) problems))
(color :white "https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-data-validation") (color :white "https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-data-validation")
[:break]]) [:break]])

View file

@ -64,11 +64,11 @@
(let [defined (-> path-params keys set) (let [defined (-> path-params keys set)
missing (set/difference (:required match) defined)] missing (set/difference (:required match) defined)]
(js/console.warn (js/console.warn
"missing path-params for route" name "missing path-params for route" name
{:template (:template match) {:template (:template match)
:missing missing :missing missing
:path-params path-params :path-params path-params
:required (:required match)}) :required (:required match)})
nil)) nil))
match) match)
(do (js/console.warn "missing route" name) (do (js/console.warn "missing route" name)

View file

@ -38,7 +38,7 @@
(when (nil? @history) (when (nil? @history)
(reset! history this)) (reset! history this))
(on-navigate m this)) (on-navigate m this))
opts)) opts))
(defn (defn
^{:see-also ["reitit.frontend.history/href"]} ^{:see-also ["reitit.frontend.history/href"]}

View file

@ -9,16 +9,16 @@
(defn coerce-handler [[path data] {:keys [expand] :as opts}] (defn coerce-handler [[path data] {:keys [expand] :as opts}]
[path (reduce [path (reduce
(fn [acc method] (fn [acc method]
(if (contains? acc method) (if (contains? acc method)
(update acc method expand opts) (update acc method expand opts)
acc)) data ring/http-methods)]) acc)) data ring/http-methods)])
(defn compile-result [[path data] {:keys [::default-options-endpoint expand] :as opts}] (defn compile-result [[path data] {:keys [::default-options-endpoint expand] :as opts}]
(let [[top childs] (ring/group-keys data) (let [[top childs] (ring/group-keys data)
childs (cond-> childs childs (cond-> childs
(and (not (:options childs)) (not (:handler top)) default-options-endpoint) (and (not (:options childs)) (not (:handler top)) default-options-endpoint)
(assoc :options (expand default-options-endpoint opts))) (assoc :options (expand default-options-endpoint opts)))
compile (fn [[path data] opts scope] compile (fn [[path data] opts scope]
(interceptor/compile-result [path data] opts scope)) (interceptor/compile-result [path data] opts scope))
->endpoint (fn [p d m s] ->endpoint (fn [p d m s]
@ -29,19 +29,19 @@
(assoc :method m)))) (assoc :method m))))
->methods (fn [any? data] ->methods (fn [any? data]
(reduce (reduce
(fn [acc method] (fn [acc method]
(cond-> acc (cond-> acc
any? (assoc method (->endpoint path data method nil)))) any? (assoc method (->endpoint path data method nil))))
(ring/map->Methods {}) (ring/map->Methods {})
ring/http-methods))] ring/http-methods))]
(if-not (seq childs) (if-not (seq childs)
(->methods true top) (->methods true top)
(reduce-kv (reduce-kv
(fn [acc method data] (fn [acc method data]
(let [data (meta-merge top data)] (let [data (meta-merge top data)]
(assoc acc method (->endpoint path data method method)))) (assoc acc method (->endpoint path data method method))))
(->methods (:handler top) data) (->methods (:handler top) data)
childs)))) childs))))
(defn router (defn router
"Creates a [[reitit.core/Router]] from raw route data and optionally an options map with "Creates a [[reitit.core/Router]] from raw route data and optionally an options map with
@ -133,7 +133,7 @@
(assoc ::interceptor/queue (partial interceptor/queue executor)) (assoc ::interceptor/queue (partial interceptor/queue executor))
(dissoc :data) ; data is already merged into routes (dissoc :data) ; data is already merged into routes
(cond-> (seq interceptors) (cond-> (seq interceptors)
(update-in [:data :interceptors] (partial into (vec interceptors))))) (update-in [:data :interceptors] (partial into (vec interceptors)))))
router (reitit.http/router (r/routes router) router-opts) ;; will re-compile the interceptors router (reitit.http/router (r/routes router) router-opts) ;; will re-compile the interceptors
enrich-request (ring/create-enrich-request inject-match? inject-router?) enrich-request (ring/create-enrich-request inject-match? inject-router?)
enrich-default-request (ring/create-enrich-default-request inject-router?)] enrich-default-request (ring/create-enrich-default-request inject-router?)]

View file

@ -22,5 +22,5 @@
[routes {:keys [spec ::rs/wrap] :or {spec ::data, wrap identity}}] [routes {:keys [spec ::rs/wrap] :or {spec ::data, wrap identity}}]
(when-let [problems (rrs/validate-route-data routes :interceptors wrap spec)] (when-let [problems (rrs/validate-route-data routes :interceptors wrap spec)]
(exception/fail! (exception/fail!
::rs/invalid-route-data ::rs/invalid-route-data
{:problems problems}))) {:problems problems})))

View file

@ -36,16 +36,16 @@
[stages {:keys [enter leave error name] :as interceptor}] [stages {:keys [enter leave error name] :as interceptor}]
(if (->> (select-keys interceptor stages) (vals) (keep identity) (seq)) (if (->> (select-keys interceptor stages) (vals) (keep identity) (seq))
(cond-> {:name ::diff} (cond-> {:name ::diff}
(and enter (stages :enter)) (assoc :enter (handle name :enter)) (and enter (stages :enter)) (assoc :enter (handle name :enter))
(and leave (stages :leave)) (assoc :leave (handle name :leave)) (and leave (stages :leave)) (assoc :leave (handle name :leave))
(and error (stages :error)) (assoc :error (handle name :error))))) (and error (stages :error)) (assoc :error (handle name :error)))))
(defn print-context-diffs (defn print-context-diffs
"A interceptor chain transformer that adds a context diff printer between all interceptors" "A interceptor chain transformer that adds a context diff printer between all interceptors"
[interceptors] [interceptors]
(reduce (reduce
(fn [chain interceptor] (fn [chain interceptor]
(into chain (keep identity [(diff-interceptor #{:leave :error} interceptor) (into chain (keep identity [(diff-interceptor #{:leave :error} interceptor)
interceptor interceptor
(diff-interceptor #{:enter} interceptor)]))) (diff-interceptor #{:enter} interceptor)])))
[(diff-interceptor #{:enter :leave :error} {:enter identity})] interceptors)) [(diff-interceptor #{:enter :leave :error} {:enter identity})] interceptors))

View file

@ -25,11 +25,11 @@
error-handler (or (get handlers type) error-handler (or (get handlers type)
(get handlers ex-class) (get handlers ex-class)
(some (some
(partial get handlers) (partial get handlers)
(descendants type)) (descendants type))
(some (some
(partial get handlers) (partial get handlers)
(super-classes ex-class)) (super-classes ex-class))
(get handlers ::default))] (get handlers ::default))]
(if-let [wrap (get handlers ::wrap)] (if-let [wrap (get handlers ::wrap)]
(wrap error-handler error request) (wrap error-handler error request)

View file

@ -18,14 +18,14 @@
(def temp-file-part (def temp-file-part
"Spec for file param created by ring.middleware.multipart-params.temp-file store." "Spec for file param created by ring.middleware.multipart-params.temp-file store."
(st/spec (st/spec
{:spec (s/keys :req-un [::filename ::content-type ::tempfile ::size]) {:spec (s/keys :req-un [::filename ::content-type ::tempfile ::size])
:swagger/type "file"})) :swagger/type "file"}))
(def bytes-part (def bytes-part
"Spec for file param created by ring.middleware.multipart-params.byte-array store." "Spec for file param created by ring.middleware.multipart-params.byte-array store."
(st/spec (st/spec
{:spec (s/keys :req-un [::filename ::content-type ::bytes]) {:spec (s/keys :req-un [::filename ::content-type ::bytes])
:swagger/type "file"})) :swagger/type "file"}))
(defn- coerced-request [request coercers] (defn- coerced-request [request coercers]
(if-let [coerced (if coercers (coercion/coerce-request coercers request))] (if-let [coerced (if coercers (coercion/coerce-request coercers request))]
@ -49,7 +49,7 @@
:compile (fn [{:keys [parameters coercion]} opts] :compile (fn [{:keys [parameters coercion]} opts]
(if-let [multipart (:multipart parameters)] (if-let [multipart (:multipart parameters)]
(let [parameter-coercion {:multipart (coercion/->ParameterCoercion (let [parameter-coercion {:multipart (coercion/->ParameterCoercion
:multipart-params :string true true)} :multipart-params :string true true)}
opts (assoc opts ::coercion/parameter-coercion parameter-coercion) opts (assoc opts ::coercion/parameter-coercion parameter-coercion)
coercers (if multipart (coercion/request-coercers coercion parameters opts))] coercers (if multipart (coercion/request-coercers coercion parameters opts))]
{:data {:swagger {:consumes ^:replace #{"multipart/form-data"}}} {:data {:swagger {:consumes ^:replace #{"multipart/form-data"}}}

View file

@ -40,10 +40,10 @@
:compile (fn [{:keys [muuntaja parameters]} _] :compile (fn [{:keys [muuntaja parameters]} _]
(if-let [muuntaja (or muuntaja default-muuntaja)] (if-let [muuntaja (or muuntaja default-muuntaja)]
(merge (merge
(stripped (muuntaja.interceptor/format-interceptor muuntaja)) (stripped (muuntaja.interceptor/format-interceptor muuntaja))
(if (publish-swagger-data? parameters) (if (publish-swagger-data? parameters)
{:data {:swagger {:produces (displace (m/encodes muuntaja)) {:data {:swagger {:produces (displace (m/encodes muuntaja))
:consumes (displace (m/decodes muuntaja))}}}))))})) :consumes (displace (m/decodes muuntaja))}}}))))}))
(defn format-negotiate-interceptor (defn format-negotiate-interceptor
"Interceptor for content-negotiation. "Interceptor for content-negotiation.
@ -87,9 +87,9 @@
:compile (fn [{:keys [muuntaja parameters]} _] :compile (fn [{:keys [muuntaja parameters]} _]
(if-let [muuntaja (or muuntaja default-muuntaja)] (if-let [muuntaja (or muuntaja default-muuntaja)]
(merge (merge
(stripped (muuntaja.interceptor/format-request-interceptor muuntaja)) (stripped (muuntaja.interceptor/format-request-interceptor muuntaja))
(when (publish-swagger-data? parameters) (when (publish-swagger-data? parameters)
{:data {:swagger {:consumes (displace (m/decodes muuntaja))}}}))))})) {:data {:swagger {:consumes (displace (m/decodes muuntaja))}}}))))}))
(defn format-response-interceptor (defn format-response-interceptor
"Interceptor for response formatting. "Interceptor for response formatting.
@ -112,6 +112,6 @@
:compile (fn [{:keys [muuntaja parameters]} _] :compile (fn [{:keys [muuntaja parameters]} _]
(if-let [muuntaja (or muuntaja default-muuntaja)] (if-let [muuntaja (or muuntaja default-muuntaja)]
(merge (merge
(stripped (muuntaja.interceptor/format-response-interceptor muuntaja)) (stripped (muuntaja.interceptor/format-response-interceptor muuntaja))
(when (publish-swagger-data? parameters) (when (publish-swagger-data? parameters)
{:data {:swagger {:produces (displace (m/encodes muuntaja))}}}))))})) {:data {:swagger {:produces (displace (m/encodes muuntaja))}}}))))}))

View file

@ -26,9 +26,9 @@
(reify TransformationProvider (reify TransformationProvider
(-transformer [_ {:keys [strip-extra-keys default-values]}] (-transformer [_ {:keys [strip-extra-keys default-values]}]
(mt/transformer (mt/transformer
(if strip-extra-keys (mt/strip-extra-keys-transformer)) (if strip-extra-keys (mt/strip-extra-keys-transformer))
transformer transformer
(if default-values (mt/default-value-transformer)))))) (if default-values (mt/default-value-transformer))))))
(def string-transformer-provider (-provider (mt/string-transformer))) (def string-transformer-provider (-provider (mt/string-transformer)))
(def json-transformer-provider (-provider (mt/json-transformer))) (def json-transformer-provider (-provider (mt/json-transformer)))
@ -61,7 +61,7 @@
transformed transformed
(let [error (-explain coercer transformed)] (let [error (-explain coercer transformed)]
(coercion/map->CoercionError (coercion/map->CoercionError
(assoc error :transformed transformed))))) (assoc error :transformed transformed)))))
value)) value))
;; encode: decode -> validate -> encode ;; encode: decode -> validate -> encode
(fn [value format] (fn [value format]
@ -71,7 +71,7 @@
(-encode coercer transformed) (-encode coercer transformed)
(let [error (-explain coercer transformed)] (let [error (-explain coercer transformed)]
(coercion/map->CoercionError (coercion/map->CoercionError
(assoc error :transformed transformed)))) (assoc error :transformed transformed))))
value)))))))) value))))))))
;; ;;
@ -91,15 +91,15 @@
(defmethod extract-parameter :default [in schema options] (defmethod extract-parameter :default [in schema options]
(let [{:keys [properties required]} (swagger/transform schema (merge options {:in in, :type :parameter}))] (let [{:keys [properties required]} (swagger/transform schema (merge options {:in in, :type :parameter}))]
(mapv (mapv
(fn [[k {:keys [type] :as schema}]] (fn [[k {:keys [type] :as schema}]]
(merge (merge
{:in (name in) {:in (name in)
:name k :name k
:description (:description schema "") :description (:description schema "")
:type type :type type
:required (contains? (set required) k)} :required (contains? (set required) k)}
schema)) schema))
properties))) properties)))
;; ;;
;; public api ;; public api
@ -143,39 +143,39 @@
(-get-apidocs [_ specification {:keys [parameters responses]}] (-get-apidocs [_ specification {:keys [parameters responses]}]
(case specification (case specification
:swagger (merge :swagger (merge
(if parameters (if parameters
{:parameters {:parameters
(->> (for [[in schema] parameters (->> (for [[in schema] parameters
parameter (extract-parameter in (compile schema options) options)] parameter (extract-parameter in (compile schema options) options)]
parameter) parameter)
(into []))}) (into []))})
(if responses (if responses
{:responses {:responses
(into (into
(empty responses) (empty responses)
(for [[status response] responses] (for [[status response] responses]
[status (as-> response $ [status (as-> response $
(set/rename-keys $ {:body :schema}) (set/rename-keys $ {:body :schema})
(update $ :description (fnil identity "")) (update $ :description (fnil identity ""))
(if (:schema $) (if (:schema $)
(-> $ (-> $
(update :schema compile options) (update :schema compile options)
(update :schema swagger/transform {:type :schema})) (update :schema swagger/transform {:type :schema}))
$))]))})) $))]))}))
(throw (throw
(ex-info (ex-info
(str "Can't produce Schema apidocs for " specification) (str "Can't produce Schema apidocs for " specification)
{:type specification, :coercion :schema})))) {:type specification, :coercion :schema}))))
(-compile-model [_ model _] (compile model options)) (-compile-model [_ model _] (compile model options))
(-open-model [_ schema] schema) (-open-model [_ schema] schema)
(-encode-error [_ error] (-encode-error [_ error]
(cond-> error (cond-> error
(show? :humanized) (assoc :humanized (me/humanize error {:wrap :message})) (show? :humanized) (assoc :humanized (me/humanize error {:wrap :message}))
(show? :schema) (update :schema edn/write-string opts) (show? :schema) (update :schema edn/write-string opts)
(show? :errors) (-> (me/with-error-messages opts) (show? :errors) (-> (me/with-error-messages opts)
(update :errors (partial map #(update % :schema edn/write-string opts)))) (update :errors (partial map #(update % :schema edn/write-string opts))))
(seq error-keys) (select-keys error-keys) (seq error-keys) (select-keys error-keys)
encode-error (encode-error))) encode-error (encode-error)))
(-request-coercer [_ type schema] (-request-coercer [_ type schema]
(-coercer (compile schema options) type transformers :decode opts)) (-coercer (compile schema options) type transformers :decode opts))
(-response-coercer [_ schema] (-response-coercer [_ schema]

View file

@ -48,6 +48,6 @@
printer between all middleware." printer between all middleware."
[chain] [chain]
(reduce (reduce
(fn [chain mw] (fn [chain mw]
(into chain [mw (print-diff-middleware (select-keys mw [:name]))])) (into chain [mw (print-diff-middleware (select-keys mw [:name]))]))
[(print-diff-middleware)] chain)) [(print-diff-middleware)] chain))

View file

@ -25,11 +25,11 @@
error-handler (or (get handlers type) error-handler (or (get handlers type)
(get handlers ex-class) (get handlers ex-class)
(some (some
(partial get handlers) (partial get handlers)
(descendants type)) (descendants type))
(some (some
(partial get handlers) (partial get handlers)
(super-classes ex-class)) (super-classes ex-class))
(get handlers ::default))] (get handlers ::default))]
(if-let [wrap (get handlers ::wrap)] (if-let [wrap (get handlers ::wrap)]
(wrap error-handler error request) (wrap error-handler error request)

View file

@ -15,14 +15,14 @@
(def temp-file-part (def temp-file-part
"Spec for file param created by ring.middleware.multipart-params.temp-file store." "Spec for file param created by ring.middleware.multipart-params.temp-file store."
(st/spec (st/spec
{:spec (s/keys :req-un [::filename ::content-type ::tempfile ::size]) {:spec (s/keys :req-un [::filename ::content-type ::tempfile ::size])
:swagger/type "file"})) :swagger/type "file"}))
(def bytes-part (def bytes-part
"Spec for file param created by ring.middleware.multipart-params.byte-array store." "Spec for file param created by ring.middleware.multipart-params.byte-array store."
(st/spec (st/spec
{:spec (s/keys :req-un [::filename ::content-type ::bytes]) {:spec (s/keys :req-un [::filename ::content-type ::bytes])
:swagger/type "file"})) :swagger/type "file"}))
(defn- coerced-request [request coercers] (defn- coerced-request [request coercers]
(if-let [coerced (if coercers (coercion/coerce-request coercers request))] (if-let [coerced (if coercers (coercion/coerce-request coercers request))]
@ -33,7 +33,7 @@
(fn [{:keys [parameters coercion]} opts] (fn [{:keys [parameters coercion]} opts]
(if-let [multipart (:multipart parameters)] (if-let [multipart (:multipart parameters)]
(let [parameter-coercion {:multipart (coercion/->ParameterCoercion (let [parameter-coercion {:multipart (coercion/->ParameterCoercion
:multipart-params :string true true)} :multipart-params :string true true)}
opts (assoc opts ::coercion/parameter-coercion parameter-coercion) opts (assoc opts ::coercion/parameter-coercion parameter-coercion)
coercers (if multipart (coercion/request-coercers coercion parameters opts))] coercers (if multipart (coercion/request-coercers coercion parameters opts))]
{:data {:swagger {:consumes ^:replace #{"multipart/form-data"}}} {:data {:swagger {:consumes ^:replace #{"multipart/form-data"}}}

View file

@ -34,10 +34,10 @@
:compile (fn [{:keys [muuntaja parameters]} _] :compile (fn [{:keys [muuntaja parameters]} _]
(if muuntaja (if muuntaja
(merge (merge
(if (publish-swagger-data? parameters) (if (publish-swagger-data? parameters)
{:data {:swagger {:produces (displace (m/encodes muuntaja)) {:data {:swagger {:produces (displace (m/encodes muuntaja))
:consumes (displace (m/decodes muuntaja))}}}) :consumes (displace (m/decodes muuntaja))}}})
{:wrap #(muuntaja.middleware/wrap-format % muuntaja)})))}) {:wrap #(muuntaja.middleware/wrap-format % muuntaja)})))})
(def format-negotiate-middleware (def format-negotiate-middleware
"Middleware for content-negotiation. "Middleware for content-negotiation.
@ -71,9 +71,9 @@
:compile (fn [{:keys [muuntaja parameters]} _] :compile (fn [{:keys [muuntaja parameters]} _]
(if muuntaja (if muuntaja
(merge (merge
(when (publish-swagger-data? parameters) (when (publish-swagger-data? parameters)
{:data {:swagger {:consumes (displace (m/decodes muuntaja))}}}) {:data {:swagger {:consumes (displace (m/decodes muuntaja))}}})
{:wrap #(muuntaja.middleware/wrap-format-request % muuntaja)})))}) {:wrap #(muuntaja.middleware/wrap-format-request % muuntaja)})))})
(def format-response-middleware (def format-response-middleware
"Middleware for response formatting. "Middleware for response formatting.
@ -91,6 +91,6 @@
:compile (fn [{:keys [muuntaja parameters]} _] :compile (fn [{:keys [muuntaja parameters]} _]
(if muuntaja (if muuntaja
(merge (merge
(when (publish-swagger-data? parameters) (when (publish-swagger-data? parameters)
{:data {:swagger {:produces (displace (m/encodes muuntaja))}}}) {:data {:swagger {:produces (displace (m/encodes muuntaja))}}})
{:wrap #(muuntaja.middleware/wrap-format-response % muuntaja)})))}) {:wrap #(muuntaja.middleware/wrap-format-response % muuntaja)})))})

View file

@ -36,9 +36,9 @@
interceptor interceptor
(->> (select-keys interceptor [:enter :leave :error]) (vals) (keep identity) (seq)) (->> (select-keys interceptor [:enter :leave :error]) (vals) (keep identity) (seq))
(interceptor/interceptor (interceptor/interceptor
(if (error-without-arity-2? interceptor) (if (error-without-arity-2? interceptor)
(wrap-error-arity-2->1 interceptor) (wrap-error-arity-2->1 interceptor)
interceptor)))) interceptor))))
;; ;;
;; Public API ;; Public API
@ -62,11 +62,11 @@
(routing-interceptor router default-handler nil)) (routing-interceptor router default-handler nil))
([router default-handler {:keys [interceptors]}] ([router default-handler {:keys [interceptors]}]
(interceptor/interceptor (interceptor/interceptor
(reitit.http/routing-interceptor (reitit.http/routing-interceptor
router router
default-handler default-handler
{:executor pedestal-executor {:executor pedestal-executor
:interceptors interceptors})))) :interceptors interceptors}))))
(defn replace-last-interceptor [service-map interceptor] (defn replace-last-interceptor [service-map interceptor]
(-> service-map (-> service-map

View file

@ -17,23 +17,23 @@
(defn ^:no-wiki group-keys [data] (defn ^:no-wiki group-keys [data]
(reduce-kv (reduce-kv
(fn [[top childs] k v] (fn [[top childs] k v]
(if (http-methods k) (if (http-methods k)
[top (assoc childs k v)] [top (assoc childs k v)]
[(assoc top k v) childs])) [{} {}] data)) [(assoc top k v) childs])) [{} {}] data))
(defn coerce-handler [[path data] {:keys [expand] :as opts}] (defn coerce-handler [[path data] {:keys [expand] :as opts}]
[path (reduce [path (reduce
(fn [acc method] (fn [acc method]
(if (contains? acc method) (if (contains? acc method)
(update acc method expand opts) (update acc method expand opts)
acc)) data http-methods)]) acc)) data http-methods)])
(defn compile-result [[path data] {:keys [::default-options-endpoint expand] :as opts}] (defn compile-result [[path data] {:keys [::default-options-endpoint expand] :as opts}]
(let [[top childs] (group-keys data) (let [[top childs] (group-keys data)
childs (cond-> childs childs (cond-> childs
(and (not (:options childs)) (not (:handler top)) default-options-endpoint) (and (not (:options childs)) (not (:handler top)) default-options-endpoint)
(assoc :options (expand default-options-endpoint opts))) (assoc :options (expand default-options-endpoint opts)))
->endpoint (fn [p d m s] ->endpoint (fn [p d m s]
(-> (middleware/compile-result [p d] opts s) (-> (middleware/compile-result [p d] opts s)
(map->Endpoint) (map->Endpoint)
@ -41,19 +41,19 @@
(assoc :method m))) (assoc :method m)))
->methods (fn [any? data] ->methods (fn [any? data]
(reduce (reduce
(fn [acc method] (fn [acc method]
(cond-> acc (cond-> acc
any? (assoc method (->endpoint path data method nil)))) any? (assoc method (->endpoint path data method nil))))
(map->Methods {}) (map->Methods {})
http-methods))] http-methods))]
(if-not (seq childs) (if-not (seq childs)
(->methods true top) (->methods true top)
(reduce-kv (reduce-kv
(fn [acc method data] (fn [acc method data]
(let [data (meta-merge top data)] (let [data (meta-merge top data)]
(assoc acc method (->endpoint path data method method)))) (assoc acc method (->endpoint path data method method))))
(->methods (:handler top) data) (->methods (:handler top) data)
childs)))) childs))))
(def default-options-handler (def default-options-handler
(let [handle (fn [request] (let [handle (fn [request]
@ -318,26 +318,26 @@
enrich-default-request (create-enrich-default-request inject-router?)] enrich-default-request (create-enrich-default-request inject-router?)]
(with-meta (with-meta
(wrap (wrap
(fn (fn
([request] ([request]
(if-let [match (r/match-by-path router (:uri request))] (if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request) (let [method (:request-method request)
path-params (:path-params match) path-params (:path-params match)
result (:result match) result (:result match)
handler (-> result method :handler (or default-handler)) handler (-> result method :handler (or default-handler))
request (enrich-request request path-params match router)] request (enrich-request request path-params match router)]
(or (handler request) (default-handler request))) (or (handler request) (default-handler request)))
(default-handler (enrich-default-request request router)))) (default-handler (enrich-default-request request router))))
([request respond raise] ([request respond raise]
(if-let [match (r/match-by-path router (:uri request))] (if-let [match (r/match-by-path router (:uri request))]
(let [method (:request-method request) (let [method (:request-method request)
path-params (:path-params match) path-params (:path-params match)
result (:result match) result (:result match)
handler (-> result method :handler (or default-handler)) handler (-> result method :handler (or default-handler))
request (enrich-request request path-params match router)] request (enrich-request request path-params match router)]
((routes handler default-handler) request respond raise)) ((routes handler default-handler) request respond raise))
(default-handler (enrich-default-request request router) respond raise)) (default-handler (enrich-default-request request router) respond raise))
nil))) nil)))
{::r/router router})))) {::r/router router}))))
(defn get-router [handler] (defn get-router [handler]

View file

@ -10,8 +10,8 @@
::coercion/response-coercion 500 ::coercion/response-coercion 500
nil)] nil)]
(respond (respond
{:status status {:status status
:body (coercion/encode-error data)}) :body (coercion/encode-error data)})
(raise e)))) (raise e))))
;; ;;

View file

@ -19,7 +19,6 @@
(s/def ::trace map?) (s/def ::trace map?)
(s/def ::patch map?) (s/def ::patch map?)
(s/def ::data (s/def ::data
(s/keys :opt-un [::rs/handler ::rs/name ::rs/no-doc ::middleware])) (s/keys :opt-un [::rs/handler ::rs/name ::rs/no-doc ::middleware]))
@ -30,9 +29,9 @@
(defn merge-specs [specs] (defn merge-specs [specs]
(when-let [non-specs (seq (remove #(or (s/spec? %) (s/get-spec %)) specs))] (when-let [non-specs (seq (remove #(or (s/spec? %) (s/get-spec %)) specs))]
(exception/fail! (exception/fail!
::invalid-specs ::invalid-specs
{:specs specs {:specs specs
:invalid non-specs})) :invalid non-specs}))
(s/merge-spec-impl (vec specs) (vec specs) nil)) (s/merge-spec-impl (vec specs) (vec specs) nil))
(defn validate-route-data [routes key wrap spec] (defn validate-route-data [routes key wrap spec]
@ -51,5 +50,5 @@
[routes {:keys [spec ::rs/wrap] :or {spec ::data, wrap identity}}] [routes {:keys [spec ::rs/wrap] :or {spec ::data, wrap identity}}]
(when-let [problems (validate-route-data routes :middleware wrap spec)] (when-let [problems (validate-route-data routes :middleware wrap spec)]
(exception/fail! (exception/fail!
::rs/invalid-route-data ::rs/invalid-route-data
{:problems problems}))) {:problems problems})))

View file

@ -23,16 +23,16 @@
(defn stringify [schema] (defn stringify [schema]
(walk/prewalk (walk/prewalk
(fn [x] (fn [x]
(cond (cond
#?@(:clj [(class? x) (.getName ^Class x)]) #?@(:clj [(class? x) (.getName ^Class x)])
(instance? schema.core.OptionalKey x) (pr-str (list 'opt (:k x))) (instance? schema.core.OptionalKey x) (pr-str (list 'opt (:k x)))
(instance? schema.core.RequiredKey x) (pr-str (list 'req (:k x))) (instance? schema.core.RequiredKey x) (pr-str (list 'req (:k x)))
(and (satisfies? s/Schema x) (record? x)) (try (pr-str (s/explain x)) (catch #?(:clj Exception :cljs js/Error) _ x)) (and (satisfies? s/Schema x) (record? x)) (try (pr-str (s/explain x)) (catch #?(:clj Exception :cljs js/Error) _ x))
(instance? schema.utils.ValidationError x) (str (su/validation-error-explain x)) (instance? schema.utils.ValidationError x) (str (su/validation-error-explain x))
(instance? schema.utils.NamedError x) (str (su/named-error-explain x)) (instance? schema.utils.NamedError x) (str (su/named-error-explain x))
:else x)) :else x))
schema)) schema))
(def default-options (def default-options
{:coerce-response? coerce-response? {:coerce-response? coerce-response?
@ -50,27 +50,27 @@
;; TODO: this looks identical to spec, refactor when schema is done. ;; TODO: this looks identical to spec, refactor when schema is done.
(case specification (case specification
:swagger (swagger/swagger-spec :swagger (swagger/swagger-spec
(merge (merge
(if parameters (if parameters
{::swagger/parameters {::swagger/parameters
(into (into
(empty parameters) (empty parameters)
(for [[k v] parameters] (for [[k v] parameters]
[k (coercion/-compile-model this v nil)]))}) [k (coercion/-compile-model this v nil)]))})
(if responses (if responses
{::swagger/responses {::swagger/responses
(into (into
(empty responses) (empty responses)
(for [[k response] responses] (for [[k response] responses]
[k (as-> response $ [k (as-> response $
(set/rename-keys $ {:body :schema}) (set/rename-keys $ {:body :schema})
(if (:schema $) (if (:schema $)
(update $ :schema #(coercion/-compile-model this % nil)) (update $ :schema #(coercion/-compile-model this % nil))
$))]))}))) $))]))})))
(throw (throw
(ex-info (ex-info
(str "Can't produce Schema apidocs for " specification) (str "Can't produce Schema apidocs for " specification)
{:type specification, :coercion :schema})))) {:type specification, :coercion :schema}))))
(-compile-model [_ model _] model) (-compile-model [_ model _] model)
(-open-model [_ schema] (st/open-schema schema)) (-open-model [_ schema] (st/open-schema schema))
(-encode-error [_ error] (-encode-error [_ error]
@ -88,8 +88,8 @@
coerced (coercer value)] coerced (coercer value)]
(if-let [error (su/error-val coerced)] (if-let [error (su/error-val coerced)]
(coercion/map->CoercionError (coercion/map->CoercionError
{:schema schema {:schema schema
:errors error}) :errors error})
coerced)) coerced))
value)))) value))))
(-response-coercer [this schema] (-response-coercer [this schema]

View file

@ -8,10 +8,10 @@
interceptor/Executor interceptor/Executor
(queue [_ interceptors] (queue [_ interceptors]
(queue/into-queue (queue/into-queue
(map (map
(fn [{::interceptor/keys [handler] :as interceptor}] (fn [{::interceptor/keys [handler] :as interceptor}]
(or handler interceptor)) (or handler interceptor))
interceptors))) interceptors)))
(execute [_ interceptors request] (execute [_ interceptors request]
(sieppari/execute interceptors request)) (sieppari/execute interceptors request))
(execute [_ interceptors request respond raise] (execute [_ interceptors request respond raise]

View file

@ -11,13 +11,13 @@
(def string-transformer (def string-transformer
(st/type-transformer (st/type-transformer
st/strip-extra-keys-transformer st/strip-extra-keys-transformer
st/string-transformer)) st/string-transformer))
(def json-transformer (def json-transformer
(st/type-transformer (st/type-transformer
st/strip-extra-keys-transformer st/strip-extra-keys-transformer
st/json-transformer)) st/json-transformer))
(def strip-extra-keys-transformer (def strip-extra-keys-transformer
st/strip-extra-keys-transformer) st/strip-extra-keys-transformer)
@ -88,27 +88,27 @@
(-get-apidocs [this specification {:keys [parameters responses]}] (-get-apidocs [this specification {:keys [parameters responses]}]
(case specification (case specification
:swagger (swagger/swagger-spec :swagger (swagger/swagger-spec
(merge (merge
(if parameters (if parameters
{::swagger/parameters {::swagger/parameters
(into (into
(empty parameters) (empty parameters)
(for [[k v] parameters] (for [[k v] parameters]
[k (coercion/-compile-model this v nil)]))}) [k (coercion/-compile-model this v nil)]))})
(if responses (if responses
{::swagger/responses {::swagger/responses
(into (into
(empty responses) (empty responses)
(for [[k response] responses] (for [[k response] responses]
[k (as-> response $ [k (as-> response $
(set/rename-keys $ {:body :schema}) (set/rename-keys $ {:body :schema})
(if (:schema $) (if (:schema $)
(update $ :schema #(coercion/-compile-model this % nil)) (update $ :schema #(coercion/-compile-model this % nil))
$))]))}))) $))]))})))
(throw (throw
(ex-info (ex-info
(str "Can't produce Spec apidocs for " specification) (str "Can't produce Spec apidocs for " specification)
{:specification specification, :coercion :spec})))) {:specification specification, :coercion :spec}))))
(-compile-model [_ model name] (-compile-model [_ model name]
(into-spec model name)) (into-spec model name))
(-open-model [_ spec] spec) (-open-model [_ spec] spec)
@ -129,8 +129,8 @@
(if (s/invalid? transformed) (if (s/invalid? transformed)
(let [problems (st/explain-data spec coerced transformer)] (let [problems (st/explain-data spec coerced transformer)]
(coercion/map->CoercionError (coercion/map->CoercionError
{:spec spec {:spec spec
:problems problems})) :problems problems}))
(s/unform spec transformed))))) (s/unform spec transformed)))))
value)))) value))))
(-response-coercer [this spec] (-response-coercer [this spec]

View file

@ -31,10 +31,10 @@
([options] ([options]
(let [config-json (fn [{:keys [url config]}] (j/write-value-as-string (merge config {:url url}))) (let [config-json (fn [{:keys [url config]}] (j/write-value-as-string (merge config {:url url})))
options (as-> options $ options (as-> options $
(update $ :root (fnil identity "swagger-ui")) (update $ :root (fnil identity "swagger-ui"))
(update $ :url (fnil identity "/swagger.json")) (update $ :url (fnil identity "/swagger.json"))
(assoc $ :paths {"/config.json" {:headers {"Content-Type" "application/json"} (assoc $ :paths {"/config.json" {:headers {"Content-Type" "application/json"}
:status 200 :status 200
:body (config-json $)}}))] :body (config-json $)}}))]
(ring/routes (ring/routes
(ring/create-resource-handler options)))))) (ring/create-resource-handler options))))))

View file

@ -88,13 +88,13 @@
(if (and data (not no-doc)) (if (and data (not no-doc))
[method [method
(meta-merge (meta-merge
base-swagger-spec base-swagger-spec
(apply meta-merge (keep (comp :swagger :data) middleware)) (apply meta-merge (keep (comp :swagger :data) middleware))
(apply meta-merge (keep (comp :swagger :data) interceptors)) (apply meta-merge (keep (comp :swagger :data) interceptors))
(if coercion (if coercion
(coercion/get-apidocs coercion :swagger data)) (coercion/get-apidocs coercion :swagger data))
(select-keys data [:tags :summary :description]) (select-keys data [:tags :summary :description])
(strip-top-level-keys swagger))])) (strip-top-level-keys swagger))]))
transform-path (fn [[p _ c]] transform-path (fn [[p _ c]]
(if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))] (if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))]
[(swagger-path p (r/options router)) endpoint])) [(swagger-path p (r/options router)) endpoint]))

View file

@ -11,11 +11,10 @@
wrap (if (pos? (count indent)) vector identity)] wrap (if (pos? (count indent)) vector identity)]
(wrap [name {:file (str "doc/" file)}]))) (wrap [name {:file (str "doc/" file)}])))
(reduce (reduce
(fn [acc data] (fn [acc data]
(if (vector? (first data)) (if (vector? (first data))
(update-in acc [(dec (count acc)) 2] (fnil into []) data) (update-in acc [(dec (count acc)) 2] (fnil into []) data)
(conj acc data)) (conj acc data))) [])
) [])
;; third sweep to flatten chids... ;; third sweep to flatten chids...
(mapv (fn [[n o c]] (if c (into [n o] c) [n o])))) (mapv (fn [[n o c]] (if c (into [n o] c) [n o]))))
data {:cljdoc/include-namespaces-from-dependencies ['metosin/reitit data {:cljdoc/include-namespaces-from-dependencies ['metosin/reitit

View file

@ -17,23 +17,23 @@
(create f nil)) (create f nil))
([f wrap] ([f wrap]
(http/ring-handler (http/ring-handler
(http/router (http/router
[["/defaults" [["/defaults"
{:handler f}] {:handler f}]
["/coercion" ["/coercion"
{:interceptors [(reitit.http.coercion/coerce-request-interceptor) {:interceptors [(reitit.http.coercion/coerce-request-interceptor)
(reitit.http.coercion/coerce-response-interceptor)] (reitit.http.coercion/coerce-response-interceptor)]
:coercion reitit.coercion.spec/coercion :coercion reitit.coercion.spec/coercion
:parameters {:query {:x int?, :y int?}} :parameters {:query {:x int?, :y int?}}
:responses {200 {:body {:total pos-int?}}} :responses {200 {:body {:total pos-int?}}}
:handler f}]] :handler f}]]
{:data {:interceptors [(exception/exception-interceptor {:data {:interceptors [(exception/exception-interceptor
(merge (merge
exception/default-handlers exception/default-handlers
{::kikka (constantly {:status 400, :body "kikka"}) {::kikka (constantly {:status 400, :body "kikka"})
SQLException (constantly {:status 400, :body "sql"}) SQLException (constantly {:status 400, :body "sql"})
::exception/wrap wrap}))]}}) ::exception/wrap wrap}))]}})
{:executor sieppari/executor})))] {:executor sieppari/executor})))]
(testing "normal calls work ok" (testing "normal calls work ok"
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}

View file

@ -9,11 +9,11 @@
(deftest muuntaja-test (deftest muuntaja-test
(let [data {:kikka "kukka"} (let [data {:kikka "kukka"}
app (http/ring-handler app (http/ring-handler
(http/router (http/router
["/ping" {:get (constantly {:status 200, :body data})}] ["/ping" {:get (constantly {:status 200, :body data})}]
{:data {:muuntaja m/instance {:data {:muuntaja m/instance
:interceptors [(muuntaja/format-interceptor)]}}) :interceptors [(muuntaja/format-interceptor)]}})
{:executor sieppari/executor})] {:executor sieppari/executor})]
(is (= data (->> {:request-method :get, :uri "/ping"} (is (= data (->> {:request-method :get, :uri "/ping"}
(app) (app)
:body :body
@ -24,27 +24,27 @@
no-edn-decode (m/create (-> m/default-options (update-in [:formats "application/edn"] dissoc :decoder))) no-edn-decode (m/create (-> m/default-options (update-in [:formats "application/edn"] dissoc :decoder)))
just-edn (m/create (-> m/default-options (m/select-formats ["application/edn"]))) just-edn (m/create (-> m/default-options (m/select-formats ["application/edn"])))
app (http/ring-handler app (http/ring-handler
(http/router (http/router
[["/defaults" [["/defaults"
{:get identity}] {:get identity}]
["/explicit-defaults" ["/explicit-defaults"
{:muuntaja with-defaults {:muuntaja with-defaults
:get identity}] :get identity}]
["/no-edn-decode" ["/no-edn-decode"
{:muuntaja no-edn-decode {:muuntaja no-edn-decode
:get identity}] :get identity}]
["/just-edn" ["/just-edn"
{:muuntaja just-edn {:muuntaja just-edn
:get identity}] :get identity}]
["/form-params" ["/form-params"
{:post {:parameters {:form {:x string?}} {:post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]]
{:data {:muuntaja m/instance {:data {:muuntaja m/instance
:interceptors [(muuntaja/format-interceptor)]}}) :interceptors [(muuntaja/format-interceptor)]}})
{:executor sieppari/executor}) {:executor sieppari/executor})
spec (fn [method path] spec (fn [method path]
(let [path (keyword path)] (let [path (keyword path)]
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
@ -99,42 +99,42 @@
(deftest muuntaja-swagger-parts-test (deftest muuntaja-swagger-parts-test
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
[["/request" [["/request"
{:interceptors [(muuntaja/format-negotiate-interceptor) {:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-request-interceptor)]
:get identity}]
["/response"
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)]
:get identity}]
["/both"
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)
(muuntaja/format-request-interceptor)]
:get identity}]
["/form-request"
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-request-interceptor)] (muuntaja/format-request-interceptor)]
:post {:parameters {:form {:x string?}} :get identity}]
:handler identity}}] ["/response"
["/form-response" {:interceptors [(muuntaja/format-negotiate-interceptor)
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)] (muuntaja/format-response-interceptor)]
:post {:parameters {:form {:x string?}} :get identity}]
:handler identity}}] ["/both"
["/form-with-both" {:interceptors [(muuntaja/format-negotiate-interceptor)
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor) (muuntaja/format-response-interceptor)
(muuntaja/format-request-interceptor)] (muuntaja/format-request-interceptor)]
:post {:parameters {:form {:x string?}} :get identity}]
:handler identity}}] ["/form-request"
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-request-interceptor)]
:post {:parameters {:form {:x string?}}
:handler identity}}]
["/form-response"
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)]
:post {:parameters {:form {:x string?}}
:handler identity}}]
["/form-with-both"
{:interceptors [(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)
(muuntaja/format-request-interceptor)]
:post {:parameters {:form {:x string?}}
:handler identity}}]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]]
{:data {:muuntaja m/instance}}) {:data {:muuntaja m/instance}})
{:executor sieppari/executor}) {:executor sieppari/executor})
spec (fn [method path] spec (fn [method path]
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
(app) :body :paths (get path) method)) (app) :body :paths (get path) method))

View file

@ -7,10 +7,10 @@
(deftest parameters-test (deftest parameters-test
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
["/ping" {:get #(select-keys % [:params :query-params])}] ["/ping" {:get #(select-keys % [:params :query-params])}]
{:data {:interceptors [(parameters/parameters-interceptor)]}}) {:data {:interceptors [(parameters/parameters-interceptor)]}})
{:executor sieppari/executor})] {:executor sieppari/executor})]
(is (= {:query-params {"kikka" "kukka"} (is (= {:query-params {"kikka" "kukka"}
:params {"kikka" "kukka"}} :params {"kikka" "kukka"}}
(app {:request-method :get (app {:request-method :get
@ -19,15 +19,15 @@
(deftest parameters-swagger-test (deftest parameters-swagger-test
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
[["/form-params" {:post {:parameters {:form {:x string?}} [["/form-params" {:post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/body-params" {:post {:parameters {:body {:x string?}} ["/body-params" {:post {:parameters {:body {:x string?}}
:handler identity}}] :handler identity}}]
["/swagger.json" {:get {:no-doc true ["/swagger.json" {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]]
{:data {:interceptors [(parameters/parameters-interceptor)]}}) {:data {:interceptors [(parameters/parameters-interceptor)]}})
 {:executor sieppari/executor}) {:executor sieppari/executor})
spec (fn [path] spec (fn [path]
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
app app

View file

@ -74,20 +74,20 @@
(deftest spec-coercion-test (deftest spec-coercion-test
(let [create (fn [interceptors] (let [create (fn [interceptors]
(http/ring-handler (http/ring-handler
(http/router (http/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:parameters {:query {:a int?} {:get {:parameters {:query {:a int?}
:body {:b int?} :body {:b int?}
:form {:c int?} :form {:c int?}
:header {:d int?} :header {:d int?}
:path {:e int?}} :path {:e int?}}
:responses {200 {:body {:total pos-int?}} :responses {200 {:body {:total pos-int?}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler handler}}]] :handler handler}}]]
{:data {:interceptors interceptors {:data {:interceptors interceptors
:coercion spec/coercion}}) :coercion spec/coercion}})
{:executor sieppari/executor}))] {:executor sieppari/executor}))]
(testing "without exception handling" (testing "without exception handling"
(let [app (create [(rrc/coerce-request-interceptor) (let [app (create [(rrc/coerce-request-interceptor)
@ -103,15 +103,15 @@
(testing "invalid request" (testing "invalid request"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app invalid-request1)))) (app invalid-request1))))
(testing "invalid response" (testing "invalid response"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Response coercion failed" #"Response coercion failed"
(app invalid-request2)))))) (app invalid-request2))))))
(testing "with exception handling" (testing "with exception handling"
(let [app (create [(rrc/coerce-exceptions-interceptor) (let [app (create [(rrc/coerce-exceptions-interceptor)
@ -134,20 +134,20 @@
(deftest schema-coercion-test (deftest schema-coercion-test
(let [create (fn [middleware] (let [create (fn [middleware]
(http/ring-handler (http/ring-handler
(http/router (http/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:parameters {:query {:a s/Int} {:get {:parameters {:query {:a s/Int}
:body {:b s/Int} :body {:b s/Int}
:form {:c s/Int} :form {:c s/Int}
:header {:d s/Int} :header {:d s/Int}
:path {:e s/Int}} :path {:e s/Int}}
:responses {200 {:body {:total (s/constrained s/Int pos? 'positive)}} :responses {200 {:body {:total (s/constrained s/Int pos? 'positive)}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler handler}}]] :handler handler}}]]
{:data {:interceptors middleware {:data {:interceptors middleware
:coercion schema/coercion}}) :coercion schema/coercion}})
{:executor sieppari/executor}))] {:executor sieppari/executor}))]
(testing "without exception handling" (testing "without exception handling"
(let [app (create [(rrc/coerce-request-interceptor) (let [app (create [(rrc/coerce-request-interceptor)
@ -163,15 +163,15 @@
(testing "invalid request" (testing "invalid request"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app invalid-request1)))) (app invalid-request1))))
(testing "invalid response" (testing "invalid response"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Response coercion failed" #"Response coercion failed"
(app invalid-request2)))) (app invalid-request2))))
(testing "with exception handling" (testing "with exception handling"
(let [app (create [(rrc/coerce-exceptions-interceptor) (let [app (create [(rrc/coerce-exceptions-interceptor)
@ -194,51 +194,51 @@
(deftest malli-coercion-test (deftest malli-coercion-test
(let [create (fn [interceptors] (let [create (fn [interceptors]
(http/ring-handler (http/ring-handler
(http/router (http/router
["/api" ["/api"
["/validate" {:summary "just validation" ["/validate" {:summary "just validation"
:coercion (reitit.coercion.malli/create {:transformers {}}) :coercion (reitit.coercion.malli/create {:transformers {}})
:post {:parameters {:body [:map [:x int?]]} :post {:parameters {:body [:map [:x int?]]}
:responses {200 {:body [:map [:x int?]]}} :responses {200 {:body [:map [:x int?]]}}
:handler (fn [req] :handler (fn [req]
{:status 200 {:status 200
:body (-> req :parameters :body)})}}] :body (-> req :parameters :body)})}}]
["/no-op" {:summary "no-operation" ["/no-op" {:summary "no-operation"
:coercion (reitit.coercion.malli/create {:transformers {}, :validate false}) :coercion (reitit.coercion.malli/create {:transformers {}, :validate false})
:post {:parameters {:body [:map [:x int?]]} :post {:parameters {:body [:map [:x int?]]}
:responses {200 {:body [:map [:x int?]]}} :responses {200 {:body [:map [:x int?]]}}
:handler (fn [req] :handler (fn [req]
{:status 200 {:status 200
:body (-> req :parameters :body)})}}] :body (-> req :parameters :body)})}}]
["/skip" {:summary "skip" ["/skip" {:summary "skip"
:coercion (reitit.coercion.malli/create {:enabled false}) :coercion (reitit.coercion.malli/create {:enabled false})
:post {:parameters {:body [:map [:x int?]]} :post {:parameters {:body [:map [:x int?]]}
:responses {200 {:body [:map [:x int?]]}} :responses {200 {:body [:map [:x int?]]}}
:handler (fn [req] :handler (fn [req]
{:status 200
:body (-> req :parameters :body)})}}]
["/or" {:post {:summary "accepts either of two map schemas"
:parameters {:body [:or [:map [:x int?]] [:map [:y int?]]]}
:responses {200 {:body [:map [:msg string?]]}}
:handler (fn [{{{:keys [x]} :body} :parameters}]
{:status 200 {:status 200
:body {:msg (if x "you sent x" "you sent y")}})}}] :body (-> req :parameters :body)})}}]
["/plus/:e" {:get {:parameters {:query [:map [:a {:optional true} int?]] ["/or" {:post {:summary "accepts either of two map schemas"
:body [:map [:b int?]] :parameters {:body [:or [:map [:x int?]] [:map [:y int?]]]}
:form [:map [:c [int? {:default 3}]]] :responses {200 {:body [:map [:msg string?]]}}
:header [:map [:d int?]] :handler (fn [{{{:keys [x]} :body} :parameters}]
:path [:map [:e int?]]} {:status 200
:responses {200 {:body [:map [:total pos-int?]]} :body {:msg (if x "you sent x" "you sent y")}})}}]
500 {:description "fail"}}
:handler handler}}]] ["/plus/:e" {:get {:parameters {:query [:map [:a {:optional true} int?]]
{:data {:interceptors interceptors :body [:map [:b int?]]
:coercion malli/coercion}}) :form [:map [:c [int? {:default 3}]]]
{:executor sieppari/executor}))] :header [:map [:d int?]]
:path [:map [:e int?]]}
:responses {200 {:body [:map [:total pos-int?]]}
500 {:description "fail"}}
:handler handler}}]]
{:data {:interceptors interceptors
:coercion malli/coercion}})
{:executor sieppari/executor}))]
(testing "withut exception handling" (testing "withut exception handling"
(let [app (create [(rrc/coerce-request-interceptor) (let [app (create [(rrc/coerce-request-interceptor)
@ -249,8 +249,8 @@
:body {:total 15}} :body {:total 15}}
(app valid-request1))) (app valid-request1)))
#_(is (= {:status 200 #_(is (= {:status 200
:body {:total 115}} :body {:total 115}}
(app valid-request2))) (app valid-request2)))
(is (= {:status 200 (is (= {:status 200
:body {:total 15}} :body {:total 15}}
(app valid-request3))) (app valid-request3)))
@ -264,15 +264,15 @@
(testing "invalid request" (testing "invalid request"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app invalid-request1)))) (app invalid-request1))))
(testing "invalid response" (testing "invalid response"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Response coercion failed" #"Response coercion failed"
(app invalid-request2)))))) (app invalid-request2))))))
(testing "with exception handling" (testing "with exception handling"
(let [app (create [(rrc/coerce-exceptions-interceptor) (let [app (create [(rrc/coerce-exceptions-interceptor)
@ -339,16 +339,16 @@
{:status 200, :body (assoc body :response true)})}}) {:status 200, :body (assoc body :response true)})}})
->app (fn [options] ->app (fn [options]
(http/ring-handler (http/ring-handler
(http/router (http/router
["/api" ["/api"
["/default" (endpoint [:map [:x int?]])] ["/default" (endpoint [:map [:x int?]])]
["/closed" (endpoint [:map {:closed true} [:x int?]])] ["/closed" (endpoint [:map {:closed true} [:x int?]])]
["/open" (endpoint [:map {:closed false} [:x int?]])]] ["/open" (endpoint [:map {:closed false} [:x int?]])]]
{:data {:interceptors [(rrc/coerce-exceptions-interceptor) {:data {:interceptors [(rrc/coerce-exceptions-interceptor)
(rrc/coerce-request-interceptor) (rrc/coerce-request-interceptor)
(rrc/coerce-response-interceptor)] (rrc/coerce-response-interceptor)]
:coercion (malli/create options)}}) :coercion (malli/create options)}})
{:executor sieppari/executor})) {:executor sieppari/executor}))
->request (fn [uri] {:uri (str "/api/" uri) ->request (fn [uri] {:uri (str "/api/" uri)
:request-method :get :request-method :get
:muuntaja/request {:format "application/json"} :muuntaja/request {:format "application/json"}
@ -399,23 +399,23 @@
(testing "sequence schemas" (testing "sequence schemas"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
["/ping" {:get {:parameters {:body [:vector [:map [:message string?]]]} ["/ping" {:get {:parameters {:body [:vector [:map [:message string?]]]}
:responses {200 {:body [:vector [:map [:pong string?]]]} :responses {200 {:body [:vector [:map [:pong string?]]]}
501 {:body [:vector [:map [:error string?]]]}} 501 {:body [:vector [:map [:error string?]]]}}
:handler (fn [{{[{:keys [message]}] :body} :parameters :as req}] :handler (fn [{{[{:keys [message]}] :body} :parameters :as req}]
(condp = message (condp = message
"ping" {:status 200 "ping" {:status 200
:body [{:pong message}]} :body [{:pong message}]}
"fail" {:status 501 "fail" {:status 501
:body [{:error "fail"}]} :body [{:error "fail"}]}
{:status 200 {:status 200
:body {:invalid "response"}}))}}] :body {:invalid "response"}}))}}]
{:data {:interceptors [(rrc/coerce-exceptions-interceptor) {:data {:interceptors [(rrc/coerce-exceptions-interceptor)
(rrc/coerce-request-interceptor) (rrc/coerce-request-interceptor)
(rrc/coerce-response-interceptor)] (rrc/coerce-response-interceptor)]
:coercion malli/coercion}}) :coercion malli/coercion}})
{:executor sieppari/executor}) {:executor sieppari/executor})
->request (fn [body] ->request (fn [body]
{:uri "/ping" {:uri "/ping"
:request-method :get :request-method :get
@ -439,19 +439,19 @@
(deftest muuntaja-test (deftest muuntaja-test
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
["/api" ["/api"
["/plus" ["/plus"
{:post {:parameters {:body {:int int?, :keyword keyword?}} {:post {:parameters {:body {:int int?, :keyword keyword?}}
:responses {200 {:body {:int int?, :keyword keyword?}}} :responses {200 {:body {:int int?, :keyword keyword?}}}
:handler (fn [{{:keys [body]} :parameters}] :handler (fn [{{:keys [body]} :parameters}]
{:status 200 {:status 200
:body body})}}]] :body body})}}]]
{:data {:interceptors [(muuntaja.interceptor/format-interceptor) {:data {:interceptors [(muuntaja.interceptor/format-interceptor)
(rrc/coerce-response-interceptor) (rrc/coerce-response-interceptor)
(rrc/coerce-request-interceptor)] (rrc/coerce-request-interceptor)]
:coercion spec/coercion}}) :coercion spec/coercion}})
{:executor sieppari/executor}) {:executor sieppari/executor})
request (fn [content-type body] request (fn [content-type body]
(-> {:request-method :post (-> {:request-method :post
:headers {"content-type" content-type, "accept" content-type} :headers {"content-type" content-type, "accept" content-type}

View file

@ -21,14 +21,14 @@
(testing "http-handler" (testing "http-handler"
(let [api-interceptor (interceptor :api) (let [api-interceptor (interceptor :api)
router (http/router router (http/router
["/api" {:interceptors [api-interceptor]} ["/api" {:interceptors [api-interceptor]}
["/all" handler] ["/all" handler]
["/get" {:get handler}] ["/get" {:get handler}]
["/users" {:interceptors [[interceptor :users]] ["/users" {:interceptors [[interceptor :users]]
:get handler :get handler
:post {:handler handler :post {:handler handler
:interceptors [[interceptor :post]]} :interceptors [[interceptor :post]]}
:handler handler}]]) :handler handler}]])
app (http/ring-handler router nil {:executor sieppari/executor})] app (http/ring-handler router nil {:executor sieppari/executor})]
(testing "router can be extracted" (testing "router can be extracted"
@ -68,14 +68,14 @@
(testing "named routes" (testing "named routes"
(let [router (http/router (let [router (http/router
[["/api" [["/api"
["/all" {:handler handler :name ::all}] ["/all" {:handler handler :name ::all}]
["/get" {:get {:handler handler :name ::HIDDEN} ["/get" {:get {:handler handler :name ::HIDDEN}
:name ::get}] :name ::get}]
["/users" {:get handler ["/users" {:get handler
:post handler :post handler
:handler handler :handler handler
:name ::users}]]]) :name ::users}]]])
app (http/ring-handler router nil {:executor sieppari/executor})] app (http/ring-handler router nil {:executor sieppari/executor})]
(testing "router can be extracted" (testing "router can be extracted"
@ -102,13 +102,13 @@
(deftest enforcing-data-rules-at-runtime-test (deftest enforcing-data-rules-at-runtime-test
(let [handler (constantly {:status 200, :body "ok"}) (let [handler (constantly {:status 200, :body "ok"})
app (http/ring-handler app (http/ring-handler
(http/router (http/router
[["/api" [["/api"
["/ping" handler] ["/ping" handler]
["/admin" {::roles #{:admin}} ["/admin" {::roles #{:admin}}
["/ping" handler]]]] ["/ping" handler]]]]
{:data {:interceptors [enforce-roles-interceptor]}}) {:data {:interceptors [enforce-roles-interceptor]}})
nil {:executor sieppari/executor})] nil {:executor sieppari/executor})]
(testing "public handler" (testing "public handler"
(is (= {:status 200, :body "ok"} (is (= {:status 200, :body "ok"}
@ -128,8 +128,8 @@
(deftest default-handler-test (deftest default-handler-test
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}
router (http/router router (http/router
[["/ping" {:get (constantly response)}] [["/ping" {:get (constantly response)}]
["/pong" (constantly nil)]]) ["/pong" (constantly nil)]])
app (http/ring-handler router nil {:executor sieppari/executor})] app (http/ring-handler router nil {:executor sieppari/executor})]
(testing "match" (testing "match"
@ -146,9 +146,9 @@
(testing "with default http responses" (testing "with default http responses"
(let [app (http/ring-handler (let [app (http/ring-handler
router router
(ring/create-default-handler) (ring/create-default-handler)
{:executor sieppari/executor})] {:executor sieppari/executor})]
(testing "route doesn't match yields 404" (testing "route doesn't match yields 404"
(is (= 404 (:status (app {:request-method :get, :uri "/"}))))) (is (= 404 (:status (app {:request-method :get, :uri "/"})))))
(testing "method doesn't match yields 405" (testing "method doesn't match yields 405"
@ -158,12 +158,12 @@
(testing "with custom http responses" (testing "with custom http responses"
(let [app (http/ring-handler (let [app (http/ring-handler
router router
(ring/create-default-handler (ring/create-default-handler
{:not-found (constantly {:status -404}) {:not-found (constantly {:status -404})
:method-not-allowed (constantly {:status -405}) :method-not-allowed (constantly {:status -405})
:not-acceptable (constantly {:status -406})}) :not-acceptable (constantly {:status -406})})
{:executor sieppari/executor})] {:executor sieppari/executor})]
(testing "route doesn't match" (testing "route doesn't match"
(is (= -404 (:status (app {:request-method :get, :uri "/"}))))) (is (= -404 (:status (app {:request-method :get, :uri "/"})))))
(testing "method doesn't match" (testing "method doesn't match"
@ -180,12 +180,12 @@
(testing "with defaults" (testing "with defaults"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
[["/get" {:get (constantly response) [["/get" {:get (constantly response)
:post (constantly response)}] :post (constantly response)}]
["/options" {:options (constantly response)}] ["/options" {:options (constantly response)}]
["/any" (constantly response)]]) ["/any" (constantly response)]])
{:executor sieppari/executor})] {:executor sieppari/executor})]
(testing "endpoint with a non-options handler" (testing "endpoint with a non-options handler"
(is (= response (app {:request-method :get, :uri "/get"}))) (is (= response (app {:request-method :get, :uri "/get"})))
@ -201,12 +201,12 @@
(testing "disabled via options" (testing "disabled via options"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
[["/get" {:get (constantly response)}] [["/get" {:get (constantly response)}]
["/options" {:options (constantly response)}] ["/options" {:options (constantly response)}]
["/any" (constantly response)]] ["/any" (constantly response)]]
{::http/default-options-endpoint nil}) {::http/default-options-endpoint nil})
{:executor sieppari/executor})] {:executor sieppari/executor})]
(testing "endpoint with a non-options handler" (testing "endpoint with a non-options handler"
(is (= response (app {:request-method :get, :uri "/get"}))) (is (= response (app {:request-method :get, :uri "/get"})))
@ -227,8 +227,8 @@
(reset! value x)))) (reset! value x))))
response {:status 200, :body "ok"} response {:status 200, :body "ok"}
router (http/router router (http/router
[["/ping" {:get (fn [_] response)}] [["/ping" {:get (fn [_] response)}]
["/pong" (fn [_] nil)]]) ["/pong" (fn [_] nil)]])
app (http/ring-handler router nil {:executor sieppari/executor})] app (http/ring-handler router nil {:executor sieppari/executor})]
(testing "match" (testing "match"
@ -287,11 +287,11 @@
(require '[sieppari.async.core-async]) (require '[sieppari.async.core-async])
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}
app (http/ring-handler app (http/ring-handler
(http/router (http/router
["/ping" {:get {:interceptors [{:enter #(a/go %)}] ["/ping" {:get {:interceptors [{:enter #(a/go %)}]
:handler (fn [_] (a/go response))}}]) :handler (fn [_] (a/go response))}}])
(ring/create-default-handler) (ring/create-default-handler)
{:executor sieppari/executor})] {:executor sieppari/executor})]
(let [respond (promise)] (let [respond (promise)]
(app {:request-method :get, :uri "/ping"} respond ::irrelevant) (app {:request-method :get, :uri "/ping"} respond ::irrelevant)
(is (= response (deref respond 100 ::timeout))))))) (is (= response (deref respond 100 ::timeout)))))))
@ -302,11 +302,11 @@
(testing "works if registered" (testing "works if registered"
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}
app (http/ring-handler app (http/ring-handler
(http/router (http/router
["/ping" {:get {:interceptors [{:enter map->MyAsyncContext}] ["/ping" {:get {:interceptors [{:enter map->MyAsyncContext}]
:handler (fn [_] response)}}]) :handler (fn [_] response)}}])
(ring/create-default-handler) (ring/create-default-handler)
{:executor sieppari/executor}) {:executor sieppari/executor})
respond (promise) respond (promise)
raise (promise)] raise (promise)]
(app {:request-method :get, :uri "/ping"} respond raise) (app {:request-method :get, :uri "/ping"} respond raise)
@ -321,14 +321,14 @@
request {:uri "/api/avaruus" :request-method :get} request {:uri "/api/avaruus" :request-method :get}
create (fn [options] create (fn [options]
(http/ring-handler (http/ring-handler
(http/router (http/router
["/api" {:interceptors [(interceptor :olipa)]} ["/api" {:interceptors [(interceptor :olipa)]}
["/avaruus" {:interceptors [(interceptor :kerran)] ["/avaruus" {:interceptors [(interceptor :kerran)]
:get {:handler handler :get {:handler handler
:interceptors [(interceptor :avaruus)]}}]] :interceptors [(interceptor :avaruus)]}}]]
options) options)
nil nil
{:executor sieppari/executor}))] {:executor sieppari/executor}))]
(testing "by default, all middleware are applied in order" (testing "by default, all middleware are applied in order"
(let [app (create nil)] (let [app (create nil)]
@ -352,10 +352,10 @@
(testing "from root" (testing "from root"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
["/*" (ring/create-resource-handler)]) ["/*" (ring/create-resource-handler)])
(ring/create-default-handler) (ring/create-default-handler)
{:executor sieppari/executor})] {:executor sieppari/executor})]
(testing test (testing test
(testing "different file-types" (testing "different file-types"
(let [response (app (request "/hello.json"))] (let [response (app (request "/hello.json"))]
@ -388,10 +388,10 @@
(testing "from path" (testing "from path"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router (http/router
["/files/*" (ring/create-resource-handler)]) ["/files/*" (ring/create-resource-handler)])
(ring/create-default-handler) (ring/create-default-handler)
{:executor sieppari/executor}) {:executor sieppari/executor})
request #(request (str "/files" %)) request #(request (str "/files" %))
redirect #(redirect (str "/files" %))] redirect #(redirect (str "/files" %))]
(testing test (testing test
@ -428,11 +428,11 @@
(testing "from root" (testing "from root"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router []) (http/router [])
(ring/routes (ring/routes
(ring/create-resource-handler {:path "/"}) (ring/create-resource-handler {:path "/"})
(ring/create-default-handler)) (ring/create-default-handler))
{:executor sieppari/executor})] {:executor sieppari/executor})]
(testing test (testing test
(testing "different file-types" (testing "different file-types"
(let [response (app (request "/hello.json"))] (let [response (app (request "/hello.json"))]
@ -465,11 +465,11 @@
(testing "from path" (testing "from path"
(let [app (http/ring-handler (let [app (http/ring-handler
(http/router []) (http/router [])
(ring/routes (ring/routes
(ring/create-resource-handler {:path "/files"}) (ring/create-resource-handler {:path "/files"})
(ring/create-default-handler)) (ring/create-default-handler))
{:executor sieppari/executor}) {:executor sieppari/executor})
request #(request (str "/files" %)) request #(request (str "/files" %))
redirect #(redirect (str "/files" %))] redirect #(redirect (str "/files" %))]
(testing test (testing test
@ -510,18 +510,18 @@
interceptor (fn [x] {:enter (fn [ctx] (swap! times update-in [:enter x] (fnil inc 0)) ctx) interceptor (fn [x] {:enter (fn [ctx] (swap! times update-in [:enter x] (fnil inc 0)) ctx)
:leave (fn [ctx] (swap! times update-in [:leave x] (fnil inc 0)) ctx)}) :leave (fn [ctx] (swap! times update-in [:leave x] (fnil inc 0)) ctx)})
app (http/ring-handler app (http/ring-handler
(http/router (http/router
["/api" ["/api"
{:interceptors [(interceptor :api)]} {:interceptors [(interceptor :api)]}
["/ping" ["/ping"
{:interceptors [(interceptor :ping)] {:interceptors [(interceptor :ping)]
:get {:interceptors [(interceptor :get)] :get {:interceptors [(interceptor :get)]
:handler (fn [_] response)}}]]) :handler (fn [_] response)}}]])
(ring/routes (ring/routes
(ring/create-default-handler) (ring/create-default-handler)
{:data {:interceptors [(interceptor :router)]}}) {:data {:interceptors [(interceptor :router)]}})
{:executor sieppari/executor {:executor sieppari/executor
:interceptors [(interceptor :top)]})] :interceptors [(interceptor :top)]})]
(is (= response (app {:request-method :get, :uri "/api/ping"}))) (is (= response (app {:request-method :get, :uri "/api/ping"})))
(is (= {:enter {:top 1, :api 1, :ping 1, :get 1} (is (= {:enter {:top 1, :api 1, :ping 1, :get 1}
:leave {:get 1, :ping 1, :api 1, :top 1}} :leave {:get 1, :ping 1, :api 1, :top 1}}
@ -530,15 +530,15 @@
(deftest router-available-in-default-branch (deftest router-available-in-default-branch
(testing "1-arity" (testing "1-arity"
((http/ring-handler ((http/ring-handler
(http/router []) (http/router [])
(fn [{::r/keys [router]}] (fn [{::r/keys [router]}]
(is router)) (is router))
{:executor sieppari/executor}) {:executor sieppari/executor})
{})) {}))
(testing "3-arity" (testing "3-arity"
((http/ring-handler ((http/ring-handler
(http/router []) (http/router [])
(fn [{::r/keys [router]}] (fn [{::r/keys [router]}]
(is router)) (is router))
{:executor sieppari/executor}) {:executor sieppari/executor})
{} ::respond ::raise))) {} ::respond ::raise)))

View file

@ -28,11 +28,11 @@
(deftest pedestal-e2e-test (deftest pedestal-e2e-test
(let [router (pedestal/routing-interceptor (let [router (pedestal/routing-interceptor
(http/router (http/router
["" [""
{:interceptors [{:name :nop} (exception/exception-interceptor)]} {:interceptors [{:name :nop} (exception/exception-interceptor)]}
["/ok" (fn [_] {:status 200, :body "ok"})] ["/ok" (fn [_] {:status 200, :body "ok"})]
["/fail" (fn [_] (throw (ex-info "kosh" {})))]])) ["/fail" (fn [_] (throw (ex-info "kosh" {})))]]))
service (-> {:io.pedestal.http/request-logger nil service (-> {:io.pedestal.http/request-logger nil
:io.pedestal.http/routes []} :io.pedestal.http/routes []}
(io.pedestal.http/default-interceptors) (io.pedestal.http/default-interceptors)

View file

@ -18,25 +18,25 @@
(create f nil)) (create f nil))
([f wrap] ([f wrap]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
[["/defaults" [["/defaults"
{:handler f}] {:handler f}]
["/http-response" ["/http-response"
{:handler (fn [req] {:handler (fn [req]
(http-response/unauthorized! "Unauthorized"))}] (http-response/unauthorized! "Unauthorized"))}]
["/coercion" ["/coercion"
{:middleware [reitit.ring.coercion/coerce-request-middleware {:middleware [reitit.ring.coercion/coerce-request-middleware
reitit.ring.coercion/coerce-response-middleware] reitit.ring.coercion/coerce-response-middleware]
:coercion reitit.coercion.spec/coercion :coercion reitit.coercion.spec/coercion
:parameters {:query {:x int?, :y int?}} :parameters {:query {:x int?, :y int?}}
:responses {200 {:body {:total pos-int?}}} :responses {200 {:body {:total pos-int?}}}
:handler f}]] :handler f}]]
{:data {:middleware [(exception/create-exception-middleware {:data {:middleware [(exception/create-exception-middleware
(merge (merge
exception/default-handlers exception/default-handlers
{::kikka (constantly {:status 400, :body "kikka"}) {::kikka (constantly {:status 400, :body "kikka"})
SQLException (constantly {:status 400, :body "sql"}) SQLException (constantly {:status 400, :body "sql"})
::exception/wrap wrap}))]}}))))] ::exception/wrap wrap}))]}}))))]
(testing "normal calls work ok" (testing "normal calls work ok"
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}
@ -66,7 +66,6 @@
:response response}))))] :response response}))))]
(is (= response (app {:request-method :post, :uri "/http-response"}))))) (is (= response (app {:request-method :post, :uri "/http-response"})))))
(testing ":muuntaja/decode" (testing ":muuntaja/decode"
(let [app (create (fn [_] (m/decode m/instance "application/json" "{:so \"invalid\"}")))] (let [app (create (fn [_] (m/decode m/instance "application/json" "{:so \"invalid\"}")))]
(is (= {:body "Malformed \"application/json\" request." (is (= {:body "Malformed \"application/json\" request."
@ -130,21 +129,21 @@
(deftest spec-coercion-exception-test (deftest spec-coercion-exception-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/plus" ["/plus"
{:get {:get
{:parameters {:query {:x int?, :y int?}} {:parameters {:query {:x int?, :y int?}}
:responses {200 {:body {:total pos-int?}}} :responses {200 {:body {:total pos-int?}}}
:handler (fn [{{{:keys [x y]} :query} :parameters}] :handler (fn [{{{:keys [x y]} :query} :parameters}]
{:status 200, :body {:total (+ x y)}})}}] {:status 200, :body {:total (+ x y)}})}}]
{:data {:coercion reitit.coercion.spec/coercion {:data {:coercion reitit.coercion.spec/coercion
:middleware [(exception/create-exception-middleware :middleware [(exception/create-exception-middleware
(merge (merge
exception/default-handlers exception/default-handlers
{::coercion/request-coercion (fn [e _] {:status 400, :body (ex-data e)}) {::coercion/request-coercion (fn [e _] {:status 400, :body (ex-data e)})
::coercion/response-coercion (fn [e _] {:status 500, :body (ex-data e)})})) ::coercion/response-coercion (fn [e _] {:status 500, :body (ex-data e)})}))
reitit.ring.coercion/coerce-request-middleware reitit.ring.coercion/coerce-request-middleware
reitit.ring.coercion/coerce-response-middleware]}}))] reitit.ring.coercion/coerce-response-middleware]}}))]
(testing "success" (testing "success"
(let [{:keys [status body]} (app {:uri "/plus", :request-method :get, :query-params {"x" "1", "y" "2"}})] (let [{:keys [status body]} (app {:uri "/plus", :request-method :get, :query-params {"x" "1", "y" "2"}})]
(is (= 200 status)) (is (= 200 status))

View file

@ -8,10 +8,10 @@
(deftest muuntaja-test (deftest muuntaja-test
(let [data {:kikka "kukka"} (let [data {:kikka "kukka"}
app (ring/ring-handler app (ring/ring-handler
(ring/router (ring/router
["/ping" {:get (constantly {:status 200, :body data})}] ["/ping" {:get (constantly {:status 200, :body data})}]
{:data {:muuntaja m/instance {:data {:muuntaja m/instance
:middleware [muuntaja/format-middleware]}}))] :middleware [muuntaja/format-middleware]}}))]
(is (= data (->> {:request-method :get, :uri "/ping"} (is (= data (->> {:request-method :get, :uri "/ping"}
(app) (app)
:body :body
@ -22,26 +22,26 @@
no-edn-decode (m/create (-> m/default-options (update-in [:formats "application/edn"] dissoc :decoder))) no-edn-decode (m/create (-> m/default-options (update-in [:formats "application/edn"] dissoc :decoder)))
just-edn (m/create (-> m/default-options (m/select-formats ["application/edn"]))) just-edn (m/create (-> m/default-options (m/select-formats ["application/edn"])))
app (ring/ring-handler app (ring/ring-handler
(ring/router (ring/router
[["/defaults" [["/defaults"
{:get identity}] {:get identity}]
["/explicit-defaults" ["/explicit-defaults"
{:muuntaja with-defaults {:muuntaja with-defaults
:get identity}] :get identity}]
["/no-edn-decode" ["/no-edn-decode"
{:muuntaja no-edn-decode {:muuntaja no-edn-decode
:get identity}] :get identity}]
["/just-edn" ["/just-edn"
{:muuntaja just-edn {:muuntaja just-edn
:get identity}] :get identity}]
["/form-params" ["/form-params"
{:post {:parameters {:form {:x string?}} {:post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]]
{:data {:muuntaja m/instance {:data {:muuntaja m/instance
:middleware [muuntaja/format-middleware]}})) :middleware [muuntaja/format-middleware]}}))
spec (fn [method path] spec (fn [method path]
(let [path (keyword path)] (let [path (keyword path)]
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
@ -97,41 +97,41 @@
(deftest muuntaja-swagger-parts-test (deftest muuntaja-swagger-parts-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/request" [["/request"
{:middleware [muuntaja/format-negotiate-middleware {:middleware [muuntaja/format-negotiate-middleware
muuntaja/format-request-middleware] muuntaja/format-request-middleware]
:get identity}] :get identity}]
["/response" ["/response"
{:middleware [muuntaja/format-negotiate-middleware {:middleware [muuntaja/format-negotiate-middleware
muuntaja/format-response-middleware] muuntaja/format-response-middleware]
:get identity}] :get identity}]
["/both" ["/both"
{:middleware [muuntaja/format-negotiate-middleware {:middleware [muuntaja/format-negotiate-middleware
muuntaja/format-response-middleware muuntaja/format-response-middleware
muuntaja/format-request-middleware] muuntaja/format-request-middleware]
:get identity}] :get identity}]
["/form-request" ["/form-request"
{:middleware [muuntaja/format-negotiate-middleware {:middleware [muuntaja/format-negotiate-middleware
muuntaja/format-request-middleware] muuntaja/format-request-middleware]
:post {:parameters {:form {:x string?}} :post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/form-response" ["/form-response"
{:middleware [muuntaja/format-negotiate-middleware {:middleware [muuntaja/format-negotiate-middleware
muuntaja/format-response-middleware] muuntaja/format-response-middleware]
:post {:parameters {:form {:x string?}} :post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/form-with-both" ["/form-with-both"
{:middleware [muuntaja/format-negotiate-middleware {:middleware [muuntaja/format-negotiate-middleware
muuntaja/format-response-middleware muuntaja/format-response-middleware
muuntaja/format-request-middleware] muuntaja/format-request-middleware]
:post {:parameters {:form {:x string?}} :post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]]
{:data {:muuntaja m/instance}})) {:data {:muuntaja m/instance}}))
spec (fn [method path] spec (fn [method path]
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
(app) :body :paths (get path) method)) (app) :body :paths (get path) method))

View file

@ -6,9 +6,9 @@
(deftest parameters-test (deftest parameters-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/ping" {:get #(select-keys % [:params :query-params])}] ["/ping" {:get #(select-keys % [:params :query-params])}]
{:data {:middleware [parameters/parameters-middleware]}}))] {:data {:middleware [parameters/parameters-middleware]}}))]
(is (= {:query-params {"kikka" "kukka"} (is (= {:query-params {"kikka" "kukka"}
:params {"kikka" "kukka"}} :params {"kikka" "kukka"}}
(app {:request-method :get (app {:request-method :get
@ -17,14 +17,14 @@
(deftest parameters-swagger-test (deftest parameters-swagger-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/form-params" {:post {:parameters {:form {:x string?}} [["/form-params" {:post {:parameters {:form {:x string?}}
:handler identity}}] :handler identity}}]
["/body-params" {:post {:parameters {:body {:x string?}} ["/body-params" {:post {:parameters {:body {:x string?}}
:handler identity}}] :handler identity}}]
["/swagger.json" {:get {:no-doc true ["/swagger.json" {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]] :handler (swagger/create-swagger-handler)}}]]
{:data {:middleware [parameters/parameters-middleware]}})) {:data {:middleware [parameters/parameters-middleware]}}))
spec (fn [path] spec (fn [path]
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
app app

View file

@ -12,23 +12,23 @@
(deftest coercion-test (deftest coercion-test
(let [r (r/router (let [r (r/router
[["/schema" {:coercion reitit.coercion.schema/coercion} [["/schema" {:coercion reitit.coercion.schema/coercion}
["/:number/:keyword" {:parameters {:path {:number s/Int ["/:number/:keyword" {:parameters {:path {:number s/Int
:keyword s/Keyword} :keyword s/Keyword}
:query (s/maybe {:int s/Int, :ints [s/Int], :map {s/Int s/Int}})}}]] :query (s/maybe {:int s/Int, :ints [s/Int], :map {s/Int s/Int}})}}]]
["/malli" {:coercion reitit.coercion.malli/coercion} ["/malli" {:coercion reitit.coercion.malli/coercion}
["/:number/:keyword" {:parameters {:path [:map [:number int?] [:keyword keyword?]] ["/:number/:keyword" {:parameters {:path [:map [:number int?] [:keyword keyword?]]
:query [:maybe [:map [:int int?] :query [:maybe [:map [:int int?]
[:ints [:vector int?]] [:ints [:vector int?]]
[:map [:map-of int? int?]]]]}}]] [:map [:map-of int? int?]]]]}}]]
["/spec" {:coercion reitit.coercion.spec/coercion} ["/spec" {:coercion reitit.coercion.spec/coercion}
["/:number/:keyword" {:parameters {:path {:number int? ["/:number/:keyword" {:parameters {:path {:number int?
:keyword keyword?} :keyword keyword?}
:query (ds/maybe {:int int?, :ints [int?], :map {int? int?}})}}]] :query (ds/maybe {:int int?, :ints [int?], :map {int? int?}})}}]]
["/none" ["/none"
["/:number/:keyword" {:parameters {:path {:number int? ["/:number/:keyword" {:parameters {:path {:number int?
:keyword keyword?}}}]]] :keyword keyword?}}}]]]
{:compile coercion/compile-request-coercers})] {:compile coercion/compile-request-coercers})]
(testing "schema-coercion" (testing "schema-coercion"
(testing "succeeds" (testing "succeeds"
@ -80,10 +80,10 @@
(deftest data-spec-example-test (deftest data-spec-example-test
(let [router (r/router (let [router (r/router
["/:company/users/:user-id" {:name ::user-view ["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.spec/coercion :coercion reitit.coercion.spec/coercion
:parameters {:path {:company string? :parameters {:path {:company string?
:user-id int?}}}] :user-id int?}}}]
{:compile coercion/compile-request-coercers})] {:compile coercion/compile-request-coercers})]
(is (= {:path {:user-id 123, :company "metosin"}} (is (= {:path {:user-id 123, :company "metosin"}}
(:parameters (match-by-path-and-coerce! router "/metosin/users/123")))))) (:parameters (match-by-path-and-coerce! router "/metosin/users/123"))))))

View file

@ -21,38 +21,38 @@
(is (= nil (is (= nil
(r/match-by-path router "/api"))) (r/match-by-path router "/api")))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/ipa/:size" {:template "/api/ipa/:size"
:data {:name ::beer} :data {:name ::beer}
:path "/api/ipa/large" :path "/api/ipa/large"
:path-params {:size "large"}}) :path-params {:size "large"}})
(r/match-by-path router "/api/ipa/large"))) (r/match-by-path router "/api/ipa/large")))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/ipa/:size" {:template "/api/ipa/:size"
:data {:name ::beer} :data {:name ::beer}
:path "/api/ipa/large" :path "/api/ipa/large"
:path-params {:size "large"}}) :path-params {:size "large"}})
(r/match-by-name router ::beer {:size "large"}))) (r/match-by-name router ::beer {:size "large"})))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/ipa/:size" {:template "/api/ipa/:size"
:data {:name ::beer} :data {:name ::beer}
:path "/api/ipa/large" :path "/api/ipa/large"
:path-params {:size "large"}}) :path-params {:size "large"}})
(r/match-by-name router ::beer {:size :large}))) (r/match-by-name router ::beer {:size :large})))
(is (= nil (r/match-by-name router "ILLEGAL"))) (is (= nil (r/match-by-name router "ILLEGAL")))
(is (= [::beer] (r/route-names router))) (is (= [::beer] (r/route-names router)))
(testing "name-based routing with missing parameters" (testing "name-based routing with missing parameters"
(is (= (r/map->PartialMatch (is (= (r/map->PartialMatch
{:template "/api/ipa/:size" {:template "/api/ipa/:size"
:data {:name ::beer} :data {:name ::beer}
:required #{:size} :required #{:size}
:path-params nil}) :path-params nil})
(r/match-by-name router ::beer))) (r/match-by-name router ::beer)))
(is (r/partial-match? (r/match-by-name router ::beer))) (is (r/partial-match? (r/match-by-name router ::beer)))
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"^missing path-params for route /api/ipa/:size -> \#\{:size\}$" #"^missing path-params for route /api/ipa/:size -> \#\{:size\}$"
(r/match-by-name! router ::beer)))))) (r/match-by-name! router ::beer))))))
(testing "decode %-encoded path params" (testing "decode %-encoded path params"
(let [router (r/router [["/one-param-path/:param1" ::one] (let [router (r/router [["/one-param-path/:param1" ::one]
@ -71,14 +71,14 @@
(testing "complex" (testing "complex"
(let [router (r/router (let [router (r/router
[["/:abba" ::abba] [["/:abba" ::abba]
["/abba/1" ::abba2] ["/abba/1" ::abba2]
["/:jabba/2" ::jabba2] ["/:jabba/2" ::jabba2]
["/:abba/:dabba/doo" ::doo] ["/:abba/:dabba/doo" ::doo]
["/abba/dabba/boo/baa" ::baa] ["/abba/dabba/boo/baa" ::baa]
["/abba/:dabba/boo" ::boo] ["/abba/:dabba/boo" ::boo]
["/:jabba/:dabba/:doo/:daa/*foo" ::wild]] ["/:jabba/:dabba/:doo/:daa/*foo" ::wild]]
{:router r}) {:router r})
by-path #(-> router (r/match-by-path %) :data :name)] by-path #(-> router (r/match-by-path %) :data :name)]
(is (= ::abba (by-path "/abba"))) (is (= ::abba (by-path "/abba")))
(is (= ::abba2 (by-path "/abba/1"))) (is (= ::abba2 (by-path "/abba/1")))
@ -93,19 +93,19 @@
(testing "bracket-params" (testing "bracket-params"
(testing "successful" (testing "successful"
(let [router (r/router (let [router (r/router
[["/{abba}" ::abba] [["/{abba}" ::abba]
["/abba/1" ::abba2] ["/abba/1" ::abba2]
["/{jabba}/2" ::jabba2] ["/{jabba}/2" ::jabba2]
["/{abba}/{dabba}/doo" ::doo] ["/{abba}/{dabba}/doo" ::doo]
["/abba/dabba/boo/baa" ::baa] ["/abba/dabba/boo/baa" ::baa]
["/abba/{dabba}/boo" ::boo] ["/abba/{dabba}/boo" ::boo]
["/{a/jabba}/{a.b/dabba}/{a.b.c/doo}/{a.b.c.d/daa}/{*foo/bar}" ::wild] ["/{a/jabba}/{a.b/dabba}/{a.b.c/doo}/{a.b.c.d/daa}/{*foo/bar}" ::wild]
["/files/file-{name}.html" ::html] ["/files/file-{name}.html" ::html]
["/files/file-{name}.json" ::json] ["/files/file-{name}.json" ::json]
["/{eskon}/{saum}/pium\u2215paum" ::loru] ["/{eskon}/{saum}/pium\u2215paum" ::loru]
["/{🌈}🤔/🎈" ::emoji] ["/{🌈}🤔/🎈" ::emoji]
["/extra-end}s-are/ok" ::bracket]] ["/extra-end}s-are/ok" ::bracket]]
{:router r}) {:router r})
by-path #(-> router (r/match-by-path %) ((juxt (comp :name :data) :path-params)))] by-path #(-> router (r/match-by-path %) ((juxt (comp :name :data) :path-params)))]
(is (= [::abba {:abba "abba"}] (by-path "/abba"))) (is (= [::abba {:abba "abba"}] (by-path "/abba")))
(is (= [::abba2 {}] (by-path "/abba/1"))) (is (= [::abba2 {}] (by-path "/abba/1")))
@ -130,22 +130,22 @@
(testing "invalid syntax fails fast" (testing "invalid syntax fails fast"
(testing "unclosed brackets" (testing "unclosed brackets"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#":reitit.trie/unclosed-brackets" #":reitit.trie/unclosed-brackets"
(r/router ["/kikka/{kukka"])))) (r/router ["/kikka/{kukka"]))))
(testing "multiple terminators" (testing "multiple terminators"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#":reitit.trie/multiple-terminators" #":reitit.trie/multiple-terminators"
(r/router [["/{kukka}.json"] (r/router [["/{kukka}.json"]
["/{kukka}-json"]])))))) ["/{kukka}-json"]]))))))
(testing "empty path segments" (testing "empty path segments"
(let [router (r/router (let [router (r/router
[["/items" ::list] [["/items" ::list]
["/items/:id" ::item] ["/items/:id" ::item]
["/items/:id/:side" ::deep]] ["/items/:id/:side" ::deep]]
{:router r}) {:router r})
matches #(-> router (r/match-by-path %) :data :name)] matches #(-> router (r/match-by-path %) :data :name)]
(is (= ::list (matches "/items"))) (is (= ::list (matches "/items")))
(is (= nil (matches "/items/"))) (is (= nil (matches "/items/")))
@ -169,28 +169,28 @@
(is (= nil (is (= nil
(r/match-by-path router "/api"))) (r/match-by-path router "/api")))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/ipa/large" {:template "/api/ipa/large"
:data {:name ::beer} :data {:name ::beer}
:path "/api/ipa/large" :path "/api/ipa/large"
:path-params {}}) :path-params {}})
(r/match-by-path router "/api/ipa/large"))) (r/match-by-path router "/api/ipa/large")))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/ipa/large" {:template "/api/ipa/large"
:data {:name ::beer} :data {:name ::beer}
:path "/api/ipa/large" :path "/api/ipa/large"
:path-params {:size "large"}}) :path-params {:size "large"}})
(r/match-by-name router ::beer {:size "large"}))) (r/match-by-name router ::beer {:size "large"})))
(is (= nil (r/match-by-name router "ILLEGAL"))) (is (= nil (r/match-by-name router "ILLEGAL")))
(is (= [::beer] (r/route-names router))) (is (= [::beer] (r/route-names router)))
(testing "can't be created with wildcard routes" (testing "can't be created with wildcard routes"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"can't create :lookup-router with wildcard routes" #"can't create :lookup-router with wildcard routes"
(r/lookup-router (r/lookup-router
(impl/resolve-routes (impl/resolve-routes
["/api/:version/ping"] ["/api/:version/ping"]
(r/default-router-options))))))) (r/default-router-options)))))))
r/lookup-router :lookup-router r/lookup-router :lookup-router
r/single-static-path-router :single-static-path-router r/single-static-path-router :single-static-path-router
@ -216,14 +216,14 @@
(swap! compile-times inc) (swap! compile-times inc)
(constantly path)) (constantly path))
router (r/router router (r/router
["/api" {:roles #{:admin}} ["/api" {:roles #{:admin}}
["/ping" ::ping] ["/ping" ::ping]
["/pong" ::pong] ["/pong" ::pong]
["/hidden" {:invalid? true} ["/hidden" {:invalid? true}
["/utter"] ["/utter"]
["/crap"]]] ["/crap"]]]
{:coerce coerce {:coerce coerce
:compile compile})] :compile compile})]
(testing "routes are coerced" (testing "routes are coerced"
(is (= [["/api/ping" {:name ::ping (is (= [["/api/ping" {:name ::ping
@ -281,10 +281,10 @@
router (r/router routes)] router (r/router routes)]
(is (= expected (impl/resolve-routes routes (r/default-router-options)))) (is (= expected (impl/resolve-routes routes (r/default-router-options))))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/user/:id/:sub-id" {:template "/api/user/:id/:sub-id"
:data {:mw [:api], :parameters {:id "String", :sub-id "String"}} :data {:mw [:api], :parameters {:id "String", :sub-id "String"}}
:path "/api/user/1/2" :path "/api/user/1/2"
:path-params {:id "1", :sub-id "2"}}) :path-params {:id "1", :sub-id "2"}})
(r/match-by-path router "/api/user/1/2")))))) (r/match-by-path router "/api/user/1/2"))))))
(deftest conflicting-routes-test (deftest conflicting-routes-test
@ -334,10 +334,10 @@
(testing "router with conflicting routes" (testing "router with conflicting routes"
(testing "throws by default" (testing "throws by default"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Router contains conflicting route paths" #"Router contains conflicting route paths"
(r/router (r/router
[["/a"] ["/a"]])))) [["/a"] ["/a"]]))))
(testing "can be configured to ignore with route data" (testing "can be configured to ignore with route data"
(are [paths expected] (are [paths expected]
(let [router (r/router paths)] (let [router (r/router paths)]
@ -364,9 +364,9 @@
(testing "unmarked path conflicts throw" (testing "unmarked path conflicts throw"
(are [paths] (are [paths]
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Router contains conflicting route paths" #"Router contains conflicting route paths"
(r/router paths))) (r/router paths)))
[["/a"] ["/a" {:conflicting true}]] [["/a"] ["/a" {:conflicting true}]]
[["/a" {:conflicting true}] ["/a"]]))) [["/a" {:conflicting true}] ["/a"]])))
(testing "can be configured to ignore with router option" (testing "can be configured to ignore with router option"
@ -375,10 +375,10 @@
(testing "name conflicts" (testing "name conflicts"
(testing "router with conflicting routes always throws" (testing "router with conflicting routes always throws"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Router contains conflicting route names" #"Router contains conflicting route names"
(r/router (r/router
[["/1" ::1] ["/2" ::1]])))))) [["/1" ::1] ["/2" ::1]]))))))
(deftest match->path-test (deftest match->path-test
(let [router (r/router ["/:a/:b" ::route])] (let [router (r/router ["/:a/:b" ::route])]
@ -406,10 +406,10 @@
(r/routes))))) (r/routes)))))
(testing "sequential route definition fails" (testing "sequential route definition fails"
(is (thrown? (is (thrown?
#?(:clj Exception, :cljs js/Error) #?(:clj Exception, :cljs js/Error)
(-> ["/api" (-> ["/api"
(list "/ipa")] (list "/ipa")]
(r/router)))))) (r/router))))))
(defrecord Named [n] (defrecord Named [n]
r/Expand r/Expand
@ -422,12 +422,12 @@
(deftest routing-order-test-229 (deftest routing-order-test-229
(let [router (r/router (let [router (r/router
[["/" :root] [["/" :root]
["/" {:name :create :method :post}]] ["/" {:name :create :method :post}]]
{:conflicts nil}) {:conflicts nil})
router2 (r/router router2 (r/router
[["/*a" :root] [["/*a" :root]
["/:a/b/c/d" {:name :create :method :post}]] ["/:a/b/c/d" {:name :create :method :post}]]
{:conflicts nil})] {:conflicts nil})]
(is (= :root (-> (r/match-by-path router "/") :data :name))) (is (= :root (-> (r/match-by-path router "/") :data :name)))
(is (= :root (-> (r/match-by-path router2 "/") :data :name))))) (is (= :root (-> (r/match-by-path router2 "/") :data :name)))))

View file

@ -17,12 +17,12 @@
(are [exception] (are [exception]
(are [error routes] (are [error routes]
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
error error
(r/router (r/router
routes routes
{:validate rs/validate {:validate rs/validate
:exception exception}))) :exception exception})))
#"Router contains conflicting route paths" #"Router contains conflicting route paths"
[["/:a/1"] [["/:a/1"]

View file

@ -9,9 +9,9 @@
(defn execute [interceptors ctx] (defn execute [interceptors ctx]
(as-> ctx $ (as-> ctx $
(reduce #(%2 %1) $ (keep :enter interceptors)) (reduce #(%2 %1) $ (keep :enter interceptors))
(reduce #(%2 %1) $ (reverse (keep :leave interceptors))) (reduce #(%2 %1) $ (reverse (keep :leave interceptors)))
(:response $))) (:response $)))
(defn f [value ctx] (defn f [value ctx]
(update ctx :request conj value)) (update ctx :request conj value))
@ -36,8 +36,8 @@
(create interceptors nil)) (create interceptors nil))
([interceptors opts] ([interceptors opts]
(let [chain (interceptor/chain (let [chain (interceptor/chain
(conj interceptors handler) (conj interceptors handler)
:data opts)] :data opts)]
(partial execute chain)))) (partial execute chain))))
(deftest expand-interceptor-test (deftest expand-interceptor-test
@ -74,9 +74,9 @@
(testing "missing keyword" (testing "missing keyword"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Interceptor :enter not found in registry" #"Interceptor :enter not found in registry"
(create [:enter])))) (create [:enter]))))
(testing "existing keyword, compiling to nil" (testing "existing keyword, compiling to nil"
(let [app (create [:enter] {::interceptor/registry {:enter {:compile (constantly nil)}}})] (let [app (create [:enter] {::interceptor/registry {:enter {:compile (constantly nil)}}})]
@ -134,9 +134,9 @@
(testing "too deeply compiled interceptor fails" (testing "too deeply compiled interceptor fails"
(binding [interceptor/*max-compile-depth* 2] (binding [interceptor/*max-compile-depth* 2]
(is (thrown? (is (thrown?
ExceptionInfo ExceptionInfo
#"Too deep Interceptor compilation" #"Too deep Interceptor compilation"
(create [[i3 :value]]))))) (create [[i3 :value]])))))
(testing "nil unmounts the interceptor" (testing "nil unmounts the interceptor"
(let [app (create [{:compile (constantly nil)} (let [app (create [{:compile (constantly nil)}
@ -155,11 +155,11 @@
(testing "interceptor-handler" (testing "interceptor-handler"
(let [api-interceptor (interceptor :api) (let [api-interceptor (interceptor :api)
router (interceptor/router router (interceptor/router
[["/ping" handler] [["/ping" handler]
["/api" {:interceptors [api-interceptor]} ["/api" {:interceptors [api-interceptor]}
["/ping" handler] ["/ping" handler]
["/admin" {:interceptors [[interceptor :admin]]} ["/admin" {:interceptors [[interceptor :admin]]}
["/ping" handler]]]]) ["/ping" handler]]]])
app (create-app router)] app (create-app router)]
(testing "not found" (testing "not found"
@ -179,8 +179,8 @@
i2 {:name ::i2, :compile (constantly nil)} i2 {:name ::i2, :compile (constantly nil)}
i3 (interceptor ::i3) i3 (interceptor ::i3)
router (interceptor/router router (interceptor/router
["/api" {:interceptors [i1 i2 i3 i2] ["/api" {:interceptors [i1 i2 i3 i2]
:handler handler}]) :handler handler}])
app (create-app router)] app (create-app router)]
(is (= [::enter_i1 ::enter_i3 :ok ::leave_i3 ::leave_i1] (app "/api"))) (is (= [::enter_i1 ::enter_i3 :ok ::leave_i3 ::leave_i1] (app "/api")))
@ -221,12 +221,12 @@
(let [debug-i (enter ::debug) (let [debug-i (enter ::debug)
create (fn [options] create (fn [options]
(create-app (create-app
(interceptor/router (interceptor/router
["/ping" {:interceptors [(enter ::olipa) ["/ping" {:interceptors [(enter ::olipa)
(enter ::kerran) (enter ::kerran)
(enter ::avaruus)] (enter ::avaruus)]
:handler handler}] :handler handler}]
options))) options)))
inject-debug (interceptor/transform-butlast #(interleave % (repeat debug-i))) inject-debug (interceptor/transform-butlast #(interleave % (repeat debug-i)))
sort-interceptors (interceptor/transform-butlast (partial sort-by :name))] sort-interceptors (interceptor/transform-butlast (partial sort-by :name))]

View file

@ -15,10 +15,10 @@
(create middleware nil)) (create middleware nil))
([middleware opts] ([middleware opts]
(middleware/chain (middleware/chain
middleware middleware
handler handler
:data :data
opts))) opts)))
(deftest expand-middleware-test (deftest expand-middleware-test
@ -61,9 +61,9 @@
(testing "missing keyword" (testing "missing keyword"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Middleware :wrap not found in registry" #"Middleware :wrap not found in registry"
(create [:wrap])))) (create [:wrap]))))
(testing "existing keyword, compiling to nil" (testing "existing keyword, compiling to nil"
(let [app (create [:wrap] {::middleware/registry {:wrap {:compile (constantly nil)}}})] (let [app (create [:wrap] {::middleware/registry {:wrap {:compile (constantly nil)}}})]
@ -142,9 +142,9 @@
(testing "too deeply compiled Middleware fails" (testing "too deeply compiled Middleware fails"
(binding [middleware/*max-compile-depth* 2] (binding [middleware/*max-compile-depth* 2]
(is (thrown? (is (thrown?
ExceptionInfo ExceptionInfo
#"Too deep Middleware compilation" #"Too deep Middleware compilation"
(create [[(middleware/map->Middleware mw3) :value]]))))) (create [[(middleware/map->Middleware mw3) :value]])))))
(testing "nil unmounts the middleware" (testing "nil unmounts the middleware"
(let [app (create [{:compile (constantly nil)} (let [app (create [{:compile (constantly nil)}
@ -162,9 +162,9 @@
(testing "all paths should have a handler" (testing "all paths should have a handler"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"path \"/ping\" doesn't have a :handler defined" #"path \"/ping\" doesn't have a :handler defined"
(middleware/router ["/ping"])))) (middleware/router ["/ping"]))))
(testing "middleware-handler" (testing "middleware-handler"
(let [mw (fn [handler value] (let [mw (fn [handler value]
@ -173,11 +173,11 @@
api-mw #(mw % :api) api-mw #(mw % :api)
handler #(conj % :ok) handler #(conj % :ok)
router (middleware/router router (middleware/router
[["/ping" handler] [["/ping" handler]
["/api" {:middleware [api-mw]} ["/api" {:middleware [api-mw]}
["/ping" handler] ["/ping" handler]
["/admin" {:middleware [[mw :admin]]} ["/admin" {:middleware [[mw :admin]]}
["/ping" handler]]]]) ["/ping" handler]]]])
app (create-app router)] app (create-app router)]
(testing "not found" (testing "not found"
@ -197,9 +197,9 @@
mw2 {:name ::mw2, :compile (constantly nil)} mw2 {:name ::mw2, :compile (constantly nil)}
mw3 {:name ::mw3, :wrap #(mw % ::mw3)} mw3 {:name ::mw3, :wrap #(mw % ::mw3)}
router (middleware/router router (middleware/router
["/api" {:name ::api ["/api" {:name ::api
:middleware [mw1 mw2 mw3 mw2] :middleware [mw1 mw2 mw3 mw2]
:handler handler}]) :handler handler}])
app (create-app router)] app (create-app router)]
(is (= [::mw1 ::mw3 :ok ::mw3 ::mw1] (app "/api"))) (is (= [::mw1 ::mw3 :ok ::mw3 ::mw1] (app "/api")))
@ -241,12 +241,12 @@
debug-mw {:name ::debug, :wrap #(wrap % ::debug)} debug-mw {:name ::debug, :wrap #(wrap % ::debug)}
create (fn [options] create (fn [options]
(create-app (create-app
(middleware/router (middleware/router
["/ping" {:middleware [{:name ::olipa, :wrap #(wrap % ::olipa)} ["/ping" {:middleware [{:name ::olipa, :wrap #(wrap % ::olipa)}
{:name ::kerran, :wrap #(wrap % ::kerran)} {:name ::kerran, :wrap #(wrap % ::kerran)}
{:name ::avaruus, :wrap #(wrap % ::avaruus)}] {:name ::avaruus, :wrap #(wrap % ::avaruus)}]
:handler #(conj % :ok)}] :handler #(conj % :ok)}]
options)))] options)))]
(testing "by default, all middleware are applied in order" (testing "by default, all middleware are applied in order"
(let [app (create nil)] (let [app (create nil)]

View file

@ -77,19 +77,19 @@
(deftest spec-coercion-test (deftest spec-coercion-test
(let [create (fn [middleware] (let [create (fn [middleware]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:parameters {:query {(ds/opt :a) int?} {:get {:parameters {:query {(ds/opt :a) int?}
:body {:b int?} :body {:b int?}
:form {:c int?} :form {:c int?}
:header {:d int?} :header {:d int?}
:path {:e int?}} :path {:e int?}}
:responses {200 {:body {:total pos-int?}} :responses {200 {:body {:total pos-int?}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler handler}}]] :handler handler}}]]
{:data {:middleware middleware {:data {:middleware middleware
:coercion spec/coercion}})))] :coercion spec/coercion}})))]
(testing "without exception handling" (testing "without exception handling"
(let [app (create [rrc/coerce-request-middleware (let [app (create [rrc/coerce-request-middleware
@ -111,15 +111,15 @@
(testing "invalid request" (testing "invalid request"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app invalid-request1)))) (app invalid-request1))))
(testing "invalid response" (testing "invalid response"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Response coercion failed" #"Response coercion failed"
(app invalid-request2)))))) (app invalid-request2))))))
(testing "with exception handling" (testing "with exception handling"
(let [app (create [rrc/coerce-exceptions-middleware (let [app (create [rrc/coerce-exceptions-middleware
@ -144,19 +144,19 @@
(deftest schema-coercion-test (deftest schema-coercion-test
(let [create (fn [middleware] (let [create (fn [middleware]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:parameters {:query {(s/optional-key :a) s/Int} {:get {:parameters {:query {(s/optional-key :a) s/Int}
:body {:b s/Int} :body {:b s/Int}
:form {:c s/Int} :form {:c s/Int}
:header {:d s/Int} :header {:d s/Int}
:path {:e s/Int}} :path {:e s/Int}}
:responses {200 {:body {:total (s/constrained s/Int pos? 'positive)}} :responses {200 {:body {:total (s/constrained s/Int pos? 'positive)}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler handler}}]] :handler handler}}]]
{:data {:middleware middleware {:data {:middleware middleware
:coercion schema/coercion}})))] :coercion schema/coercion}})))]
(testing "withut exception handling" (testing "withut exception handling"
(let [app (create [rrc/coerce-request-middleware (let [app (create [rrc/coerce-request-middleware
@ -175,19 +175,19 @@
(testing "invalid request" (testing "invalid request"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app invalid-request1))) (app invalid-request1)))
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app valid-request3)))) (app valid-request3))))
(testing "invalid response" (testing "invalid response"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Response coercion failed" #"Response coercion failed"
(app invalid-request2)))))) (app invalid-request2))))))
(testing "with exception handling" (testing "with exception handling"
(let [app (create [rrc/coerce-exceptions-middleware (let [app (create [rrc/coerce-exceptions-middleware
@ -210,50 +210,50 @@
(deftest malli-coercion-test (deftest malli-coercion-test
(let [create (fn [middleware] (let [create (fn [middleware]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
["/validate" {:summary "just validation" ["/validate" {:summary "just validation"
:coercion (reitit.coercion.malli/create {:transformers {}}) :coercion (reitit.coercion.malli/create {:transformers {}})
:post {:parameters {:body [:map [:x int?]]} :post {:parameters {:body [:map [:x int?]]}
:responses {200 {:body [:map [:x int?]]}} :responses {200 {:body [:map [:x int?]]}}
:handler (fn [req] :handler (fn [req]
{:status 200 {:status 200
:body (-> req :parameters :body)})}}] :body (-> req :parameters :body)})}}]
["/no-op" {:summary "no-operation" ["/no-op" {:summary "no-operation"
:coercion (reitit.coercion.malli/create {:transformers {}, :validate false}) :coercion (reitit.coercion.malli/create {:transformers {}, :validate false})
:post {:parameters {:body [:map [:x int?]]} :post {:parameters {:body [:map [:x int?]]}
:responses {200 {:body [:map [:x int?]]}} :responses {200 {:body [:map [:x int?]]}}
:handler (fn [req] :handler (fn [req]
{:status 200 {:status 200
:body (-> req :parameters :body)})}}] :body (-> req :parameters :body)})}}]
["/skip" {:summary "skip" ["/skip" {:summary "skip"
:coercion (reitit.coercion.malli/create {:enabled false}) :coercion (reitit.coercion.malli/create {:enabled false})
:post {:parameters {:body [:map [:x int?]]} :post {:parameters {:body [:map [:x int?]]}
:responses {200 {:body [:map [:x int?]]}} :responses {200 {:body [:map [:x int?]]}}
:handler (fn [req] :handler (fn [req]
{:status 200
:body (-> req :parameters :body)})}}]
["/or" {:post {:summary "accepts either of two map schemas"
:parameters {:body [:or [:map [:x int?]] [:map [:y int?]]]}
:responses {200 {:body [:map [:msg string?]]}}
:handler (fn [{{{:keys [x]} :body} :parameters}]
{:status 200 {:status 200
:body {:msg (if x "you sent x" "you sent y")}})}}] :body (-> req :parameters :body)})}}]
["/plus/:e" {:get {:parameters {:query [:map [:a {:optional true} int?]] ["/or" {:post {:summary "accepts either of two map schemas"
:body [:map [:b int?]] :parameters {:body [:or [:map [:x int?]] [:map [:y int?]]]}
:form [:map [:c [int? {:default 3}]]] :responses {200 {:body [:map [:msg string?]]}}
:header [:map [:d int?]] :handler (fn [{{{:keys [x]} :body} :parameters}]
:path [:map [:e int?]]} {:status 200
:responses {200 {:body [:map [:total pos-int?]]} :body {:msg (if x "you sent x" "you sent y")}})}}]
500 {:description "fail"}}
:handler handler}}]] ["/plus/:e" {:get {:parameters {:query [:map [:a {:optional true} int?]]
{:data {:middleware middleware :body [:map [:b int?]]
:coercion malli/coercion}})))] :form [:map [:c [int? {:default 3}]]]
:header [:map [:d int?]]
:path [:map [:e int?]]}
:responses {200 {:body [:map [:total pos-int?]]}
500 {:description "fail"}}
:handler handler}}]]
{:data {:middleware middleware
:coercion malli/coercion}})))]
(testing "without exception handling" (testing "without exception handling"
(let [app (create [rrc/coerce-request-middleware (let [app (create [rrc/coerce-request-middleware
@ -279,15 +279,15 @@
(testing "invalid request" (testing "invalid request"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Request coercion failed" #"Request coercion failed"
(app invalid-request1)))) (app invalid-request1))))
(testing "invalid response" (testing "invalid response"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Response coercion failed" #"Response coercion failed"
(app invalid-request2)))))) (app invalid-request2))))))
(testing "with exception handling" (testing "with exception handling"
(let [app (create [rrc/coerce-exceptions-middleware (let [app (create [rrc/coerce-exceptions-middleware
@ -350,15 +350,15 @@
{:status 200, :body (assoc body :response true)})}}) {:status 200, :body (assoc body :response true)})}})
->app (fn [options] ->app (fn [options]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
["/default" (endpoint [:map [:x int?]])] ["/default" (endpoint [:map [:x int?]])]
["/closed" (endpoint [:map {:closed true} [:x int?]])] ["/closed" (endpoint [:map {:closed true} [:x int?]])]
["/open" (endpoint [:map {:closed false} [:x int?]])]] ["/open" (endpoint [:map {:closed false} [:x int?]])]]
{:data {:middleware [rrc/coerce-exceptions-middleware {:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion (malli/create options)}}))) :coercion (malli/create options)}})))
->request (fn [uri] {:uri (str "/api/" uri) ->request (fn [uri] {:uri (str "/api/" uri)
:request-method :get :request-method :get
:muuntaja/request {:format "application/json"} :muuntaja/request {:format "application/json"}
@ -414,22 +414,22 @@
(testing "sequence schemas" (testing "sequence schemas"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/ping" {:get {:parameters {:body [:vector [:map [:message string?]]]} ["/ping" {:get {:parameters {:body [:vector [:map [:message string?]]]}
:responses {200 {:body [:vector [:map [:pong string?]]]} :responses {200 {:body [:vector [:map [:pong string?]]]}
501 {:body [:vector [:map [:error string?]]]}} 501 {:body [:vector [:map [:error string?]]]}}
:handler (fn [{{[{:keys [message]}] :body} :parameters :as req}] :handler (fn [{{[{:keys [message]}] :body} :parameters :as req}]
(condp = message (condp = message
"ping" {:status 200 "ping" {:status 200
:body [{:pong message}]} :body [{:pong message}]}
"fail" {:status 501 "fail" {:status 501
:body [{:error "fail"}]} :body [{:error "fail"}]}
{:status 200 {:status 200
:body {:invalid "response"}}))}}] :body {:invalid "response"}}))}}]
{:data {:middleware [rrc/coerce-exceptions-middleware {:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion malli/coercion}})) :coercion malli/coercion}}))
->request (fn [body] ->request (fn [body]
{:uri "/ping" {:uri "/ping"
:request-method :get :request-method :get
@ -454,15 +454,15 @@
(testing "encoding responses" (testing "encoding responses"
(let [->app (fn [total-schema] (let [->app (fn [total-schema]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/total" {:get {:parameters {:query [:map [:x :int]]} ["/total" {:get {:parameters {:query [:map [:x :int]]}
:responses {200 {:body [:map [:total total-schema]]}} :responses {200 {:body [:map [:total total-schema]]}}
:handler (fn [{{{:keys [x]} :query} :parameters}] :handler (fn [{{{:keys [x]} :query} :parameters}]
{:status 200 {:status 200
:body {:total (* x x)}})}}] :body {:total (* x x)}})}}]
{:data {:middleware [rrc/coerce-request-middleware {:data {:middleware [rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion malli/coercion}}))) :coercion malli/coercion}})))
call (fn [accept total-schema] call (fn [accept total-schema]
((->app total-schema) {:uri "/total" ((->app total-schema) {:uri "/total"
:request-method :get :request-method :get
@ -482,18 +482,18 @@
#?(:clj #?(:clj
(deftest muuntaja-test (deftest muuntaja-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
["/plus" ["/plus"
{:post {:parameters {:body {:int int?, :keyword keyword?}} {:post {:parameters {:body {:int int?, :keyword keyword?}}
:responses {200 {:body {:int int?, :keyword keyword?}}} :responses {200 {:body {:int int?, :keyword keyword?}}}
:handler (fn [{{:keys [body]} :parameters}] :handler (fn [{{:keys [body]} :parameters}]
{:status 200 {:status 200
:body body})}}]] :body body})}}]]
{:data {:middleware [muuntaja.middleware/wrap-format {:data {:middleware [muuntaja.middleware/wrap-format
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion spec/coercion}})) :coercion spec/coercion}}))
request (fn [content-type body] request (fn [content-type body]
(-> {:request-method :post (-> {:request-method :post
:headers {"content-type" content-type, "accept" content-type} :headers {"content-type" content-type, "accept" content-type}

View file

@ -15,69 +15,69 @@
(deftest route-data-validation-test (deftest route-data-validation-test
(testing "validation is turned off by default" (testing "validation is turned off by default"
(is (r/router? (is (r/router?
(r/router (r/router
["/api" {:handler "identity"}])))) ["/api" {:handler "identity"}]))))
(testing "with default spec validates :name, :handler and :middleware" (testing "with default spec validates :name, :handler and :middleware"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(ring/router (ring/router
["/api" {:handler "identity"}] ["/api" {:handler "identity"}]
{:validate rrs/validate}))) {:validate rrs/validate})))
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(ring/router (ring/router
["/api" {:handler identity ["/api" {:handler identity
:name "kikka"}] :name "kikka"}]
{:validate rrs/validate})))) {:validate rrs/validate}))))
(testing "all endpoints are validated" (testing "all endpoints are validated"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(ring/router (ring/router
["/api" {:patch {:handler "identity"}}] ["/api" {:patch {:handler "identity"}}]
{:validate rrs/validate})))) {:validate rrs/validate}))))
(testing "spec can be overridden" (testing "spec can be overridden"
(is (r/router? (is (r/router?
(ring/router (ring/router
["/api" {:handler "identity"}] ["/api" {:handler "identity"}]
{:spec (s/spec any?) {:spec (s/spec any?)
:validate rrs/validate}))) :validate rrs/validate})))
(testing "predicates are not allowed" (testing "predicates are not allowed"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#":reitit.ring.spec/invalid-specs" #":reitit.ring.spec/invalid-specs"
(ring/router (ring/router
["/api" {:handler "identity"}] ["/api" {:handler "identity"}]
{:spec any? {:spec any?
:validate rrs/validate}))))) :validate rrs/validate})))))
(testing "middleware can contribute to specs" (testing "middleware can contribute to specs"
(is (r/router? (is (r/router?
(ring/router (ring/router
["/api" {:get {:handler identity ["/api" {:get {:handler identity
:roles #{:admin}}}] :roles #{:admin}}}]
{:validate rrs/validate {:validate rrs/validate
:data {:middleware [{:spec (s/keys :opt-un [::roles]) :data {:middleware [{:spec (s/keys :opt-un [::roles])
:wrap (fn [handler] :wrap (fn [handler]
(fn [request] (fn [request]
(handler request)))}]}}))) (handler request)))}]}})))
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(ring/router (ring/router
["/api" {:get {:handler identity ["/api" {:get {:handler identity
:roles #{:adminz}}}] :roles #{:adminz}}}]
{:validate rrs/validate {:validate rrs/validate
:data {:middleware [{:spec (s/keys :opt-un [::roles]) :data {:middleware [{:spec (s/keys :opt-un [::roles])
:wrap (fn [handler] :wrap (fn [handler]
(fn [request] (fn [request]
(handler request)))}]}})))) (handler request)))}]}}))))
(testing "middleware cannot be a list" (testing "middleware cannot be a list"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
@ -89,46 +89,46 @@
(deftest coercion-spec-test (deftest coercion-spec-test
(is (r/router? (is (r/router?
(ring/router (ring/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:parameters {:query {:a string?} {:get {:parameters {:query {:a string?}
:body {:b string?} :body {:b string?}
:form {:c string?} :form {:c string?}
:header {:d string?} :header {:d string?}
:path {:e string?}} :path {:e string?}}
:responses {200 {:body {:total pos-int?}} :responses {200 {:body {:total pos-int?}}
400 {:description "fail"} 400 {:description "fail"}
500 {}} 500 {}}
:handler identity}}]] :handler identity}}]]
{:data {:middleware [rrc/coerce-exceptions-middleware {:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion reitit.coercion.spec/coercion} :coercion reitit.coercion.spec/coercion}
:validate rrs/validate}))) :validate rrs/validate})))
(is (r/router? (is (r/router?
(ring/router (ring/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:parameters {:query (s/keys)} {:get {:parameters {:query (s/keys)}
:handler identity}}]] :handler identity}}]]
{:data {:middleware [rrc/coerce-exceptions-middleware {:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion reitit.coercion.spec/coercion} :coercion reitit.coercion.spec/coercion}
:validate rrs/validate}))) :validate rrs/validate})))
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(ring/router (ring/router
["/api" ["/api"
["/plus/:e" ["/plus/:e"
{:get {:responses {"200" {}} {:get {:responses {"200" {}}
:handler identity}}]] :handler identity}}]]
{:data {:middleware [rrc/coerce-exceptions-middleware {:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware] rrc/coerce-response-middleware]
:coercion reitit.coercion.spec/coercion} :coercion reitit.coercion.spec/coercion}
:validate rrs/validate})))) :validate rrs/validate}))))

View file

@ -28,35 +28,35 @@
(testing "nils are removed" (testing "nils are removed"
(is (= 123 (is (= 123
((ring/routes ((ring/routes
(constantly nil) (constantly nil)
nil nil
(constantly 123)) (constantly 123))
::irrelevant)))) ::irrelevant))))
(testing "can return nil" (testing "can return nil"
(is (= nil (is (= nil
(ring/routes (ring/routes
nil nil
nil))))) nil)))))
(deftest ring-router-test (deftest ring-router-test
(testing "all paths should have a handler" (testing "all paths should have a handler"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"path \"/ping\" doesn't have a :handler defined for :get" #"path \"/ping\" doesn't have a :handler defined for :get"
(ring/router ["/ping" {:get {}}])))) (ring/router ["/ping" {:get {}}]))))
(testing "ring-handler" (testing "ring-handler"
(let [api-mw #(mw % :api) (let [api-mw #(mw % :api)
router (ring/router router (ring/router
["/api" {:middleware [api-mw]} ["/api" {:middleware [api-mw]}
["/all" handler] ["/all" handler]
["/get" {:get handler}] ["/get" {:get handler}]
["/users" {:middleware [[mw :users]] ["/users" {:middleware [[mw :users]]
:get handler :get handler
:post {:handler handler :post {:handler handler
:middleware [[mw :post]]} :middleware [[mw :post]]}
:handler handler}]]) :handler handler}]])
app (ring/ring-handler router)] app (ring/ring-handler router)]
(testing "router can be extracted" (testing "router can be extracted"
@ -95,8 +95,8 @@
(testing "with top-level middleware" (testing "with top-level middleware"
(let [router (ring/router (let [router (ring/router
["/api" {:middleware [[mw :api]]} ["/api" {:middleware [[mw :api]]}
["/get" {:get handler}]]) ["/get" {:get handler}]])
app (ring/ring-handler router nil {:middleware [[mw :top]]})] app (ring/ring-handler router nil {:middleware [[mw :top]]})]
(testing "router can be extracted" (testing "router can be extracted"
@ -111,14 +111,14 @@
(testing "named routes" (testing "named routes"
(let [router (ring/router (let [router (ring/router
[["/api" [["/api"
["/all" {:handler handler :name ::all}] ["/all" {:handler handler :name ::all}]
["/get" {:get {:handler handler :name ::HIDDEN} ["/get" {:get {:handler handler :name ::HIDDEN}
:name ::get}] :name ::get}]
["/users" {:get handler ["/users" {:get handler
:post handler :post handler
:handler handler :handler handler
:name ::users}]]]) :name ::users}]]])
app (ring/ring-handler router)] app (ring/ring-handler router)]
(testing "router can be extracted" (testing "router can be extracted"
@ -141,21 +141,21 @@
(deftest mw-variadic-test (deftest mw-variadic-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/" {:middleware [[mw-variadic "kikka" "kakka" "kukka"]] ["/" {:middleware [[mw-variadic "kikka" "kakka" "kukka"]]
:handler handler}]))] :handler handler}]))]
(is (= {:status 200, :body [:kikka_kakka_kukka :ok]} (is (= {:status 200, :body [:kikka_kakka_kukka :ok]}
(app {:request-method :get, :uri "/"}))))) (app {:request-method :get, :uri "/"})))))
(deftest enforcing-data-rules-at-runtime-test (deftest enforcing-data-rules-at-runtime-test
(let [handler (constantly {:status 200, :body "ok"}) (let [handler (constantly {:status 200, :body "ok"})
app (ring/ring-handler app (ring/ring-handler
(ring/router (ring/router
[["/api" [["/api"
["/ping" handler] ["/ping" handler]
["/admin" {::roles #{:admin}} ["/admin" {::roles #{:admin}}
["/ping" handler]]]] ["/ping" handler]]]]
{:data {:middleware [wrap-enforce-roles]}}))] {:data {:middleware [wrap-enforce-roles]}}))]
(testing "public handler" (testing "public handler"
(is (= {:status 200, :body "ok"} (is (= {:status 200, :body "ok"}
@ -175,8 +175,8 @@
(deftest default-handler-test (deftest default-handler-test
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}
router (ring/router router (ring/router
[["/ping" {:get (constantly response)}] [["/ping" {:get (constantly response)}]
["/pong" (constantly nil)]]) ["/pong" (constantly nil)]])
app (ring/ring-handler router)] app (ring/ring-handler router)]
(testing "match" (testing "match"
@ -202,9 +202,9 @@
(testing "with custom http responses" (testing "with custom http responses"
(let [app (ring/ring-handler router (ring/create-default-handler (let [app (ring/ring-handler router (ring/create-default-handler
{:not-found (constantly {:status -404}) {:not-found (constantly {:status -404})
:method-not-allowed (constantly {:status -405}) :method-not-allowed (constantly {:status -405})
:not-acceptable (constantly {:status -406})}))] :not-acceptable (constantly {:status -406})}))]
(testing "route doesn't match" (testing "route doesn't match"
(is (= -404 (:status (app {:request-method :get, :uri "/"}))))) (is (= -404 (:status (app {:request-method :get, :uri "/"})))))
(testing "method doesn't match" (testing "method doesn't match"
@ -214,7 +214,7 @@
(testing "with some custom http responses" (testing "with some custom http responses"
(let [app (ring/ring-handler router (ring/create-default-handler (let [app (ring/ring-handler router (ring/create-default-handler
{:not-found (constantly {:status -404})}))] {:not-found (constantly {:status -404})}))]
(testing "route doesn't match" (testing "route doesn't match"
(is (= 405 (:status (app {:request-method :post, :uri "/ping"})))))))))) (is (= 405 (:status (app {:request-method :post, :uri "/ping"}))))))))))
@ -227,11 +227,11 @@
(testing "with defaults" (testing "with defaults"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/get" {:get (constantly response) [["/get" {:get (constantly response)
:post (constantly response)}] :post (constantly response)}]
["/options" {:options (constantly response)}] ["/options" {:options (constantly response)}]
["/any" (constantly response)]]))] ["/any" (constantly response)]]))]
(testing "endpoint with a non-options handler" (testing "endpoint with a non-options handler"
(let [request {:request-method :options, :uri "/get"}] (let [request {:request-method :options, :uri "/get"}]
@ -258,10 +258,10 @@
(constantly {:status 200, :body "ok"})]] (constantly {:status 200, :body "ok"})]]
(let [response {:status 200, :body "ok"} (let [response {:status 200, :body "ok"}
app (ring/ring-handler app (ring/ring-handler
(ring/router (ring/router
["/get" {:get (constantly response) ["/get" {:get (constantly response)
:post (constantly response)}] :post (constantly response)}]
{::ring/default-options-endpoint endpoint}))] {::ring/default-options-endpoint endpoint}))]
(testing "endpoint with a non-options handler" (testing "endpoint with a non-options handler"
(let [request {:request-method :options, :uri "/get"}] (let [request {:request-method :options, :uri "/get"}]
@ -270,11 +270,11 @@
(testing "disabled via options" (testing "disabled via options"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/get" {:get (constantly response)}] [["/get" {:get (constantly response)}]
["/options" {:options (constantly response)}] ["/options" {:options (constantly response)}]
["/any" (constantly response)]] ["/any" (constantly response)]]
{::ring/default-options-endpoint nil}))] {::ring/default-options-endpoint nil}))]
(testing "endpoint with a non-options handler" (testing "endpoint with a non-options handler"
(is (= response (app {:request-method :get, :uri "/get"}))) (is (= response (app {:request-method :get, :uri "/get"})))
@ -297,8 +297,8 @@
:post (constantly ok)}]]] :post (constantly ok)}]]]
(testing "using :method :add" (testing "using :method :add"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router routes) (ring/router routes)
(ring/redirect-trailing-slash-handler {:method :add}))] (ring/redirect-trailing-slash-handler {:method :add}))]
(testing "exact matches work" (testing "exact matches work"
(is (= ok (app {:request-method :get, :uri "/slash-less"}))) (is (= ok (app {:request-method :get, :uri "/slash-less"})))
@ -316,8 +316,8 @@
(testing "using :method :strip" (testing "using :method :strip"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router routes) (ring/router routes)
(ring/redirect-trailing-slash-handler {:method :strip}))] (ring/redirect-trailing-slash-handler {:method :strip}))]
(testing "stripping to empty string doesn't match" (testing "stripping to empty string doesn't match"
(is (= nil (:status (app {:request-method :get, :uri "/"}))))) (is (= nil (:status (app {:request-method :get, :uri "/"})))))
@ -342,8 +342,8 @@
(testing "without option (equivalent to using :method :both)" (testing "without option (equivalent to using :method :both)"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router routes) (ring/router routes)
(ring/redirect-trailing-slash-handler))] (ring/redirect-trailing-slash-handler))]
(testing "exact matches work" (testing "exact matches work"
(is (= ok (app {:request-method :get, :uri "/slash-less"}))) (is (= ok (app {:request-method :get, :uri "/slash-less"})))
@ -370,10 +370,10 @@
([x] (reset! value x)))) ([x] (reset! value x))))
response {:status 200, :body "ok"} response {:status 200, :body "ok"}
router (ring/router router (ring/router
[["/ping" {:get (fn [_ respond _] [["/ping" {:get (fn [_ respond _]
(respond response))}] (respond response))}]
["/pong" (fn [_ respond _] ["/pong" (fn [_ respond _]
(respond nil))]]) (respond nil))]])
app (ring/ring-handler router)] app (ring/ring-handler router)]
(testing "match" (testing "match"
@ -436,12 +436,12 @@
request {:uri "/api/avaruus" :request-method :get} request {:uri "/api/avaruus" :request-method :get}
create (fn [options] create (fn [options]
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" {:middleware [(middleware :olipa)]} ["/api" {:middleware [(middleware :olipa)]}
["/avaruus" {:middleware [(middleware :kerran)] ["/avaruus" {:middleware [(middleware :kerran)]
:get {:handler handler :get {:handler handler
:middleware [(middleware :avaruus)]}}]] :middleware [(middleware :avaruus)]}}]]
options)))] options)))]
(testing "by default, all middleware are applied in order" (testing "by default, all middleware are applied in order"
(let [app (create nil)] (let [app (create nil)]
@ -510,9 +510,9 @@
(testing "from path" (testing "from path"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/files/*" (create nil)]) ["/files/*" (create nil)])
(ring/create-default-handler)) (ring/create-default-handler))
request #(request (str "/files" %)) request #(request (str "/files" %))
redirect #(redirect (str "/files" %))] redirect #(redirect (str "/files" %))]
(testing "different file-types" (testing "different file-types"
@ -553,10 +553,10 @@
(testing "from root" (testing "from root"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router []) (ring/router [])
(ring/routes (ring/routes
(create {:path "/" :not-found-handler (fn [x] {:status 404 :body "resource-handler"})}) (create {:path "/" :not-found-handler (fn [x] {:status 404 :body "resource-handler"})})
(ring/create-default-handler)))] (ring/create-default-handler)))]
(testing "different file-types" (testing "different file-types"
(let [response (app (request "/hello.json"))] (let [response (app (request "/hello.json"))]
(is (= "application/json" (get-in response [:headers "Content-Type"]))) (is (= "application/json" (get-in response [:headers "Content-Type"])))
@ -594,10 +594,10 @@
(testing "from path" (testing "from path"
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router []) (ring/router [])
(ring/routes (ring/routes
(create {:path "/files" :not-found-handler (fn [x] {:status 404 :body "resource-handler"})}) (create {:path "/files" :not-found-handler (fn [x] {:status 404 :body "resource-handler"})})
(ring/create-default-handler))) (ring/create-default-handler)))
request #(request (str "/files" %)) request #(request (str "/files" %))
redirect #(redirect (str "/files" %))] redirect #(redirect (str "/files" %))]
(testing "different file-types" (testing "different file-types"
@ -638,12 +638,11 @@
(is (get-in @result [:headers "Last-Modified"])) (is (get-in @result [:headers "Last-Modified"]))
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))))))) (is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result))))))))))))))
#?(:clj #?(:clj
(deftest file-resource-handler-not-found-test (deftest file-resource-handler-not-found-test
(let [redirect (fn [uri] {:status 302, :body "", :headers {"Location" uri}}) (let [redirect (fn [uri] {:status 302, :body "", :headers {"Location" uri}})
request (fn [uri] {:uri uri, :request-method :get}) request (fn [uri] {:uri uri, :request-method :get})
not-found-handler (fn [_] {:status 404, :body "not-found-handler"})] not-found-handler (fn [_] {:status 404, :body "not-found-handler"})]
(doseq [[name create] [["resource-handler" ring/create-resource-handler] (doseq [[name create] [["resource-handler" ring/create-resource-handler]
["file-handler" #(ring/create-file-handler (assoc % :root "dev-resources/public"))]]] ["file-handler" #(ring/create-file-handler (assoc % :root "dev-resources/public"))]]]
@ -681,15 +680,15 @@
(deftest router-available-in-default-branch (deftest router-available-in-default-branch
(testing "1-arity" (testing "1-arity"
((ring/ring-handler ((ring/ring-handler
(ring/router []) (ring/router [])
(fn [{::r/keys [router]}] (fn [{::r/keys [router]}]
(is router))) (is router)))
{})) {}))
(testing "3-arity" (testing "3-arity"
((ring/ring-handler ((ring/ring-handler
(ring/router []) (ring/router [])
(fn [{::r/keys [router]} _ _] (fn [{::r/keys [router]} _ _]
(is router))) (is router)))
{} ::respond ::raise))) {} ::respond ::raise)))
#?(:clj #?(:clj
@ -697,11 +696,11 @@
(testing "in enough concurrent system, path-parameters can bleed" (testing "in enough concurrent system, path-parameters can bleed"
(doseq [compiler [trie/java-trie-compiler trie/clojure-trie-compiler]] (doseq [compiler [trie/java-trie-compiler trie/clojure-trie-compiler]]
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
["/:id" (fn [request] ["/:id" (fn [request]
{:status 200 {:status 200
:body (-> request :path-params :id)})]) :body (-> request :path-params :id)})])
{::trie/trie-compiler compiler})] {::trie/trie-compiler compiler})]
(dotimes [_ 10] (dotimes [_ 10]
(future (future
(dotimes [n 100000] (dotimes [n 100000]

View file

@ -38,10 +38,10 @@
(testing "with invalid routes" (testing "with invalid routes"
(are [data] (are [data]
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Call to #'reitit.core/router did not conform to spec" #"Call to #'reitit.core/router did not conform to spec"
(r/router (r/router
data))) data)))
;; path ;; path
[:invalid {}] [:invalid {}]
@ -68,10 +68,10 @@
(are [opts] (are [opts]
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Call to #'reitit.core/router did not conform to spec" #"Call to #'reitit.core/router did not conform to spec"
(r/router (r/router
["/api"] opts))) ["/api"] opts)))
{:path :api} {:path :api}
{:path nil} {:path nil}
@ -85,52 +85,52 @@
(deftest route-data-validation-test (deftest route-data-validation-test
(testing "validation is turned off by default" (testing "validation is turned off by default"
(is (r/router? (r/router (is (r/router? (r/router
["/api" {:handler "identity"}])))) ["/api" {:handler "identity"}]))))
(testing "with default spec validates :name and :handler" (testing "with default spec validates :name and :handler"
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(r/router (r/router
["/api" {:handler "identity"}] ["/api" {:handler "identity"}]
{:validate rs/validate}))) {:validate rs/validate})))
(is (thrown-with-msg? (is (thrown-with-msg?
ExceptionInfo ExceptionInfo
#"Invalid route data" #"Invalid route data"
(r/router (r/router
["/api" {:name "kikka"}] ["/api" {:name "kikka"}]
{:validate rs/validate})))) {:validate rs/validate}))))
(testing "spec can be overridden" (testing "spec can be overridden"
(is (r/router? (r/router (is (r/router? (r/router
["/api" {:handler "identity"}] ["/api" {:handler "identity"}]
{:spec any? {:spec any?
:validate rs/validate}))))) :validate rs/validate})))))
(deftest parameters-test (deftest parameters-test
(is (s/valid? (is (s/valid?
::rs/parameters ::rs/parameters
{:parameters {:query {:a string?} {:parameters {:query {:a string?}
:body {:b string?} :body {:b string?}
:form {:c string?} :form {:c string?}
:header {:d string?} :header {:d string?}
:path {:e string?}}})) :path {:e string?}}}))
(is (s/valid? (is (s/valid?
::rs/parameters ::rs/parameters
{:parameters {:header (s/keys)}})) {:parameters {:header (s/keys)}}))
(is (s/valid? (is (s/valid?
::rs/responses ::rs/responses
{:responses {200 {:description "ok", :body string?} {:responses {200 {:description "ok", :body string?}
400 {:description "fail"} 400 {:description "fail"}
500 {:body string?} 500 {:body string?}
:default {}}})) :default {}}}))
(is (not (s/valid? (is (not (s/valid?
::rs/responses ::rs/responses
{:responses {"200" {:description "ok", :body string?}}}))) {:responses {"200" {:description "ok", :body string?}}})))
(is (not (s/valid? (is (not (s/valid?
::rs/responses ::rs/responses
{:responses {200 {:description :ok, :body string?}}})))) {:responses {200 {:description :ok, :body string?}}}))))

View file

@ -13,93 +13,93 @@
(def app (def app
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
{:swagger {:id ::math}} {:swagger {:id ::math}}
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:swagger {:info {:title "my-api"}} :swagger {:info {:title "my-api"}}
:handler (swagger/create-swagger-handler)}}] :handler (swagger/create-swagger-handler)}}]
["/spec" {:coercion spec/coercion} ["/spec" {:coercion spec/coercion}
["/plus/:z" ["/plus/:z"
{:patch {:summary "patch" {:patch {:summary "patch"
:handler (constantly {:status 200})}
:options {:summary "options"
:middleware [{:data {:swagger {:responses {200 {:description "200"}}}}}]
:handler (constantly {:status 200})} :handler (constantly {:status 200})}
:options {:summary "options" :get {:summary "plus"
:middleware [{:data {:swagger {:responses {200 {:description "200"}}}}}] :parameters {:query {:x int?, :y int?}
:handler (constantly {:status 200})} :path {:z int?}}
:get {:summary "plus" :swagger {:responses {400 {:schema {:type "string"}
:parameters {:query {:x int?, :y int?} :description "kosh"}}}
:path {:z int?}} :responses {200 {:body {:total int?}}
:swagger {:responses {400 {:schema {:type "string"} 500 {:description "fail"}}
:description "kosh"}}} :handler (fn [{{{:keys [x y]} :query
:responses {200 {:body {:total int?}} {:keys [z]} :path} :parameters}]
500 {:description "fail"}} {:status 200, :body {:total (+ x y z)}})}
:handler (fn [{{{:keys [x y]} :query :post {:summary "plus with body"
{:keys [z]} :path} :parameters}] :parameters {:body (ds/maybe [int?])
{:status 200, :body {:total (+ x y z)}})} :path {:z int?}}
:post {:summary "plus with body" :swagger {:responses {400 {:schema {:type "string"}
:parameters {:body (ds/maybe [int?]) :description "kosh"}}}
:path {:z int?}} :responses {200 {:body {:total int?}}
:swagger {:responses {400 {:schema {:type "string"} 500 {:description "fail"}}
:description "kosh"}}} :handler (fn [{{{:keys [z]} :path
:responses {200 {:body {:total int?}} xs :body} :parameters}]
500 {:description "fail"}} {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
:handler (fn [{{{:keys [z]} :path
xs :body} :parameters}]
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
["/malli" {:coercion malli/coercion} ["/malli" {:coercion malli/coercion}
["/plus/*z" ["/plus/*z"
{:get {:summary "plus" {:get {:summary "plus"
:parameters {:query [:map [:x int?] [:y int?]] :parameters {:query [:map [:x int?] [:y int?]]
:path [:map [:z int?]]} :path [:map [:z int?]]}
:swagger {:responses {400 {:schema {:type "string"} :swagger {:responses {400 {:schema {:type "string"}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:body [:map [:total int?]]} :responses {200 {:body [:map [:total int?]]}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [x y]} :query :handler (fn [{{{:keys [x y]} :query
{:keys [z]} :path} :parameters}] {:keys [z]} :path} :parameters}]
{:status 200, :body {:total (+ x y z)}})} {:status 200, :body {:total (+ x y z)}})}
:post {:summary "plus with body" :post {:summary "plus with body"
:parameters {:body [:maybe [:vector int?]] :parameters {:body [:maybe [:vector int?]]
:path [:map [:z int?]]} :path [:map [:z int?]]}
:swagger {:responses {400 {:schema {:type "string"} :swagger {:responses {400 {:schema {:type "string"}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:body [:map [:total int?]]} :responses {200 {:body [:map [:total int?]]}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [z]} :path :handler (fn [{{{:keys [z]} :path
xs :body} :parameters}] xs :body} :parameters}]
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
["/schema" {:coercion schema/coercion} ["/schema" {:coercion schema/coercion}
["/plus/*z" ["/plus/*z"
{:get {:summary "plus" {:get {:summary "plus"
:parameters {:query {:x s/Int, :y s/Int} :parameters {:query {:x s/Int, :y s/Int}
:path {:z s/Int}} :path {:z s/Int}}
:swagger {:responses {400 {:schema {:type "string"} :swagger {:responses {400 {:schema {:type "string"}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:body {:total s/Int}} :responses {200 {:body {:total s/Int}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [x y]} :query :handler (fn [{{{:keys [x y]} :query
{:keys [z]} :path} :parameters}] {:keys [z]} :path} :parameters}]
{:status 200, :body {:total (+ x y z)}})} {:status 200, :body {:total (+ x y z)}})}
:post {:summary "plus with body" :post {:summary "plus with body"
:parameters {:body (s/maybe [s/Int]) :parameters {:body (s/maybe [s/Int])
:path {:z s/Int}} :path {:z s/Int}}
:swagger {:responses {400 {:schema {:type "string"} :swagger {:responses {400 {:schema {:type "string"}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:body {:total s/Int}} :responses {200 {:body {:total s/Int}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [z]} :path :handler (fn [{{{:keys [z]} :path
xs :body} :parameters}] xs :body} :parameters}]
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]]] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]]
{:data {:middleware [swagger/swagger-feature {:data {:middleware [swagger/swagger-feature
rrc/coerce-exceptions-middleware rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware]}}))) rrc/coerce-response-middleware]}})))
(require '[fipp.edn]) (require '[fipp.edn])
(deftest swagger-test (deftest swagger-test
@ -300,21 +300,21 @@
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}] :handler (swagger/create-swagger-handler)}}]
app (ring/ring-handler app (ring/ring-handler
(ring/router (ring/router
[["/common" {:swagger {:id #{::one ::two}}} [["/common" {:swagger {:id #{::one ::two}}}
ping-route] ping-route]
["/one" {:swagger {:id ::one}} ["/one" {:swagger {:id ::one}}
ping-route ping-route
spec-route] spec-route]
["/two" {:swagger {:id ::two}} ["/two" {:swagger {:id ::two}}
ping-route ping-route
spec-route spec-route
["/deep" {:swagger {:id ::one}} ["/deep" {:swagger {:id ::one}}
ping-route]] ping-route]]
["/one-two" {:swagger {:id #{::one ::two}}} ["/one-two" {:swagger {:id #{::one ::two}}}
spec-route]]))] spec-route]]))]
(is (= ["/common/ping" "/one/ping" "/two/deep/ping"] (is (= ["/common/ping" "/one/ping" "/two/deep/ping"]
(spec-paths app "/one/swagger.json"))) (spec-paths app "/one/swagger.json")))
(is (= ["/common/ping" "/two/ping"] (is (= ["/common/ping" "/two/ping"]
@ -324,8 +324,8 @@
(deftest swagger-ui-config-test (deftest swagger-ui-config-test
(let [app (swagger-ui/create-swagger-ui-handler (let [app (swagger-ui/create-swagger-ui-handler
{:path "/" {:path "/"
:config {:jsonEditor true}})] :config {:jsonEditor true}})]
(is (= 302 (:status (app {:request-method :get, :uri "/"})))) (is (= 302 (:status (app {:request-method :get, :uri "/"}))))
(is (= 200 (:status (app {:request-method :get, :uri "/index.html"})))) (is (= 200 (:status (app {:request-method :get, :uri "/index.html"}))))
(is (= {:jsonEditor true, :url "/swagger.json"} (is (= {:jsonEditor true, :url "/swagger.json"}
@ -334,12 +334,12 @@
(deftest without-swagger-id-test (deftest without-swagger-id-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/ping" [["/ping"
{:get (constantly "ping")}] {:get (constantly "ping")}]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]]))] :handler (swagger/create-swagger-handler)}}]]))]
(is (= ["/ping"] (spec-paths app "/swagger.json"))) (is (= ["/ping"] (spec-paths app "/swagger.json")))
(is (= #{::swagger/default} (is (= #{::swagger/default}
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
@ -347,14 +347,14 @@
(deftest with-options-endpoint-test (deftest with-options-endpoint-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/ping" [["/ping"
{:options (constantly "options")}] {:options (constantly "options")}]
["/pong" ["/pong"
(constantly "options")] (constantly "options")]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]]))] :handler (swagger/create-swagger-handler)}}]]))]
(is (= ["/ping" "/pong"] (spec-paths app "/swagger.json"))) (is (= ["/ping" "/pong"] (spec-paths app "/swagger.json")))
(is (= #{::swagger/default} (is (= #{::swagger/default}
(-> {:request-method :get :uri "/swagger.json"} (-> {:request-method :get :uri "/swagger.json"}
@ -362,18 +362,18 @@
(deftest all-parameter-types-test (deftest all-parameter-types-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/parameters" [["/parameters"
{:post {:coercion spec/coercion {:post {:coercion spec/coercion
:parameters {:query {:q string?} :parameters {:query {:q string?}
:body {:b string?} :body {:b string?}
:form {:f string?} :form {:f string?}
:header {:h string?} :header {:h string?}
:path {:p string?}} :path {:p string?}}
:handler identity}}] :handler identity}}]
["/swagger.json" ["/swagger.json"
{:get {:no-doc true {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]])) :handler (swagger/create-swagger-handler)}}]]))
spec (:body (app {:request-method :get, :uri "/swagger.json"}))] spec (:body (app {:request-method :get, :uri "/swagger.json"}))]
(is (= ["query" "body" "formData" "header" "path"] (is (= ["query" "body" "formData" "header" "path"]
(map :in (get-in spec [:paths "/parameters" :post :parameters])))))) (map :in (get-in spec [:paths "/parameters" :post :parameters]))))))