mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 16:31:11 +00:00
Fast-router if only 1 static path.
* 200x faster on basic benchmark than the slowest one
This commit is contained in:
parent
254908b70b
commit
e9c0639914
3 changed files with 131 additions and 17 deletions
|
|
@ -66,9 +66,48 @@
|
||||||
["/auth/recovery/token/:token" :auth/recovery]
|
["/auth/recovery/token/:token" :auth/recovery]
|
||||||
["/workspace/:project/:page" :workspace/page]]))
|
["/workspace/:project/:page" :workspace/page]]))
|
||||||
|
|
||||||
(defn routing-test []
|
(defn routing-test1 []
|
||||||
|
|
||||||
(suite "simple routing")
|
(suite "static route")
|
||||||
|
|
||||||
|
;; 2.2µs
|
||||||
|
(title "bidi")
|
||||||
|
(let [call #(bidi/match-route bidi-routes "/auth/login")]
|
||||||
|
(assert (call))
|
||||||
|
(cc/quick-bench
|
||||||
|
(call)))
|
||||||
|
|
||||||
|
;; 1.5µs (-40%)
|
||||||
|
(title "ataraxy")
|
||||||
|
(let [call #(ataraxy/matches ataraxy-routes {:uri "/auth/login"})]
|
||||||
|
(assert (call))
|
||||||
|
(cc/quick-bench
|
||||||
|
(call)))
|
||||||
|
|
||||||
|
;; 1.1µs (-50%)
|
||||||
|
(title "pedestal - map-tree => prefix-tree")
|
||||||
|
(let [call #(pedestal/find-route pedestal-router {:path-info "/auth/login" :request-method :get})]
|
||||||
|
(assert (call))
|
||||||
|
(cc/quick-bench
|
||||||
|
(call)))
|
||||||
|
|
||||||
|
;; 1.5µs (-40%)
|
||||||
|
(title "compojure-api")
|
||||||
|
(let [call #(compojure-api-routes {:uri "/auth/login", :request-method :get})]
|
||||||
|
(assert (call))
|
||||||
|
(cc/quick-bench
|
||||||
|
(call)))
|
||||||
|
|
||||||
|
;; 11.5ns (-99,5%)
|
||||||
|
(title "reitit")
|
||||||
|
(let [call #(reitit/match-by-path reitit-routes "/auth/login")]
|
||||||
|
(assert (call))
|
||||||
|
(cc/quick-bench
|
||||||
|
(call))))
|
||||||
|
|
||||||
|
(defn routing-test2 []
|
||||||
|
|
||||||
|
(suite "wildcard route")
|
||||||
|
|
||||||
;; 15.4µs
|
;; 15.4µs
|
||||||
(title "bidi")
|
(title "bidi")
|
||||||
|
|
@ -141,5 +180,6 @@
|
||||||
(call))))
|
(call))))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(routing-test)
|
(routing-test1)
|
||||||
|
(routing-test2)
|
||||||
(reverse-routing-test))
|
(reverse-routing-test))
|
||||||
|
|
|
||||||
|
|
@ -213,17 +213,52 @@
|
||||||
(if-let [match (impl/fast-get lookup name)]
|
(if-let [match (impl/fast-get lookup name)]
|
||||||
(match params)))))))
|
(match params)))))))
|
||||||
|
|
||||||
|
(defn fast-router
|
||||||
|
"Creates a super-fast router of 1 static route(s) and optional
|
||||||
|
expanded options. See [[router]] for available options"
|
||||||
|
([routes]
|
||||||
|
(fast-router routes {}))
|
||||||
|
([routes opts]
|
||||||
|
(when (or (not= (count routes) 1) (some impl/wild-route? routes))
|
||||||
|
(throw
|
||||||
|
(ex-info
|
||||||
|
(str ":fast-router requires exactly 1 static route: " routes)
|
||||||
|
{:routes routes})))
|
||||||
|
(let [[n :as names] (find-names routes opts)
|
||||||
|
[[p meta result] :as compiled] (compile-routes routes opts)
|
||||||
|
p #?(:clj (.intern ^String p) :cljs p)
|
||||||
|
match (->Match p meta result {} p)]
|
||||||
|
(reify Router
|
||||||
|
(router-name [_]
|
||||||
|
:fast-router)
|
||||||
|
(routes [_]
|
||||||
|
compiled)
|
||||||
|
(options [_]
|
||||||
|
opts)
|
||||||
|
(route-names [_]
|
||||||
|
names)
|
||||||
|
(match-by-path [_ path]
|
||||||
|
(if (#?(:clj .equals :cljs =) p path)
|
||||||
|
match))
|
||||||
|
(match-by-name [_ name]
|
||||||
|
(if (= n name)
|
||||||
|
match))
|
||||||
|
(match-by-name [_ name params]
|
||||||
|
(if (= n name)
|
||||||
|
(impl/fast-assoc match :params params)))))))
|
||||||
|
|
||||||
(defn mixed-router
|
(defn mixed-router
|
||||||
"Creates two routers: [[lookup-router]] for static routes and
|
"Creates two routers: [[lookup-router]] or [[fast-ruoter]] for
|
||||||
[[linear-router]] for wildcard routes. All routes should be
|
static routes and [[linear-router]] for wildcard routes. All
|
||||||
non-conflicting. Takes resolved routes and optional
|
routes should be non-conflicting. Takes resolved routes and optional
|
||||||
expanded options. See [[router]] for options."
|
expanded options. See [[router]] for options."
|
||||||
([routes]
|
([routes]
|
||||||
(mixed-router routes {}))
|
(mixed-router routes {}))
|
||||||
([routes opts]
|
([routes opts]
|
||||||
(let [{linear true, lookup false} (group-by impl/wild-route? routes)
|
(let [{linear true, lookup false} (group-by impl/wild-route? routes)
|
||||||
linear-router (linear-router linear opts)
|
->static-router (if (= 1 (count lookup)) fast-router lookup-router)
|
||||||
lookup-router (lookup-router lookup opts)
|
wildcard-router (linear-router linear opts)
|
||||||
|
static-router (->static-router lookup opts)
|
||||||
names (find-names routes opts)]
|
names (find-names routes opts)]
|
||||||
(reify Router
|
(reify Router
|
||||||
(router-name [_]
|
(router-name [_]
|
||||||
|
|
@ -235,19 +270,19 @@
|
||||||
(route-names [_]
|
(route-names [_]
|
||||||
names)
|
names)
|
||||||
(match-by-path [_ path]
|
(match-by-path [_ path]
|
||||||
(or (match-by-path lookup-router path)
|
(or (match-by-path static-router path)
|
||||||
(match-by-path linear-router path)))
|
(match-by-path wildcard-router path)))
|
||||||
(match-by-name [_ name]
|
(match-by-name [_ name]
|
||||||
(or (match-by-name lookup-router name)
|
(or (match-by-name static-router name)
|
||||||
(match-by-name linear-router name)))
|
(match-by-name wildcard-router name)))
|
||||||
(match-by-name [_ name params]
|
(match-by-name [_ name params]
|
||||||
(or (match-by-name lookup-router name params)
|
(or (match-by-name static-router name params)
|
||||||
(match-by-name linear-router name params)))))))
|
(match-by-name wildcard-router name params)))))))
|
||||||
|
|
||||||
(defn router
|
(defn router
|
||||||
"Create a [[Router]] from raw route data and optionally an options map.
|
"Create a [[Router]] from raw route data and optionally an options map.
|
||||||
If routes contain wildcards, a [[LinearRouter]] is used, otherwise a
|
Selects implementation based on route details. The following options
|
||||||
[[LookupRouter]]. The following options are available:
|
are available:
|
||||||
|
|
||||||
| key | description |
|
| key | description |
|
||||||
| -------------|-------------|
|
| -------------|-------------|
|
||||||
|
|
@ -265,10 +300,11 @@
|
||||||
(let [{:keys [router] :as opts} (meta-merge default-router-options opts)
|
(let [{:keys [router] :as opts} (meta-merge default-router-options opts)
|
||||||
routes (resolve-routes data opts)
|
routes (resolve-routes data opts)
|
||||||
conflicting (conflicting-routes routes)
|
conflicting (conflicting-routes routes)
|
||||||
wilds? (some impl/wild-route? routes)
|
wilds? (boolean (some impl/wild-route? routes))
|
||||||
all-wilds? (every? impl/wild-route? routes)
|
all-wilds? (every? impl/wild-route? routes)
|
||||||
router (cond
|
router (cond
|
||||||
router router
|
router router
|
||||||
|
(and (= 1 (count routes)) (not wilds?)) fast-router
|
||||||
(not wilds?) lookup-router
|
(not wilds?) lookup-router
|
||||||
all-wilds? linear-router
|
all-wilds? linear-router
|
||||||
(not conflicting) mixed-router
|
(not conflicting) mixed-router
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,44 @@
|
||||||
(r/resolve-routes
|
(r/resolve-routes
|
||||||
["/api/:version/ping"] {})))))))
|
["/api/:version/ping"] {})))))))
|
||||||
|
|
||||||
|
(testing "fast-router"
|
||||||
|
(let [router (r/router ["/api" ["/ipa" ["/large" ::beer]]])]
|
||||||
|
(is (= :fast-router (r/router-name router)))
|
||||||
|
(is (= [["/api/ipa/large" {:name ::beer} nil]]
|
||||||
|
(r/routes router)))
|
||||||
|
(is (= true (map? (r/options router))))
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/api/ipa/large"
|
||||||
|
:meta {:name ::beer}
|
||||||
|
:path "/api/ipa/large"
|
||||||
|
:params {}})
|
||||||
|
(r/match-by-path router "/api/ipa/large")))
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/api/ipa/large"
|
||||||
|
:meta {:name ::beer}
|
||||||
|
:path "/api/ipa/large"
|
||||||
|
: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)))
|
||||||
|
|
||||||
|
(testing "can't be created with wildcard routes"
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
ExceptionInfo
|
||||||
|
#":fast-router requires exactly 1 static route"
|
||||||
|
(r/fast-router
|
||||||
|
(r/resolve-routes
|
||||||
|
["/api/:version/ping"] {})))))
|
||||||
|
|
||||||
|
(testing "can't be created with multiple routes"
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
ExceptionInfo
|
||||||
|
#":fast-router requires exactly 1 static route"
|
||||||
|
(r/fast-router
|
||||||
|
(r/resolve-routes
|
||||||
|
[["/ping"]
|
||||||
|
["/pong"]] {})))))))
|
||||||
|
|
||||||
(testing "route coercion & compilation"
|
(testing "route coercion & compilation"
|
||||||
|
|
||||||
(testing "custom compile"
|
(testing "custom compile"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue