diff --git a/CHANGELOG.md b/CHANGELOG.md index efbe5726..f48d0ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,24 @@ We use [Break Versioning][breakver]. The version numbers follow a `. (r/router + ["http://localhost:8080/api/user/{id}" ::user-by-id] + {:syntax :bracket}) + (r/match-by-path "http://localhost:8080/api/user/123")) +;#Match{:template "http://localhost:8080/api/user/{id}", +; :data {:name :user/user-by-id}, +; :result nil, +; :path-params {:id "123"}, +; :path "http://localhost:8080/api/user/123"} +``` + ## 0.3.7 (2019-05-25) ### `reitit-pedestal` diff --git a/doc/advanced/configuring_routers.md b/doc/advanced/configuring_routers.md index b624355d..4cc30be9 100644 --- a/doc/advanced/configuring_routers.md +++ b/doc/advanced/configuring_routers.md @@ -2,12 +2,13 @@ Routers can be configured via options. The following options are available for the `reitit.core/router`: -| key | description | -|--------------|-------------| +| key | description +|--------------|------------- | `:path` | Base-path for routes | `:routes` | Initial resolved routes (default `[]`) | `:data` | Initial route data (default `{}`) | `:spec` | clojure.spec definition for a route data, see `reitit.spec` on how to use this +| `:syntax` | Path-parameter syntax as keyword or set of keywords (default #{:bracket :colon}) | `:expand` | Function of `arg opts => data` to expand route arg to route data (default `reitit.core/expand`) | `:coerce` | Function of `route opts => route` to coerce resolved route, can throw or return `nil` | `:compile` | Function of `route opts => result` to compile a route handler diff --git a/doc/basics/route_syntax.md b/doc/basics/route_syntax.md index bca58569..3794a2d7 100644 --- a/doc/basics/route_syntax.md +++ b/doc/basics/route_syntax.md @@ -4,7 +4,7 @@ Routes are defined as vectors of String path and optional (non-sequential) route Routes can be wrapped in vectors and lists and `nil` routes are ignored. -Paths can have path-parameters (`:id`) or catch-all-parameters (`*path`). Since version `0.3.0`, parameters can also be wrapped in brackets, enabling use of qualified keywords `{user/id}`, `{*user/path}`. The non-bracket syntax might be deprecated later. +Paths can have path-parameters (`:id`) or catch-all-parameters (`*path`). Parameters can also be wrapped in brackets, enabling use of qualified keywords `{user/id}`, `{*user/path}`. By default, both syntaxes are supported, see [configuring routers](../advanced/configuring_routers.md) on how to change this. ### Examples @@ -129,3 +129,23 @@ Routes are just data, so it's easy to create them programmatically: ; ["/add-user" {:post {:interceptors [add-user]}}] ; ["/add-order" {:post {:interceptors [add-order]}}])] ``` + +### Explicit path-parameter syntax + +Router options `:syntax` allows the path-parameter syntax to be explicitely defined. It takes a keyword or set of keywords as a value. Valid values are `:colon` and `:bracket`. Default value is `#{:colon :bracket}`. + +Supporting only `:bracket` syntax: + +```clj +(require '[reitit.core :as r]) + +(-> (r/router + ["http://localhost:8080/api/user/{id}" ::user-by-id] + {:syntax :bracket}) + (r/match-by-path "http://localhost:8080/api/user/123")) +;#Match{:template "http://localhost:8080/api/user/{id}", +; :data {:name :user/user-by-id}, +; :result nil, +; :path-params {:id "123"}, +; :path "http://localhost:8080/api/user/123"} +``` diff --git a/modules/reitit-core/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc index 3aafa718..26f61ab5 100644 --- a/modules/reitit-core/src/reitit/core.cljc +++ b/modules/reitit-core/src/reitit/core.cljc @@ -347,12 +347,13 @@ Selects implementation based on route details. The following options are available: - | key | description | - | -------------|-------------| + | key | description + | -------------|------------- | `:path` | Base-path for routes | `:routes` | Initial resolved routes (default `[]`) | `:data` | Initial route data (default `{}`) | `:spec` | clojure.spec definition for a route data, see `reitit.spec` on how to use this + | `:syntax` | Path-parameter syntax as keyword or set of keywords (default #{:bracket :colon}) | `:expand` | Function of `arg opts => data` to expand route arg to route data (default `reitit.core/expand`) | `:coerce` | Function of `route opts => route` to coerce resolved route, can throw or return `nil` | `:compile` | Function of `route opts => result` to compile a route handler diff --git a/modules/reitit-core/src/reitit/trie.cljc b/modules/reitit-core/src/reitit/trie.cljc index 99d13960..6eaa417f 100644 --- a/modules/reitit-core/src/reitit/trie.cljc +++ b/modules/reitit-core/src/reitit/trie.cljc @@ -57,9 +57,9 @@ (keyword (subs s 0 i) (subs s (inc i))) (keyword s))) -(defn split-path [s {:keys [parameter-syntax] :or {parameter-syntax #{:bracket :colon}}}] - (let [bracket? (-> parameter-syntax (into-set) :bracket) - colon? (-> parameter-syntax (into-set) :colon) +(defn split-path [s {:keys [syntax] :or {syntax #{:bracket :colon}}}] + (let [bracket? (-> syntax (into-set) :bracket) + colon? (-> syntax (into-set) :colon) -static (fn [from to] (if-not (= from to) [(subs s from to)])) -wild (fn [from to] [(->Wild (-keyword (subs s (inc from) to)))]) -catch-all (fn [from to] [(->CatchAll (keyword (subs s (inc from) to)))])] diff --git a/test/cljc/reitit/trie_test.cljc b/test/cljc/reitit/trie_test.cljc index b68e455b..7eca95fe 100644 --- a/test/cljc/reitit/trie_test.cljc +++ b/test/cljc/reitit/trie_test.cljc @@ -31,9 +31,9 @@ (deftest split-path-test (testing "colon" - (doseq [parameter-syntax [:colon #{:colon}]] + (doseq [syntax [:colon #{:colon}]] (are [path expected] - (is (= expected (trie/split-path path {:parameter-syntax parameter-syntax}))) + (is (= expected (trie/split-path path {:syntax syntax}))) "/olipa/:kerran/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"] "/olipa/{kerran}/avaruus", ["/olipa/{kerran}/avaruus"] @@ -43,9 +43,9 @@ "/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/{" (trie/->CatchAll (keyword "valtavan.suuri/avaruus}"))]))) (testing "bracket" - (doseq [parameter-syntax [:bracket #{:bracket}]] + (doseq [syntax [:bracket #{:bracket}]] (are [path expected] - (is (= expected (trie/split-path path {:parameter-syntax parameter-syntax}))) + (is (= expected (trie/split-path path {:syntax syntax}))) "/olipa/:kerran/avaruus", ["/olipa/:kerran/avaruus"] "/olipa/{kerran}/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"] @@ -55,9 +55,9 @@ "/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/" (trie/->CatchAll :valtavan.suuri/avaruus)]))) (testing "both" - (doseq [parameter-syntax [#{:bracket :colon}]] + (doseq [syntax [#{:bracket :colon}]] (are [path expected] - (is (= expected (trie/split-path path {:parameter-syntax parameter-syntax}))) + (is (= expected (trie/split-path path {:syntax syntax}))) "/olipa/:kerran/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"] "/olipa/{kerran}/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"] @@ -67,9 +67,9 @@ "/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/" (trie/->CatchAll :valtavan.suuri/avaruus)]))) (testing "nil" - (doseq [parameter-syntax [nil]] + (doseq [syntax [nil]] (are [path expected] - (is (= expected (trie/split-path path {:parameter-syntax parameter-syntax}))) + (is (= expected (trie/split-path path {:syntax syntax}))) "/olipa/:kerran/avaruus", ["/olipa/:kerran/avaruus"] "/olipa/{kerran}/avaruus", ["/olipa/{kerran}/avaruus"]