From 3fd20f229413ae81a7533c87e564d1a56700b506 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 22 Jan 2023 14:15:08 +0200 Subject: [PATCH 1/7] reloading-ring-handler --- modules/reitit-ring/src/reitit/ring.cljc | 16 ++++++++++++++++ test/cljc/reitit/ring_test.cljc | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/modules/reitit-ring/src/reitit/ring.cljc b/modules/reitit-ring/src/reitit/ring.cljc index 97fdc9d2..8cbc36d2 100644 --- a/modules/reitit-ring/src/reitit/ring.cljc +++ b/modules/reitit-ring/src/reitit/ring.cljc @@ -340,6 +340,22 @@ nil))) {::r/router router})))) +(defn reloading-ring-handler + "Returns a ring-handler that recreates the actual ring-handler for each request. + Takes a 0-arity function that should return a valid ring-handler. Effectively creates + an auto-reloading ring-handler, which is good for REPL-driven development. + + Example: + + ;; for dev-mode, recreate the ring-handler for each request, for prod, just once + (let [dev-mode ... + f (fn [] (reitit.ring/ring-handler ...)] + (if dev-mode (reitit.ring/reloading-ring-handler f) (f)))" + [f] + (fn + ([request] ((f) request)) + ([request respond raise] ((f) request respond raise)))) + (defn get-router [handler] (-> handler meta ::r/router)) diff --git a/test/cljc/reitit/ring_test.cljc b/test/cljc/reitit/ring_test.cljc index efd91884..352def12 100644 --- a/test/cljc/reitit/ring_test.cljc +++ b/test/cljc/reitit/ring_test.cljc @@ -736,3 +736,22 @@ (dotimes [n 100000] (let [body (:body (app {:request-method :get, :uri (str "/" n)}))] (is (= body (str n)))))))))))) + +(declare routes) + +(deftest reloading-ring-handler-test + (let [r (fn [body] {:status 200, :body body})] + (def routes ["/" (constantly (r "1"))]) ;; initial value + + (let [create-handler (fn [] (ring/ring-handler (ring/router routes)))] + (testing "static ring handler does not see underlying route changes" + (let [app (create-handler)] + (is (= (r "1") (app {:uri "/", :request-method :get}))) + (def routes ["/" (constantly (r "2"))]) ;; redefine + (is (= (r "1") (app {:uri "/", :request-method :get}))))) + + (testing "reloading ring handler sees underlying route changes" + (let [app (ring/reloading-ring-handler create-handler)] + (is (= (r "2") (app {:uri "/", :request-method :get}))) + (def routes ["/" (constantly (r "3"))]) ;; redefine again + (is (= (r "3") (app {:uri "/", :request-method :get})))))))) From e175dc76c954db99cdc69b5fb1887ce02c3c95b6 Mon Sep 17 00:00:00 2001 From: bplubell Date: Tue, 31 Jan 2023 15:34:37 -0800 Subject: [PATCH 2/7] Fix incorrect ring-router doc references It looks like documentation references to `ring-router` are left-overs from early README examples - I couldn't find any code that ever used the name. The Ring router named `reitit.ring/router`. While it didn't take too long for me to realize why my `ring-router` was not working, I had to look the examples to figure out the name of the function was just `router` - which was confusing since the section header stated `reitit-router`. --- doc/README.md | 4 ++-- doc/SUMMARY.md | 2 +- doc/cljdoc.edn | 2 +- doc/performance.md | 2 +- doc/ring/ring.md | 8 ++++---- doc/ring/swagger.md | 4 ++-- doc/ring/transforming_middleware_chain.md | 3 +-- test/cljc/reitit/ring_test.cljc | 2 +- 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/doc/README.md b/doc/README.md index f71402fb..c5d335aa 100644 --- a/doc/README.md +++ b/doc/README.md @@ -110,9 +110,9 @@ Reverse-routing: ; :path "/api/orders/2"} ``` -## Ring-router +## Ring router -Ring-router adds support for `:handler` functions, `:middleware` and routing based on `:request-method`. It also supports pluggable parameter coercion (`clojure.spec`), data-driven middleware, route and middleware compilation, dynamic extensions and more. +A Ring router function adds support for `:handler` functions, `:middleware` and routing based on `:request-method`. It also supports pluggable parameter coercion (`clojure.spec`), data-driven middleware, route and middleware compilation, dynamic extensions and more. ```clj (require '[reitit.ring :as ring]) diff --git a/doc/SUMMARY.md b/doc/SUMMARY.md index 758a1308..d70d65e4 100644 --- a/doc/SUMMARY.md +++ b/doc/SUMMARY.md @@ -25,7 +25,7 @@ ## Ring -* [Ring-router](ring/ring.md) +* [Ring Router](ring/ring.md) * [Reverse-routing](ring/reverse_routing.md) * [Default handler](ring/default_handler.md) * [Slash handler](ring/slash_handler.md) diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn index af82cc84..3ec69060 100644 --- a/doc/cljdoc.edn +++ b/doc/cljdoc.edn @@ -31,7 +31,7 @@ ["Data-specs" {:file "doc/coercion/data_spec_coercion.md"}] ["Malli" {:file "doc/coercion/malli_coercion.md"}]] ["Ring" {} - ["Ring-router" {:file "doc/ring/ring.md"}] + ["Ring Router" {:file "doc/ring/ring.md"}] ["Reverse-routing" {:file "doc/ring/reverse_routing.md"}] ["Default handler" {:file "doc/ring/default_handler.md"}] ["Slash handler" {:file "doc/ring/slash_handler.md"}] diff --git a/doc/performance.md b/doc/performance.md index 3609e05e..1b719a31 100644 --- a/doc/performance.md +++ b/doc/performance.md @@ -114,7 +114,7 @@ A quick poke to [the fast routers in Go](https://github.com/julienschmidt/go-htt ### Faster! -By default, `reitit.ring/ring-router`, `reitit.http/ring-router` and `reitit.http/routing-interceptor` inject both `Match` and `Router` into the request. You can remove the injections setting options `:inject-match?` and `:inject-router?` to `false`. This saves some tens of nanos (with the hw described above). +By default, `reitit.ring/router`, `reitit.http/router` and `reitit.http/routing-interceptor` inject both `Match` and `Router` into the request. You can remove the injections setting options `:inject-match?` and `:inject-router?` to `false`. This saves some tens of nanos (with the hw described above). ```clj (require '[reitit.ring :as ring]) diff --git a/doc/ring/ring.md b/doc/ring/ring.md index daf4b0a6..33f1459d 100644 --- a/doc/ring/ring.md +++ b/doc/ring/ring.md @@ -8,9 +8,9 @@ Read more about the [Ring Concepts](https://github.com/ring-clojure/ring/wiki/Co [metosin/reitit-ring "0.5.18"] ``` -## `reitit.ring/ring-router` +## `reitit.ring/router` -`ring-router` is a higher order router, which adds support for `:request-method` based routing, [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers) and [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware). +`reitit.ring/router` is a higher order router, which adds support for `:request-method` based routing, [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers) and [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware). It accepts the following options: @@ -33,7 +33,7 @@ Example router: ["/ping" {:get handler}])) ``` -Match contains `:result` compiled by the `ring-router`: +Match contains `:result` compiled by `reitit.ring/router`: ```clj (require '[reitit.core :as r]) @@ -49,7 +49,7 @@ Match contains `:result` compiled by the `ring-router`: ## `reitit.ring/ring-handler` -Given a `ring-router`, optional default-handler & options, `ring-handler` function will return a valid ring handler supporting both synchronous and [asynchronous](https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html) request handling. The following options are available: +Given a router from `reitit.ring/router`, optional default-handler & options, `ring-handler` function will return a valid ring handler supporting both synchronous and [asynchronous](https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html) request handling. The following options are available: | key | description | | ------------------|-------------| diff --git a/doc/ring/swagger.md b/doc/ring/swagger.md index 719a0611..0506993d 100644 --- a/doc/ring/swagger.md +++ b/doc/ring/swagger.md @@ -6,7 +6,7 @@ Reitit supports [Swagger2](https://swagger.io/) documentation, thanks to [schema-tools](https://github.com/metosin/schema-tools) and [spec-tools](https://github.com/metosin/spec-tools). Documentation is extracted from route definitions, coercion `:parameters` and `:responses` and from a set of new documentation keys. -To enable swagger-documentation for a ring-router: +To enable swagger-documentation for a Ring router: 1. annotate your routes with swagger-data 2. mount a swagger-handler to serve the swagger-spec @@ -129,7 +129,7 @@ Another way to serve the swagger-ui is using the [default handler](default_handl ["/pong" {:post (constantly {:status 200, :body "pong"})}]] ["/swagger.json" {:get {:no-doc true - :handler (swagger/create-swagger-handler)}}]]) + :handler (swagger/create-swagger-handler)}}]]) (swagger-ui/create-swagger-ui-handler {:path "/api-docs"}))) ``` diff --git a/doc/ring/transforming_middleware_chain.md b/doc/ring/transforming_middleware_chain.md index 5175758e..25ab4edf 100644 --- a/doc/ring/transforming_middleware_chain.md +++ b/doc/ring/transforming_middleware_chain.md @@ -1,6 +1,6 @@ # Transforming the Middleware Chain -There is an extra option in ring-router (actually, in the underlying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. Value should be a function or a vector of functions that get a vector of compiled middleware and should return a new vector of middleware. +There is an extra option in the Ring router (actually, in the underlying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. Value should be a function or a vector of functions that get a vector of compiled middleware and should return a new vector of middleware. ## Example Application @@ -71,4 +71,3 @@ Using `reitit.ring.middleware.dev/print-request-diffs` transformation, the reque Sample output: ![Ring Request Diff](../images/ring-request-diff.png) - diff --git a/test/cljc/reitit/ring_test.cljc b/test/cljc/reitit/ring_test.cljc index 7f0a0af3..c260fcc6 100644 --- a/test/cljc/reitit/ring_test.cljc +++ b/test/cljc/reitit/ring_test.cljc @@ -38,7 +38,7 @@ nil nil))))) -(deftest ring-router-test +(deftest router-test (testing "all paths should have a handler" (is (thrown-with-msg? From 83c31e35bc15e4b2e3cace4cf1cc8955e03cee64 Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 18 Jan 2023 20:28:26 +0200 Subject: [PATCH 3/7] Revert "Revert "Merge pull request #554 from just-sultanov/add-support-for-fragment-parameters"" This reverts commit 4d1b00edfab4c50bac22973e80f4de22aeb52ea5. --- modules/reitit-core/src/reitit/coercion.cljc | 3 +- .../reitit-frontend/src/reitit/frontend.cljs | 20 ++++++++- test/cljs/reitit/frontend/core_test.cljs | 43 +++++++++++++++---- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 4436214c..75312c86 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -39,7 +39,8 @@ :body (->ParameterCoercion :body-params :body false false) :form (->ParameterCoercion :form-params :string true true) :header (->ParameterCoercion :headers :string true true) - :path (->ParameterCoercion :path-params :string true true)}) + :path (->ParameterCoercion :path-params :string true true) + :fragment (->ParameterCoercion :fragment-params :string true true)}) (defn ^:no-doc request-coercion-failed! [result coercion value in request serialize-failed-result] (throw diff --git a/modules/reitit-frontend/src/reitit/frontend.cljs b/modules/reitit-frontend/src/reitit/frontend.cljs index d1e9c50a..922b5a8b 100644 --- a/modules/reitit-frontend/src/reitit/frontend.cljs +++ b/modules/reitit-frontend/src/reitit/frontend.cljs @@ -1,5 +1,6 @@ (ns reitit.frontend (:require [clojure.set :as set] + [clojure.string :as str] [reitit.coercion :as coercion] [reitit.core :as r]) (:import goog.Uri @@ -20,6 +21,19 @@ (map (juxt keyword #(query-param q %))) (into {})))) +(defn fragment-params + "Given goog.Uri, read fragment parameters into Clojure map." + [^Uri uri] + (let [fp (.getFragment uri)] + (if-not (seq fp) + {} + (into {} + (comp + (map #(str/split % #"=")) + (map (fn [[k v]] + [(keyword k) v]))) + (str/split fp #"&"))))) + (defn match-by-path "Given routing tree and current path, return match with possibly coerced parameters. Return nil if no match found. @@ -37,12 +51,14 @@ coercion/coerce!)] (if-let [match (r/match-by-path router (.getPath uri))] (let [q (query-params uri) - match (assoc match :query-params q) + fp (fragment-params uri) + match (assoc match :query-params q :fragment-params fp) ;; Return uncoerced values if coercion is not enabled - so ;; that tha parameters are always accessible from same property. parameters (or (coerce! match) {:path (:path-params match) - :query q})] + :query q + :fragment fp})] (assoc match :parameters parameters)))))) (defn match-by-name diff --git a/test/cljs/reitit/frontend/core_test.cljs b/test/cljs/reitit/frontend/core_test.cljs index 72bf9428..42a45bde 100644 --- a/test/cljs/reitit/frontend/core_test.cljs +++ b/test/cljs/reitit/frontend/core_test.cljs @@ -21,9 +21,11 @@ :data {:name ::frontpage} :path-params {} :query-params {} + :fragment-params {} :path "/" :parameters {:query {} - :path {}}}) + :path {} + :fragment {}}}) (rf/match-by-path router "/"))) (is (= "/" @@ -34,9 +36,11 @@ :data {:name ::foo} :path-params {} :query-params {} + :fragment-params {} :path "/foo" :parameters {:query {} - :path {}}}) + :path {} + :fragment {}}}) (rf/match-by-path router "/foo"))) (is (= (r/map->Match @@ -44,9 +48,11 @@ :data {:name ::foo} :path-params {} :query-params {:mode ["foo", "bar"]} + :fragment-params {} :path "/foo" :parameters {:query {:mode ["foo", "bar"]} - :path {}}}) + :path {} + :fragment {}}}) (rf/match-by-path router "/foo?mode=foo&mode=bar"))) (is (= "/foo" @@ -64,7 +70,12 @@ (let [router (r/router ["/" [":id" {:name ::foo :parameters {:path {:id s/Int} - :query {(s/optional-key :mode) s/Keyword}}}]] + :query {(s/optional-key :mode) s/Keyword} + :fragment {(s/optional-key :access_token) s/Str + (s/optional-key :refresh_token) s/Str + (s/optional-key :expires_in) s/Int + (s/optional-key :provider_token) s/Str + (s/optional-key :token_type) s/Str}}}]] {:compile rc/compile-request-coercers :data {:coercion rsc/coercion}})] @@ -72,9 +83,11 @@ {:template "/:id" :path-params {:id "5"} :query-params {} + :fragment-params {} :path "/5" :parameters {:query {} - :path {:id 5}}}) + :path {:id 5} + :fragment {}}}) (m (rf/match-by-path router "/5")))) (is (= "/5" @@ -98,23 +111,35 @@ {:template "/:id" :path-params {:id "5"} :query-params {:mode "foo"} + :fragment-params {} :path "/5" :parameters {:path {:id 5} - :query {:mode :foo}}}) + :query {:mode :foo} + :fragment {}}}) (m (rf/match-by-path router "/5?mode=foo")))) (is (= "/5?mode=foo" (r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo})))) - (testing "fragment is ignored" + (testing "fragment is read" (is (= (r/map->Match {:template "/:id" :path-params {:id "5"} :query-params {:mode "foo"} + :fragment-params {:access_token "foo" + :refresh_token "bar" + :provider_token "baz" + :token_type "bearer" + :expires_in "3600"} :path "/5" :parameters {:path {:id 5} - :query {:mode :foo}}}) - (m (rf/match-by-path router "/5?mode=foo#fragment"))))) + :query {:mode :foo} + :fragment {:access_token "foo" + :refresh_token "bar" + :provider_token "baz" + :token_type "bearer" + :expires_in 3600}}}) + (m (rf/match-by-path router "/5?mode=foo#access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600"))))) (testing "console warning about missing params" (is (= [{:type :warn From 2494f702d9d70484aa8ec7a6a445496fb5a6e29c Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Wed, 18 Jan 2023 20:24:33 +0200 Subject: [PATCH 4/7] Read fragment string without decoding Users can use Malli decoding to control decoding per schema. --- modules/reitit-core/src/reitit/coercion.cljc | 2 +- .../reitit-frontend/src/reitit/frontend.cljs | 23 +-- test/cljs/reitit/frontend/core_test.cljs | 135 ++++++++++++++---- 3 files changed, 112 insertions(+), 48 deletions(-) diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 75312c86..8c382e9a 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -40,7 +40,7 @@ :form (->ParameterCoercion :form-params :string true true) :header (->ParameterCoercion :headers :string true true) :path (->ParameterCoercion :path-params :string true true) - :fragment (->ParameterCoercion :fragment-params :string true true)}) + :fragment (->ParameterCoercion :fragment :string true true)}) (defn ^:no-doc request-coercion-failed! [result coercion value in request serialize-failed-result] (throw diff --git a/modules/reitit-frontend/src/reitit/frontend.cljs b/modules/reitit-frontend/src/reitit/frontend.cljs index 922b5a8b..faa258e0 100644 --- a/modules/reitit-frontend/src/reitit/frontend.cljs +++ b/modules/reitit-frontend/src/reitit/frontend.cljs @@ -1,6 +1,5 @@ (ns reitit.frontend (:require [clojure.set :as set] - [clojure.string :as str] [reitit.coercion :as coercion] [reitit.core :as r]) (:import goog.Uri @@ -21,19 +20,6 @@ (map (juxt keyword #(query-param q %))) (into {})))) -(defn fragment-params - "Given goog.Uri, read fragment parameters into Clojure map." - [^Uri uri] - (let [fp (.getFragment uri)] - (if-not (seq fp) - {} - (into {} - (comp - (map #(str/split % #"=")) - (map (fn [[k v]] - [(keyword k) v]))) - (str/split fp #"&"))))) - (defn match-by-path "Given routing tree and current path, return match with possibly coerced parameters. Return nil if no match found. @@ -51,14 +37,17 @@ coercion/coerce!)] (if-let [match (r/match-by-path router (.getPath uri))] (let [q (query-params uri) - fp (fragment-params uri) - match (assoc match :query-params q :fragment-params fp) + fragment (when (.hasFragment uri) + (.getFragment uri)) + match (assoc match + :query-params q + :fragment fragment) ;; Return uncoerced values if coercion is not enabled - so ;; that tha parameters are always accessible from same property. parameters (or (coerce! match) {:path (:path-params match) :query q - :fragment fp})] + :fragment fragment})] (assoc match :parameters parameters)))))) (defn match-by-name diff --git a/test/cljs/reitit/frontend/core_test.cljs b/test/cljs/reitit/frontend/core_test.cljs index 42a45bde..d0684398 100644 --- a/test/cljs/reitit/frontend/core_test.cljs +++ b/test/cljs/reitit/frontend/core_test.cljs @@ -4,12 +4,23 @@ [reitit.frontend :as rf] [reitit.coercion :as rc] [schema.core :as s] - [reitit.coercion.schema :as rsc] + [reitit.coercion.schema :as rcs] + [reitit.coercion.malli :as rcm] [reitit.frontend.test-utils :refer [capture-console]])) (defn m [x] (assoc x :data nil :result nil)) +(defn decode-form [s] + ;; RFC 6749 4.2.2 specifies OAuth token response uses + ;; form-urlencoded format to encode values in the fragment string. + ;; Use built-in JS function to decode. + ;; ring.util.codec/decode-form works on Clj. + (when s + (->> (.entries (js/URLSearchParams. s)) + (map (fn [[k v]] [(keyword k) v])) + (into {})))) + (deftest match-by-path-test (testing "simple" (let [router (r/router ["/" @@ -21,11 +32,11 @@ :data {:name ::frontpage} :path-params {} :query-params {} - :fragment-params {} :path "/" + :fragment nil :parameters {:query {} :path {} - :fragment {}}}) + :fragment nil}}) (rf/match-by-path router "/"))) (is (= "/" @@ -36,11 +47,11 @@ :data {:name ::foo} :path-params {} :query-params {} - :fragment-params {} :path "/foo" + :fragment nil :parameters {:query {} :path {} - :fragment {}}}) + :fragment nil}}) (rf/match-by-path router "/foo"))) (is (= (r/map->Match @@ -48,11 +59,11 @@ :data {:name ::foo} :path-params {} :query-params {:mode ["foo", "bar"]} - :fragment-params {} :path "/foo" + :fragment nil :parameters {:query {:mode ["foo", "bar"]} :path {} - :fragment {}}}) + :fragment nil}}) (rf/match-by-path router "/foo?mode=foo&mode=bar"))) (is (= "/foo" @@ -71,23 +82,19 @@ [":id" {:name ::foo :parameters {:path {:id s/Int} :query {(s/optional-key :mode) s/Keyword} - :fragment {(s/optional-key :access_token) s/Str - (s/optional-key :refresh_token) s/Str - (s/optional-key :expires_in) s/Int - (s/optional-key :provider_token) s/Str - (s/optional-key :token_type) s/Str}}}]] + :fragment (s/maybe s/Str)}}]] {:compile rc/compile-request-coercers - :data {:coercion rsc/coercion}})] + :data {:coercion rcs/coercion}})] (is (= (r/map->Match {:template "/:id" :path-params {:id "5"} :query-params {} - :fragment-params {} :path "/5" + :fragment nil :parameters {:query {} :path {:id 5} - :fragment {}}}) + :fragment nil}}) (m (rf/match-by-path router "/5")))) (is (= "/5" @@ -111,35 +118,27 @@ {:template "/:id" :path-params {:id "5"} :query-params {:mode "foo"} - :fragment-params {} :path "/5" + :fragment nil :parameters {:path {:id 5} :query {:mode :foo} - :fragment {}}}) + :fragment nil}}) (m (rf/match-by-path router "/5?mode=foo")))) (is (= "/5?mode=foo" (r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo})))) - (testing "fragment is read" + (testing "fragment string is read" (is (= (r/map->Match {:template "/:id" :path-params {:id "5"} :query-params {:mode "foo"} - :fragment-params {:access_token "foo" - :refresh_token "bar" - :provider_token "baz" - :token_type "bearer" - :expires_in "3600"} :path "/5" + :fragment "fragment" :parameters {:path {:id 5} :query {:mode :foo} - :fragment {:access_token "foo" - :refresh_token "bar" - :provider_token "baz" - :token_type "bearer" - :expires_in 3600}}}) - (m (rf/match-by-path router "/5?mode=foo#access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600"))))) + :fragment "fragment"}}) + (m (rf/match-by-path router "/5?mode=foo#fragment"))))) (testing "console warning about missing params" (is (= [{:type :warn @@ -151,4 +150,80 @@ (:messages (capture-console (fn [] - (rf/match-by-name! router ::foo {})))))))))) + (rf/match-by-name! router ::foo {}))))))))) + + (testing "malli coercion" + (let [router (r/router ["/" + [":id" {:name ::foo + :parameters {:path [:map + [:id :int]] + :query [:map + [:mode {:optional true} :keyword]] + :fragment [:maybe + [:map + {:decode/string decode-form} + [:access_token :string] + [:refresh_token :string] + [:expires_in :int] + [:provider_token :string] + [:token_type :string]]]}}]] + {:compile rc/compile-request-coercers + :data {:coercion rcm/coercion}})] + + (is (= (r/map->Match + {:template "/:id" + :path-params {:id "5"} + :query-params {} + :path "/5" + :fragment nil + :parameters {:query {} + :path {:id 5} + :fragment nil}}) + (m (rf/match-by-path router "/5")))) + + (is (= "/5" + (r/match->path (rf/match-by-name router ::foo {:id 5})))) + + (testing "coercion error" + (testing "throws without options" + (is (thrown? js/Error (m (rf/match-by-path router "/a"))))) + + (testing "thows and calles on-coercion-error" + (let [exception (atom nil) + match (atom nil)] + (is (thrown? js/Error (m (rf/match-by-path router "/a" {:on-coercion-error (fn [m e] + (reset! match m) + (reset! exception e))})))) + (is (= {:id "a"} (-> @match :path-params))) + (is (= {:id "a"} (-> @exception (ex-data) :value)))))) + + (testing "query param is read" + (is (= (r/map->Match + {:template "/:id" + :path-params {:id "5"} + :query-params {:mode "foo"} + :path "/5" + :fragment nil + :parameters {:path {:id 5} + :query {:mode :foo} + :fragment nil}}) + (m (rf/match-by-path router "/5?mode=foo")))) + + (is (= "/5?mode=foo" + (r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo})))) + + (testing "fragment string is read" + (is (= (r/map->Match + {:template "/:id" + :path-params {:id "5"} + :query-params {:mode "foo"} + :path "/5" + :fragment "access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600" + :parameters {:path {:id 5} + :query {:mode :foo} + :fragment {:access_token "foo" + :refresh_token "bar" + :provider_token "baz" + :token_type "bearer" + :expires_in 3600}}}) + (m (rf/match-by-path router "/5?mode=foo#access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600")))))))) From 47f1ee0c8407cdc6a6dbf7bf58b6eb682531a3f7 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Tue, 21 Feb 2023 15:17:00 +0200 Subject: [PATCH 5/7] 0.6.0 --- CHANGELOG.md | 6 ++- README.md | 2 +- doc/README.md | 2 +- doc/basics/error_messages.md | 2 +- doc/http/default_interceptors.md | 2 +- doc/http/interceptors.md | 2 +- doc/http/pedestal.md | 6 +-- doc/http/sieppari.md | 2 +- doc/http/transforming_interceptor_chain.md | 2 +- doc/ring/default_middleware.md | 2 +- doc/ring/exceptions.md | 2 +- doc/ring/ring.md | 2 +- doc/ring/swagger.md | 4 +- doc/ring/transforming_middleware_chain.md | 2 +- examples/buddy-auth/project.clj | 2 +- examples/frontend-auth/project.clj | 6 +-- examples/frontend-controllers/project.clj | 6 +-- examples/frontend-links/project.clj | 6 +-- examples/frontend-prompt/project.clj | 6 +-- examples/frontend-re-frame/project.clj | 2 +- examples/frontend/project.clj | 6 +-- examples/http-swagger/project.clj | 2 +- examples/http/project.clj | 2 +- examples/just-coercion-with-ring/project.clj | 2 +- examples/pedestal-malli-swagger/project.clj | 6 +-- examples/pedestal-swagger/project.clj | 4 +- examples/pedestal/project.clj | 4 +- examples/ring-example/project.clj | 2 +- examples/ring-integrant/project.clj | 2 +- examples/ring-malli-lite-swagger/project.clj | 2 +- examples/ring-malli-swagger/project.clj | 2 +- examples/ring-spec-swagger/project.clj | 2 +- examples/ring-swagger/project.clj | 2 +- modules/reitit-core/project.clj | 2 +- modules/reitit-dev/project.clj | 2 +- modules/reitit-frontend/project.clj | 2 +- modules/reitit-http/project.clj | 2 +- modules/reitit-interceptors/project.clj | 2 +- modules/reitit-malli/project.clj | 2 +- modules/reitit-middleware/project.clj | 2 +- modules/reitit-pedestal/project.clj | 2 +- modules/reitit-ring/project.clj | 2 +- modules/reitit-schema/project.clj | 2 +- modules/reitit-sieppari/project.clj | 2 +- modules/reitit-spec/project.clj | 2 +- modules/reitit-swagger-ui/project.clj | 2 +- modules/reitit-swagger/project.clj | 2 +- modules/reitit/project.clj | 2 +- project.clj | 40 ++++++++++---------- 49 files changed, 89 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69ef1f07..ea6d6b20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,10 @@ We use [Break Versioning][breakver]. The version numbers follow a `.. Date: Tue, 21 Feb 2023 15:54:52 +0200 Subject: [PATCH 6/7] updated release guide --- doc/development.md | 2 +- project.clj | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/development.md b/doc/development.md index b0721609..1f418649 100644 --- a/doc/development.md +++ b/doc/development.md @@ -49,7 +49,7 @@ git tag 1.0.0 lein test # deploy to clojars -./scripts/lein-modules do clean, deploy clojars +CLOJARS_USERNAME=*** CLOJARS_PASSWORD=*** ./scripts/lein-modules do clean, deploy clojars # push the commit and the tag git push diff --git a/project.clj b/project.clj index a74fd71d..2a18a737 100644 --- a/project.clj +++ b/project.clj @@ -4,7 +4,10 @@ :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :test-paths ["test/clj" "test/cljc"] - :deploy-repositories [["releases" :clojars]] + :deploy-repositories {"clojars" {:url "https://repo.clojars.org" + :sign-releases false + :username :env/clojars_username + :password :env/clojars_password}} :codox {:output-path "doc" :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} From aec611f8b797015c88c999a46a1defe92a8d93a0 Mon Sep 17 00:00:00 2001 From: kimmoahola <28525546+kimmoahola@users.noreply.github.com> Date: Wed, 22 Feb 2023 13:11:46 +0200 Subject: [PATCH 7/7] Fix date of version 0.6.0 --- CHANGELOG.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea6d6b20..9e604aa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ We use [Break Versioning][breakver]. The version numbers follow a `. {:status 400, :body {:errors {:x ["missing required key"]}}} ``` @@ -347,13 +347,13 @@ is called the first time, so that `rfe/push-state` and such can be called * `reitit.ring/routes` strips away `nil` routes, fixes [#394](https://github.com/metosin/reitit/issues/394) * `reitit.ring/create-file-handler` to serve files from filesystem, fixes [#395](https://github.com/metosin/reitit/issues/395) -* **BREAKING**: router option `:reitit.ring/default-options-handler` is deprecated +* **BREAKING**: router option `:reitit.ring/default-options-handler` is deprecated * fails with router creation time error * use `:reitit.ring/default-options-endpoint` instead, takes an expandable route data instead just of a handler. ### `reitit-http` -* **BREAKING**: router option `:reitit.http/default-options-handler` is deprecated +* **BREAKING**: router option `:reitit.http/default-options-handler` is deprecated * fails with router creation time error * use `:reitit.http/default-options-endpoint` instead, takes an expandable route data instead just of a handler. @@ -432,7 +432,7 @@ is called the first time, so that `rfe/push-state` and such can be called * **BREAKING**: Decode multi-valued query params correctly into seqs (e.g. `foo=bar&foo=baz` ↦ `{:foo ["bar", "baz"]}`). * Previously you'd get only the first value. (e.g. `foo=bar&foo=baz` ↦ `{:foo "bar"}`) - + ### `reitit-ring` * **BREAKING**: New validation rule: `:middleware` must be a vector, not a list. Fixes [#296](https://github.com/metosin/reitit/issues/296). ([#319](https://github.com/metosin/reitit/pull/319) by [Daw-Ran Liou](https://github.com/dawran6)) @@ -550,23 +550,23 @@ is called the first time, so that `rfe/push-state` and such can be called {:parameters {:body [s/Str]}}]] {:exception pretty/exception}) ; -- Router creation failed -------------------------------------------- user:7 -- -; +; ; Error merging route-data: -; +; ; -- On route ----------------------- -; +; ; /kikka/kakka -; +; ; -- Exception ---------------------- -; +; ; Don't know how to create ISeq from: java.lang.Class -; +; ; {:parameters {:body {:id java.lang.String}}} -; +; ; {:parameters {:body [java.lang.String]}} -; +; ; https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-data -; +; ; -------------------------------------------------------------------------------- ``` @@ -585,7 +585,7 @@ is called the first time, so that `rfe/push-state` and such can be called ### `reitit-core` -* new options `:reitit.spec/wrap` to wrap top-level route data specs when spec validation is enabled. Using `spec-tools.spell/closed` closes top-level specs. +* new options `:reitit.spec/wrap` to wrap top-level route data specs when spec validation is enabled. Using `spec-tools.spell/closed` closes top-level specs. * Updated swagger-examples to easily enable closed spec validation ```clj @@ -650,9 +650,9 @@ is called the first time, so that `rfe/push-state` and such can be called * new module for friendly router creation time exception handling * new option `:exception` in `r/router`, of type `Exception => Exception` (default `reitit.exception/exception`) * new exception pretty-printer `reitit.dev.pretty/exception`, based on [fipp](https://github.com/brandonbloom/fipp) and [expound](https://github.com/bhb/expound) for human readable, newbie-friendly errors. - + #### Conflicting paths - + ```clj (require '[reitit.core :as r]) (require '[reitit.dev.pretty :as pretty])