mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 16:31:11 +00:00
Validate routes for duplicates (fixes #23)
This commit is contained in:
parent
0befddf72c
commit
851e35ef52
3 changed files with 60 additions and 1 deletions
|
|
@ -60,6 +60,12 @@
|
||||||
(cond->> (->> (walk data opts) (map-meta merge-meta))
|
(cond->> (->> (walk data opts) (map-meta merge-meta))
|
||||||
coerce (into [] (keep #(coerce % opts)))))
|
coerce (into [] (keep #(coerce % opts)))))
|
||||||
|
|
||||||
|
(defn first-conflicting-routes [routes]
|
||||||
|
(loop [[r & rest] routes]
|
||||||
|
(if (seq rest)
|
||||||
|
(or (some #(if (impl/conflicting-routes? r %) [r %]) rest)
|
||||||
|
(recur rest)))))
|
||||||
|
|
||||||
(defn name-lookup [[_ {:keys [name]}] opts]
|
(defn name-lookup [[_ {:keys [name]}] opts]
|
||||||
(if name #{name}))
|
(if name #{name}))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,25 @@
|
||||||
:matcher #(if (= path %) {})
|
:matcher #(if (= path %) {})
|
||||||
:handler handler})))
|
:handler handler})))
|
||||||
|
|
||||||
|
(defn segments [path]
|
||||||
|
(let [ss (-> (str/split path #"/") rest vec)]
|
||||||
|
(if (str/ends-with? path "/")
|
||||||
|
(conj ss "") ss)))
|
||||||
|
|
||||||
|
(defn- catch-all? [segment]
|
||||||
|
(= \* (first segment)))
|
||||||
|
|
||||||
|
(defn conflicting-routes? [[p1 :as route1] [p2 :as route2]]
|
||||||
|
(loop [[s1 & ss1] (segments p1)
|
||||||
|
[s2 & ss2] (segments p2)]
|
||||||
|
(cond
|
||||||
|
(= s1 s2 nil) true
|
||||||
|
(or (nil? s1) (nil? s2)) false
|
||||||
|
(or (catch-all? s1) (catch-all? s2)) true
|
||||||
|
(or (wild? s1) (wild? s2)) (recur ss1 ss2)
|
||||||
|
(not= s1 s2) false
|
||||||
|
:else (recur ss1 ss2))))
|
||||||
|
|
||||||
(defn path-for [^Route route params]
|
(defn path-for [^Route route params]
|
||||||
(if-let [required (:params route)]
|
(if-let [required (:params route)]
|
||||||
(if (every? #(contains? params %) required)
|
(if (every? #(contains? params %) required)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(ns reitit.core-test
|
(ns reitit.core-test
|
||||||
(:require [clojure.test :refer [deftest testing is]]
|
(:require [clojure.test :refer [deftest testing is are]]
|
||||||
[reitit.core :as reitit #?@(:cljs [:refer [Match]])])
|
[reitit.core :as reitit #?@(:cljs [:refer [Match]])])
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(:import (reitit.core Match)
|
(:import (reitit.core Match)
|
||||||
|
|
@ -138,3 +138,37 @@
|
||||||
:path "/api/user/1/2"
|
:path "/api/user/1/2"
|
||||||
:params {:id "1", :sub-id "2"}})
|
:params {:id "1", :sub-id "2"}})
|
||||||
(reitit/match-by-path router "/api/user/1/2"))))))
|
(reitit/match-by-path router "/api/user/1/2"))))))
|
||||||
|
|
||||||
|
(deftest first-conflicting-routes-test
|
||||||
|
(are [conflicting? data]
|
||||||
|
(let [routes (reitit/resolve-routes data {})]
|
||||||
|
(= (if conflicting? routes)
|
||||||
|
(reitit/first-conflicting-routes
|
||||||
|
(reitit/resolve-routes routes {}))))
|
||||||
|
|
||||||
|
true [["/a"]
|
||||||
|
["/a"]]
|
||||||
|
|
||||||
|
true [["/a"]
|
||||||
|
["/:b"]]
|
||||||
|
|
||||||
|
true [["/a"]
|
||||||
|
["/*b"]]
|
||||||
|
|
||||||
|
true [["/a/1/2"]
|
||||||
|
["/*b"]]
|
||||||
|
|
||||||
|
false [["/a"]
|
||||||
|
["/a/"]]
|
||||||
|
|
||||||
|
false [["/a"]
|
||||||
|
["/a/1"]]
|
||||||
|
|
||||||
|
false [["/a"]
|
||||||
|
["/a/:b"]]
|
||||||
|
|
||||||
|
false [["/a"]
|
||||||
|
["/a/*b"]]
|
||||||
|
|
||||||
|
true [["/v2/public/messages/dataset/bulk"]
|
||||||
|
["/v2/public/messages/dataset/:dataset-id"]]))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue