mirror of
https://github.com/metosin/reitit.git
synced 2026-02-26 10:52:23 +00:00
Compare commits
No commits in common. "1dc961f661a01e486a2447b904bcdfb91b86699f" and "e671f78741ab69a6efc12756cba96f477beb2104" have entirely different histories.
1dc961f661
...
e671f78741
4 changed files with 87 additions and 5 deletions
|
|
@ -15,7 +15,6 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
|
||||||
## UNRELEASED
|
## UNRELEASED
|
||||||
|
|
||||||
* Improve & document how response schemas get picked in per-content-type coercion. See [docs](./doc/ring/coercion.md#per-content-type-coercion). [#745](https://github.com/metosin/reitit/issues/745).
|
* Improve & document how response schemas get picked in per-content-type coercion. See [docs](./doc/ring/coercion.md#per-content-type-coercion). [#745](https://github.com/metosin/reitit/issues/745).
|
||||||
* **BREAKING** Remove unused `reitit.dependency` ns. [#763](https://github.com/metosin/reitit/pull/763)
|
|
||||||
|
|
||||||
## 0.9.2 (2025-10-28)
|
## 0.9.2 (2025-10-28)
|
||||||
|
|
||||||
|
|
|
||||||
52
modules/reitit-core/src/reitit/dependency.cljc
Normal file
52
modules/reitit-core/src/reitit/dependency.cljc
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
(ns reitit.dependency
|
||||||
|
"Dependency resolution for middleware/interceptors."
|
||||||
|
(:require [reitit.exception :as exception]))
|
||||||
|
|
||||||
|
(defn- providers
|
||||||
|
"Map from provision key to provider. `get-provides` should return the provision keys of a dependent."
|
||||||
|
[get-provides nodes]
|
||||||
|
(reduce (fn [acc dependent]
|
||||||
|
(into acc
|
||||||
|
(map (fn [provide]
|
||||||
|
(when (contains? acc provide)
|
||||||
|
(exception/fail!
|
||||||
|
(str "multiple providers for: " provide)
|
||||||
|
{::multiple-providers provide}))
|
||||||
|
[provide dependent]))
|
||||||
|
(get-provides dependent)))
|
||||||
|
{} nodes))
|
||||||
|
|
||||||
|
(defn- get-provider
|
||||||
|
"Get the provider for `k`, throw if no provider can be found for it."
|
||||||
|
[providers k]
|
||||||
|
(if (contains? providers k)
|
||||||
|
(get providers k)
|
||||||
|
(exception/fail!
|
||||||
|
(str "provider missing for dependency: " k)
|
||||||
|
{::missing-provider k})))
|
||||||
|
|
||||||
|
(defn post-order
|
||||||
|
"Put `nodes` in post-order. Can also be described as a reverse topological sort.
|
||||||
|
`get-provides` and `get-requires` are callbacks that you can provide to compute the provide and depend
|
||||||
|
key sets of nodes, the defaults are `:provides` and `:requires`."
|
||||||
|
([nodes] (post-order :provides :requires nodes))
|
||||||
|
([get-provides get-requires nodes]
|
||||||
|
(let [providers-by-key (providers get-provides nodes)]
|
||||||
|
(letfn [(toposort [node path colors]
|
||||||
|
(case (get colors node)
|
||||||
|
:white (let [requires (get-requires node)
|
||||||
|
[nodes* colors] (toposort-seq (map (partial get-provider providers-by-key) requires)
|
||||||
|
(conj path node)
|
||||||
|
(assoc colors node :grey))]
|
||||||
|
[(conj nodes* node)
|
||||||
|
(assoc colors node :black)])
|
||||||
|
:grey (exception/fail! "circular dependency" {:cycle (drop-while #(not= % node) (conj path node))})
|
||||||
|
:black [() colors]))
|
||||||
|
|
||||||
|
(toposort-seq [nodes path colors]
|
||||||
|
(reduce (fn [[nodes* colors] node]
|
||||||
|
(let [[nodes** colors] (toposort node path colors)]
|
||||||
|
[(into nodes* nodes**) colors]))
|
||||||
|
[[] colors] nodes))]
|
||||||
|
|
||||||
|
(first (toposort-seq nodes [] (zipmap nodes (repeat :white))))))))
|
||||||
|
|
@ -298,8 +298,7 @@
|
||||||
| :index-redirect? | optional boolean: if true (default false), redirect to index file, if false serve it directly
|
| :index-redirect? | optional boolean: if true (default false), redirect to index file, if false serve it directly
|
||||||
| :canonicalize-uris? | optional boolean: if true (default), try to serve index files for non directory paths (paths that end with slash)
|
| :canonicalize-uris? | optional boolean: if true (default), try to serve index files for non directory paths (paths that end with slash)
|
||||||
| :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)
|
| :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)
|
||||||
| :mime-types | optional map of filename extensions to mime-types that will be used to guess the content type in addition to the ones defined in ring.util.mime-type/default-mime-types
|
| :mime-types | optional map of filename extensions to mime-types that will be used to guess the content type in addition to the ones defined in ring.util.mime-type/default-mime-types"
|
||||||
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to false"
|
|
||||||
([]
|
([]
|
||||||
(create-resource-handler nil))
|
(create-resource-handler nil))
|
||||||
([opts]
|
([opts]
|
||||||
|
|
@ -319,8 +318,7 @@
|
||||||
| :index-redirect? | optional boolean: if true (default false), redirect to index file, if false serve it directly
|
| :index-redirect? | optional boolean: if true (default false), redirect to index file, if false serve it directly
|
||||||
| :canonicalize-uris? | optional boolean: if true (default), try to serve index files for non directory paths (paths that end with slash)
|
| :canonicalize-uris? | optional boolean: if true (default), try to serve index files for non directory paths (paths that end with slash)
|
||||||
| :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)
|
| :not-found-handler | optional handler function to use if the requested resource is missing (404 Not Found)
|
||||||
| :mime-types | optional map of filename extensions to mime-types that will be used to guess the content type in addition to the ones defined in ring.util.mime-type/default-mime-types
|
| :mime-types | optional map of filename extensions to mime-types that will be used to guess the content type in addition to the ones defined in ring.util.mime-type/default-mime-types"
|
||||||
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to false"
|
|
||||||
([]
|
([]
|
||||||
(create-file-handler nil))
|
(create-file-handler nil))
|
||||||
([opts]
|
([opts]
|
||||||
|
|
|
||||||
33
test/cljc/reitit/dependency_test.cljc
Normal file
33
test/cljc/reitit/dependency_test.cljc
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
(ns reitit.dependency-test
|
||||||
|
(:require [clojure.test :refer [are deftest is testing]]
|
||||||
|
[reitit.dependency :as rc])
|
||||||
|
#?(:clj (:import [clojure.lang ExceptionInfo])))
|
||||||
|
|
||||||
|
(deftest post-order-test
|
||||||
|
(let [base-middlewares [{:name ::bar, :provides #{:bar}, :requires #{:foo}, :wrap identity}
|
||||||
|
{:name ::baz, :provides #{:baz}, :requires #{:bar :foo}, :wrap identity}
|
||||||
|
{:name ::foo, :provides #{:foo}, :requires #{}, :wrap identity}]]
|
||||||
|
(testing "happy cases"
|
||||||
|
(testing "default ordering works"
|
||||||
|
(is (= (rc/post-order base-middlewares)
|
||||||
|
(into (vec (drop 2 base-middlewares)) (take 2 base-middlewares)))))
|
||||||
|
|
||||||
|
(testing "custom provides and requires work"
|
||||||
|
(is (= (rc/post-order (comp hash-set :name)
|
||||||
|
(fn [node] (into #{} (map (fn [k] (keyword "reitit.dependency-test" (name k))))
|
||||||
|
(:requires node)))
|
||||||
|
base-middlewares)
|
||||||
|
(into (vec (drop 2 base-middlewares)) (take 2 base-middlewares))))))
|
||||||
|
|
||||||
|
(testing "errors"
|
||||||
|
(testing "missing dependency detection"
|
||||||
|
(is (thrown-with-msg? ExceptionInfo #"missing"
|
||||||
|
(rc/post-order (drop 1 base-middlewares)))))
|
||||||
|
|
||||||
|
(testing "ambiguous dependency detection"
|
||||||
|
(is (thrown-with-msg? ExceptionInfo #"multiple providers"
|
||||||
|
(rc/post-order (update-in base-middlewares [0 :provides] conj :foo)))))
|
||||||
|
|
||||||
|
(testing "circular dependency detection"
|
||||||
|
(is (thrown-with-msg? ExceptionInfo #"circular"
|
||||||
|
(rc/post-order (assoc-in base-middlewares [2 :requires] #{:baz}))))))))
|
||||||
Loading…
Reference in a new issue