diff --git a/doc/advanced/dev_workflow.md b/doc/advanced/dev_workflow.md index 032ded69..cec7b0e6 100644 --- a/doc/advanced/dev_workflow.md +++ b/doc/advanced/dev_workflow.md @@ -147,3 +147,19 @@ Let's apply a small change to our ```ns3```. We'll replace our router by two dif And there you have it, dynamic during dev, performance at production. We have it all ! +## Var handlers + +You can use a var instead of a function as a `:handler`. This will +allow you to modify the handler function without rebuilding the reitit +router. + +For example: + +```clj +(def router + (ring/router + ["/ping" {:get #'my-ns/handler}])) +``` + +Now you can reload `my-ns` or redefine `my-ns/handler` and the router +will use the new definition automatically. diff --git a/modules/reitit-core/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc index 96264581..95633aec 100644 --- a/modules/reitit-core/src/reitit/core.cljc +++ b/modules/reitit-core/src/reitit/core.cljc @@ -28,6 +28,10 @@ :cljs function) (expand [this _] {:handler this}) + #?(:clj clojure.lang.Var + :cljs cljs.core.Var) + (expand [this _] {:handler this}) + nil (expand [_ _])) diff --git a/modules/reitit-core/src/reitit/spec.cljc b/modules/reitit-core/src/reitit/spec.cljc index 3da7d9ea..b2608514 100644 --- a/modules/reitit-core/src/reitit/spec.cljc +++ b/modules/reitit-core/src/reitit/spec.cljc @@ -38,7 +38,7 @@ ;; (s/def ::name keyword?) -(s/def ::handler fn?) +(s/def ::handler (s/or :fn fn? :var var?)) (s/def ::no-doc boolean?) (s/def ::conflicting boolean?) (s/def ::default-data diff --git a/test/cljc/reitit/core_test.cljc b/test/cljc/reitit/core_test.cljc index ab93cce6..14ae06d0 100644 --- a/test/cljc/reitit/core_test.cljc +++ b/test/cljc/reitit/core_test.cljc @@ -6,6 +6,9 @@ (:import (clojure.lang ExceptionInfo) (reitit.core Router)))) +(defn- var-handler [& _] + "var-handler") + (deftest reitit-test (testing "routers handling wildcard paths" @@ -245,7 +248,11 @@ (let [router (r/router ["/ping" (constantly "ok")]) {:keys [result]} (r/match-by-path router "/ping")] (is result) - (is (= "ok" (result)))))) + (is (= "ok" (result)))) + (testing "var handler gets expanded" + (let [router (r/router ["/ping" #'var-handler]) + {:keys [result]} (r/match-by-path router "/ping")] + (is (= #'var-handler result)))))) (testing "custom router" (let [router (r/router ["/ping"] {:router (fn [_ _] diff --git a/test/cljc/reitit/ring_test.cljc b/test/cljc/reitit/ring_test.cljc index 7c6276f9..e00b52d7 100644 --- a/test/cljc/reitit/ring_test.cljc +++ b/test/cljc/reitit/ring_test.cljc @@ -52,6 +52,7 @@ ["/api" {:middleware [api-mw]} ["/all" handler] ["/get" {:get handler}] + ["/get-var" {:get {:handler #'handler}}] ["/users" {:middleware [[mw :users]] :get handler :post {:handler handler @@ -74,6 +75,10 @@ (app {:uri "/api/get" :request-method :get}))) (is (= nil (app {:uri "/api/get" :request-method :post})))) + (testing "var handler" + (is (= {:status 200, :body [:api :ok]} + (app {:uri "/api/get-var" :request-method :get})))) + (testing "expanded method handler" (is (= {:status 200, :body [:api :users :ok]} (app {:uri "/api/users" :request-method :get})))) diff --git a/test/cljc/reitit/spec_test.cljc b/test/cljc/reitit/spec_test.cljc index 740d2df2..94bb5aef 100644 --- a/test/cljc/reitit/spec_test.cljc +++ b/test/cljc/reitit/spec_test.cljc @@ -101,6 +101,11 @@ ["/api" {:name "kikka"}] {:validate rs/validate})))) + (testing "handler can be a var" + (is (r/router? (r/router + ["/api" {:handler #'identity}] + {:validate rs/validate})))) + (testing "spec can be overridden" (is (r/router? (r/router ["/api" {:handler "identity"}]