mirror of
https://github.com/metosin/reitit.git
synced 2025-12-16 16:01:11 +00:00
:params => :path-params
This commit is contained in:
parent
9f60b2f56d
commit
54b24be28e
15 changed files with 78 additions and 79 deletions
|
|
@ -46,14 +46,14 @@ Optionally, the parts can be required separately:
|
|||
; #Match{:template "/api/ping"
|
||||
; :data {:name ::ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/api/ping"}
|
||||
|
||||
(r/match-by-name router ::order {:id 2})
|
||||
; #Match{:template "/api/orders/:id",
|
||||
; :data {:name ::order},
|
||||
; :result nil,
|
||||
; :params {:id 2},
|
||||
; :path-params {:id 2},
|
||||
; :path "/api/orders/2"}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -53,14 +53,14 @@ Routing:
|
|||
; #Match{:template "/api/ping"
|
||||
; :data {:name ::ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/api/ping"}
|
||||
|
||||
(r/match-by-path router "/api/orders/1")
|
||||
; #Match{:template "/api/orders/:id"
|
||||
; :data {:name ::order-by-id}
|
||||
; :result nil
|
||||
; :params {:id "1"}
|
||||
; :path-params {:id "1"}
|
||||
; :path "/api/orders/1"}
|
||||
```
|
||||
|
||||
|
|
@ -74,14 +74,14 @@ Reverse-routing:
|
|||
; #Match{:template "/api/ping"
|
||||
; :data {:name ::ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/api/ping"}
|
||||
|
||||
(r/match-by-name router ::order-by-id)
|
||||
; #PartialMatch{:template "/api/orders/:id"
|
||||
; :data {:name :user/order-by-id}
|
||||
; :result nil
|
||||
; :params nil
|
||||
; :path-params nil
|
||||
; :required #{:id}}
|
||||
|
||||
(r/partial-match? (r/match-by-name router ::order-by-id))
|
||||
|
|
@ -91,7 +91,7 @@ Reverse-routing:
|
|||
; #Match{:template "/api/orders/:id",
|
||||
; :data {:name ::order-by-id},
|
||||
; :result nil,
|
||||
; :params {:id 2},
|
||||
; :path-params {:id 2},
|
||||
; :path "/api/orders/2"}
|
||||
```
|
||||
|
||||
|
|
@ -141,6 +141,6 @@ Reverse-routing:
|
|||
; :get {:handler #object[user$handler]}
|
||||
; :name ::ping}
|
||||
; :result #Methods{...}
|
||||
; :params nil
|
||||
; :path-params nil
|
||||
; :path "/api/ping"}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Matching a route:
|
|||
; #Match{:template "/api/ping"
|
||||
; :data {:name :user/ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/api/ping"}
|
||||
```
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ If not all path-parameters are set, a `PartialMatch` is returned:
|
|||
; #PartialMatch{:template "/api/user/:id",
|
||||
; :data {:name :user/user},
|
||||
; :result nil,
|
||||
; :params nil,
|
||||
; :path-params nil,
|
||||
; :required #{:id}}
|
||||
|
||||
(r/partial-match? (r/match-by-name router ::user))
|
||||
|
|
@ -61,7 +61,7 @@ With provided path-parameters:
|
|||
; :data {:name :user/user}
|
||||
; :path "/api/user/1"
|
||||
; :result nil
|
||||
; :params {:id "1"}}
|
||||
; :path-params {:id "1"}}
|
||||
```
|
||||
|
||||
There is also a exception throwing version:
|
||||
|
|
|
|||
|
|
@ -33,5 +33,5 @@ Match provides the route information:
|
|||
; :data {:name :user/user}
|
||||
; :path "/api/user/1"
|
||||
; :result nil
|
||||
; :params {:id "1"}}
|
||||
; :path-params {:id "1"}}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ The expanded route data can be retrieved from a router with `routes` and is retu
|
|||
; #Match{:template "/ping"
|
||||
; :data {:name :user/ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/ping"}
|
||||
|
||||
(r/match-by-name router ::ping)
|
||||
; #Match{:template "/ping"
|
||||
; :data {:name :user/ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/ping"}
|
||||
```
|
||||
|
||||
|
|
@ -92,6 +92,6 @@ By default, `reitit/Expand` protocol is used to expand the route arguments. It e
|
|||
; #Match{:template "/ping"
|
||||
; :data {:name :user/ping}
|
||||
; :result nil
|
||||
; :params {}
|
||||
; :path-params {}
|
||||
; :path "/ping"}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Successful coercion:
|
|||
; :coercion <<:spec>>
|
||||
; :parameters {:path ::path-params}},
|
||||
; :result {:path #object[reitit.coercion$request_coercer$]},
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :parameters {:path {:company "metosin", :user-id 123}}
|
||||
; :path "/metosin/users/123"}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Match with the parsed `:params` as Strings:
|
|||
; #Match{:template "/:company/users/:user-id",
|
||||
; :data {:name :user/user-view},
|
||||
; :result nil,
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :path "/metosin/users/123"}
|
||||
```
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ A Match:
|
|||
; :parameters {:path {:company java.lang.String,
|
||||
; :user-id Int}}},
|
||||
; :result nil,
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :path "/metosin/users/123"}
|
||||
```
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ Routing again:
|
|||
; :parameters {:path {:company java.lang.String,
|
||||
; :user-id Int}}},
|
||||
; :result {:path #object[reitit.coercion$request_coercer$]},
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :path "/metosin/users/123"}
|
||||
```
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ Here's an full example for doing routing and coercion with Reitit and Schema:
|
|||
; :parameters {:path {:company java.lang.String,
|
||||
; :user-id Int}}},
|
||||
; :result {:path #object[reitit.coercion$request_coercer$]},
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :parameters {:path {:company "metosin", :user-id 123}}
|
||||
; :path "/metosin/users/123"}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Successful coercion:
|
|||
; :parameters {:path {:company string?,
|
||||
; :user-id int?}}},
|
||||
; :result {:path #object[reitit.coercion$request_coercer$]},
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :parameters {:path {:company "metosin", :user-id 123}}
|
||||
; :path "/metosin/users/123"}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Successful coercion:
|
|||
; :parameters {:path {:company java.lang.String,
|
||||
; :user-id Int}}},
|
||||
; :result {:path #object[reitit.coercion$request_coercer$]},
|
||||
; :params {:company "metosin", :user-id "123"},
|
||||
; :path-params {:company "metosin", :user-id "123"},
|
||||
; :parameters {:path {:company "metosin", :user-id 123}}
|
||||
; :path "/metosin/users/123"}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -157,4 +157,4 @@
|
|||
If coercion or parameters are not defined, return `nil`"
|
||||
[match]
|
||||
(if-let [result (:result match)]
|
||||
(coerce-request result {:path-params (:params match)})))
|
||||
(coerce-request result {:path-params (:path-params match)})))
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@
|
|||
(into [] (keep #(compile-route % opts) routes)))
|
||||
|
||||
(defn route-info [route]
|
||||
(select-keys (impl/create route) [:path :parts :params :result :data]))
|
||||
(select-keys (impl/create route) [:path :parts :path-params :result :data]))
|
||||
|
||||
(defprotocol Router
|
||||
(router-name [this])
|
||||
|
|
@ -108,13 +108,13 @@
|
|||
(options [this])
|
||||
(route-names [this])
|
||||
(match-by-path [this path])
|
||||
(match-by-name [this name] [this name params]))
|
||||
(match-by-name [this name] [this name path-params]))
|
||||
|
||||
(defn router? [x]
|
||||
(satisfies? Router x))
|
||||
|
||||
(defrecord Match [template data result params path])
|
||||
(defrecord PartialMatch [template data result params required])
|
||||
(defrecord Match [template data result path-params path])
|
||||
(defrecord PartialMatch [template data result path-params required])
|
||||
|
||||
(defn partial-match? [x]
|
||||
(instance? PartialMatch x))
|
||||
|
|
@ -122,12 +122,12 @@
|
|||
(defn match-by-name!
|
||||
([this name]
|
||||
(match-by-name! this name nil))
|
||||
([this name params]
|
||||
(if-let [match (match-by-name this name params)]
|
||||
([this name path-params]
|
||||
(if-let [match (match-by-name this name path-params)]
|
||||
(if-not (partial-match? match)
|
||||
match
|
||||
(impl/throw-on-missing-path-params
|
||||
(:template match) (:required match) params)))))
|
||||
(:template match) (:required match) path-params)))))
|
||||
|
||||
(def default-router-options
|
||||
{:lookup name-lookup
|
||||
|
|
@ -145,10 +145,10 @@
|
|||
(let [names (find-names routes opts)
|
||||
[pl nl] (reduce
|
||||
(fn [[pl nl] [p {:keys [name] :as data} result]]
|
||||
(let [{:keys [params] :as route} (impl/create [p data result])
|
||||
(let [{:keys [path-params] :as route} (impl/create [p data result])
|
||||
f #(if-let [path (impl/path-for route %)]
|
||||
(->Match p data result % path)
|
||||
(->PartialMatch p data result % params))]
|
||||
(->PartialMatch p data result % path-params))]
|
||||
[(conj pl route)
|
||||
(if name (assoc nl name f) nl)]))
|
||||
[[] {}] routes)
|
||||
|
|
@ -166,16 +166,16 @@
|
|||
names)
|
||||
(match-by-path [_ path]
|
||||
(reduce
|
||||
(fn [acc ^Route route]
|
||||
(if-let [params ((:matcher route) path)]
|
||||
(reduced (->Match (:path route) (:data route) (:result route) params path))))
|
||||
(fn [_ ^Route route]
|
||||
(if-let [path-params ((:matcher route) path)]
|
||||
(reduced (->Match (:path route) (:data route) (:result route) path-params path))))
|
||||
nil pl))
|
||||
(match-by-name [_ name]
|
||||
(if-let [match (impl/fast-get lookup name)]
|
||||
(match nil)))
|
||||
(match-by-name [_ name params]
|
||||
(match-by-name [_ name path-params]
|
||||
(if-let [match (impl/fast-get lookup name)]
|
||||
(match params)))))))
|
||||
(match path-params)))))))
|
||||
|
||||
(defn lookup-router
|
||||
"Creates a lookup-router from resolved routes and optional
|
||||
|
|
@ -213,9 +213,9 @@
|
|||
(match-by-name [_ name]
|
||||
(if-let [match (impl/fast-get lookup name)]
|
||||
(match nil)))
|
||||
(match-by-name [_ name params]
|
||||
(match-by-name [_ name path-params]
|
||||
(if-let [match (impl/fast-get lookup name)]
|
||||
(match params)))))))
|
||||
(match path-params)))))))
|
||||
|
||||
(defn segment-router
|
||||
"Creates a special prefix-tree style segment router from resolved routes and optional
|
||||
|
|
@ -226,10 +226,10 @@
|
|||
(let [names (find-names routes opts)
|
||||
[pl nl] (reduce
|
||||
(fn [[pl nl] [p {:keys [name] :as data} result]]
|
||||
(let [{:keys [params] :as route} (impl/create [p data result])
|
||||
(let [{:keys [path-params] :as route} (impl/create [p data result])
|
||||
f #(if-let [path (impl/path-for route %)]
|
||||
(->Match p data result % path)
|
||||
(->PartialMatch p data result % params))]
|
||||
(->PartialMatch p data result % path-params))]
|
||||
[(segment/insert pl p (->Match p data result nil nil))
|
||||
(if name (assoc nl name f) nl)]))
|
||||
[nil {}] routes)
|
||||
|
|
@ -248,14 +248,14 @@
|
|||
(match-by-path [_ path]
|
||||
(if-let [match (segment/lookup pl path)]
|
||||
(-> (:data match)
|
||||
(assoc :params (:params match))
|
||||
(assoc :path-params (:path-params match))
|
||||
(assoc :path path))))
|
||||
(match-by-name [_ name]
|
||||
(if-let [match (impl/fast-get lookup name)]
|
||||
(match nil)))
|
||||
(match-by-name [_ name params]
|
||||
(match-by-name [_ name path-params]
|
||||
(if-let [match (impl/fast-get lookup name)]
|
||||
(match params)))))))
|
||||
(match path-params)))))))
|
||||
|
||||
(defn single-static-path-router
|
||||
"Creates a fast router of 1 static route(s) and optional
|
||||
|
|
@ -288,9 +288,9 @@
|
|||
(match-by-name [_ name]
|
||||
(if (= n name)
|
||||
match))
|
||||
(match-by-name [_ name params]
|
||||
(match-by-name [_ name path-params]
|
||||
(if (= n name)
|
||||
(impl/fast-assoc match :params params)))))))
|
||||
(impl/fast-assoc match :path-params path-params)))))))
|
||||
|
||||
(defn mixed-router
|
||||
"Creates two routers: [[lookup-router]] or [[single-static-path-router]] for
|
||||
|
|
@ -321,9 +321,9 @@
|
|||
(match-by-name [_ name]
|
||||
(or (match-by-name static-router name)
|
||||
(match-by-name wildcard-router name)))
|
||||
(match-by-name [_ name params]
|
||||
(or (match-by-name static-router name params)
|
||||
(match-by-name wildcard-router name params)))))))
|
||||
(match-by-name [_ name path-params]
|
||||
(or (match-by-name static-router name path-params)
|
||||
(match-by-name wildcard-router name path-params)))))))
|
||||
|
||||
(defn router
|
||||
"Create a [[Router]] from raw route data and optionally an options map.
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@
|
|||
;; Routing (c) Metosin
|
||||
;;
|
||||
|
||||
(defrecord Route [path matcher parts params data result])
|
||||
(defrecord Route [path matcher parts path-params data result])
|
||||
|
||||
(defn create [[path data result]]
|
||||
(let [path #?(:clj (.intern ^String path) :cljs path)]
|
||||
|
|
@ -110,8 +110,7 @@
|
|||
:data data})
|
||||
(dissoc $ :path-re :path-constraints)
|
||||
(update $ :path-params set)
|
||||
(set/rename-keys $ {:path-parts :parts
|
||||
:path-params :params})
|
||||
(set/rename-keys $ {:path-parts :parts})
|
||||
(map->Route $))))
|
||||
|
||||
(defn wild-route? [[path]]
|
||||
|
|
@ -128,20 +127,20 @@
|
|||
(not= s1 s2) false
|
||||
:else (recur ss1 ss2))))
|
||||
|
||||
(defn path-for [^Route route params]
|
||||
(if-let [required (:params route)]
|
||||
(if (every? #(contains? params %) required)
|
||||
(str "/" (str/join \/ (map #(get (or params {}) % %) (:parts route)))))
|
||||
(defn path-for [^Route route path-params]
|
||||
(if-let [required (:path-params route)]
|
||||
(if (every? #(contains? path-params %) required)
|
||||
(str "/" (str/join \/ (map #(get (or path-params {}) % %) (:parts route)))))
|
||||
(:path route)))
|
||||
|
||||
(defn throw-on-missing-path-params [template required params]
|
||||
(when-not (every? #(contains? params %) required)
|
||||
(let [defined (-> params keys set)
|
||||
(defn throw-on-missing-path-params [template required path-params]
|
||||
(when-not (every? #(contains? path-params %) required)
|
||||
(let [defined (-> path-params keys set)
|
||||
missing (clojure.set/difference required defined)]
|
||||
(throw
|
||||
(ex-info
|
||||
(str "missing path-params for route " template " -> " missing)
|
||||
{:params params, :required required})))))
|
||||
{:path-params path-params, :required required})))))
|
||||
|
||||
(defn fast-assoc
|
||||
#?@(:clj [[^clojure.lang.Associative a k v] (.assoc a k v)]
|
||||
|
|
|
|||
|
|
@ -3,23 +3,23 @@
|
|||
(:require [reitit.impl :as impl]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defrecord Match [data params])
|
||||
(defrecord Match [data path-params])
|
||||
|
||||
(defprotocol Segment
|
||||
(-insert [this ps data])
|
||||
(-lookup [this ps params]))
|
||||
(-lookup [this ps path-params]))
|
||||
|
||||
(extend-protocol Segment
|
||||
nil
|
||||
(-insert [_ _ _])
|
||||
(-lookup [_ _ _]))
|
||||
|
||||
(defn- -catch-all [children catch-all params p ps]
|
||||
(defn- -catch-all [children catch-all path-params p ps]
|
||||
(if catch-all
|
||||
(-lookup
|
||||
(impl/fast-get children catch-all)
|
||||
nil
|
||||
(assoc params catch-all (str/join "/" (cons p ps))))))
|
||||
(assoc path-params catch-all (str/join "/" (cons p ps))))))
|
||||
|
||||
(defn- segment
|
||||
([] (segment {} #{} nil nil))
|
||||
|
|
@ -36,12 +36,12 @@
|
|||
catch-all (or c catch-all)
|
||||
children (update children (or w c p) #(-insert (or % (segment)) ps d))]
|
||||
(segment children wilds catch-all match))))
|
||||
(-lookup [_ [p & ps] params]
|
||||
(-lookup [_ [p & ps] path-params]
|
||||
(if (nil? p)
|
||||
(if match (assoc match :params params))
|
||||
(or (-lookup (impl/fast-get children' p) ps params)
|
||||
(some #(-lookup (impl/fast-get children' %) ps (assoc params % p)) wilds)
|
||||
(-catch-all children' catch-all params p ps))))))))
|
||||
(if match (assoc match :path-params path-params))
|
||||
(or (-lookup (impl/fast-get children' p) ps path-params)
|
||||
(some #(-lookup (impl/fast-get children' %) ps (assoc path-params % p)) wilds)
|
||||
(-catch-all children' catch-all path-params p ps))))))))
|
||||
|
||||
(defn insert [root path data]
|
||||
(-insert (or root (segment)) (impl/segments path) (map->Match {:data data})))
|
||||
|
|
|
|||
|
|
@ -62,12 +62,12 @@
|
|||
([request]
|
||||
(if-let [match (r/match-by-path router (:uri request))]
|
||||
(let [method (:request-method request :any)
|
||||
params (:params match)
|
||||
path-params (:path-params match)
|
||||
result (:result match)
|
||||
handler (or (-> result method :handler)
|
||||
(-> result :any (:handler default-handler)))
|
||||
request (cond-> (impl/fast-assoc request ::match match)
|
||||
(seq params) (impl/fast-assoc :path-params params))
|
||||
(seq path-params) (impl/fast-assoc :path-params path-params))
|
||||
response (handler request)]
|
||||
(if (nil? response)
|
||||
(default-handler request)
|
||||
|
|
@ -76,12 +76,12 @@
|
|||
([request respond raise]
|
||||
(if-let [match (r/match-by-path router (:uri request))]
|
||||
(let [method (:request-method request :any)
|
||||
params (:params match)
|
||||
path-params (:path-params match)
|
||||
result (:result match)
|
||||
handler (or (-> result method :handler)
|
||||
(-> result :any (:handler default-handler)))
|
||||
request (cond-> (impl/fast-assoc request ::match match)
|
||||
(seq params) (impl/fast-assoc :path-params params))]
|
||||
(seq path-params) (impl/fast-assoc :path-params path-params))]
|
||||
(handler request respond raise))
|
||||
(default-handler request respond raise))))
|
||||
{::router router}))))
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@
|
|||
{:template "/api/ipa/:size"
|
||||
:data {:name ::beer}
|
||||
:path "/api/ipa/large"
|
||||
:params {:size "large"}})
|
||||
:path-params {:size "large"}})
|
||||
(r/match-by-path router "/api/ipa/large")))
|
||||
(is (= (r/map->Match
|
||||
{:template "/api/ipa/:size"
|
||||
:data {:name ::beer}
|
||||
:path "/api/ipa/large"
|
||||
:params {:size "large"}})
|
||||
:path-params {:size "large"}})
|
||||
(r/match-by-name router ::beer {:size "large"})))
|
||||
(is (= nil (r/match-by-name router "ILLEGAL")))
|
||||
(is (= [::beer] (r/route-names router)))
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
{:template "/api/ipa/:size"
|
||||
:data {:name ::beer}
|
||||
:required #{:size}
|
||||
:params nil})
|
||||
:path-params nil})
|
||||
(r/match-by-name router ::beer)))
|
||||
(is (r/partial-match? (r/match-by-name router ::beer)))
|
||||
(is (thrown-with-msg?
|
||||
|
|
@ -77,13 +77,13 @@
|
|||
{:template "/api/ipa/large"
|
||||
:data {:name ::beer}
|
||||
:path "/api/ipa/large"
|
||||
:params {}})
|
||||
:path-params {}})
|
||||
(r/match-by-path router "/api/ipa/large")))
|
||||
(is (= (r/map->Match
|
||||
{:template "/api/ipa/large"
|
||||
:data {:name ::beer}
|
||||
:path "/api/ipa/large"
|
||||
:params {:size "large"}})
|
||||
:path-params {:size "large"}})
|
||||
(r/match-by-name router ::beer {:size "large"})))
|
||||
(is (= nil (r/match-by-name router "ILLEGAL")))
|
||||
(is (= [::beer] (r/route-names router)))
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
{:template "/api/user/:id/:sub-id"
|
||||
:data {:mw [:api], :parameters {:id "String", :sub-id "String"}}
|
||||
:path "/api/user/1/2"
|
||||
:params {:id "1", :sub-id "2"}})
|
||||
:path-params {:id "1", :sub-id "2"}})
|
||||
(r/match-by-path router "/api/user/1/2"))))))
|
||||
|
||||
(deftest conflicting-routes-test
|
||||
|
|
|
|||
Loading…
Reference in a new issue