mirror of
https://github.com/metosin/reitit.git
synced 2026-02-15 15:55:15 +00:00
commit
93470fd176
23 changed files with 408 additions and 135 deletions
23
CHANGELOG.md
23
CHANGELOG.md
|
|
@ -1,5 +1,26 @@
|
||||||
## 0.1.2-SNAPSHOT
|
## 0.1.2-SNAPSHOT
|
||||||
|
|
||||||
|
### `reitit-core`
|
||||||
|
|
||||||
|
* Better handling of `nil` in route syntax:
|
||||||
|
* explicit `nil` after path string is always handled as `nil` route
|
||||||
|
* `nil` as path string causes the whole route to be `nil`
|
||||||
|
* `nil` as child route is stripped away
|
||||||
|
|
||||||
|
```clj
|
||||||
|
(testing "nil routes are stripped"
|
||||||
|
(is (= [] (r/routes (r/router nil))))
|
||||||
|
(is (= [] (r/routes (r/router [nil ["/ping"]]))))
|
||||||
|
(is (= [] (r/routes (r/router [nil [nil] [[nil nil nil]]]))))
|
||||||
|
(is (= [] (r/routes (r/router ["/ping" [nil "/pong"]])))))
|
||||||
|
```
|
||||||
|
### `reitit-ring`
|
||||||
|
|
||||||
|
* Use HTTP redirect (302) with index-files in `reitit.ring/create-resource-handler`.
|
||||||
|
* `reitit.ring/create-default-handler` now conforms to [RING Spec](https://github.com/ring-clojure/ring/blob/master/SPEC), Fixes [#83](https://github.com/metosin/reitit/issues/83)
|
||||||
|
|
||||||
|
https://github.com/metosin/reitit/issues/83
|
||||||
|
|
||||||
### `reitit-schema`
|
### `reitit-schema`
|
||||||
|
|
||||||
* updated dependencies:
|
* updated dependencies:
|
||||||
|
|
@ -14,6 +35,8 @@
|
||||||
|
|
||||||
### `reitit-swagger-ui`
|
### `reitit-swagger-ui`
|
||||||
|
|
||||||
|
* Use HTTP redirect (302) with index-files in `reitit.swagger-ui/create-swagger-ui-handler`.
|
||||||
|
|
||||||
* updated dependencies:
|
* updated dependencies:
|
||||||
|
|
||||||
```clj
|
```clj
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ Whole example project is in [`/examples/ring-swagger`](https://github.com/metosi
|
||||||
"application/transit+json"}}}})
|
"application/transit+json"}}}})
|
||||||
(ring/routes
|
(ring/routes
|
||||||
(swagger-ui/create-swagger-ui-handler
|
(swagger-ui/create-swagger-ui-handler
|
||||||
{:path "", :url "/api/swagger.json"})
|
{:path "/", :url "/api/swagger.json"})
|
||||||
(ring/create-default-handler))))
|
(ring/create-default-handler))))
|
||||||
|
|
||||||
(defn start []
|
(defn start []
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||||
[ring "1.6.3"]
|
[ring "1.6.3"]
|
||||||
[metosin/muuntaja "0.4.1"]
|
[metosin/muuntaja "0.4.1"]
|
||||||
[metosin/reitit "0.1.1"]])
|
[metosin/reitit "0.1.2-SNAPSHOT"]])
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||||
[ring "1.6.3"]
|
[ring "1.6.3"]
|
||||||
[metosin/muuntaja "0.4.1"]
|
[metosin/muuntaja "0.4.1"]
|
||||||
[metosin/reitit "0.1.1"]])
|
[metosin/reitit "0.1.2-SNAPSHOT"]])
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@
|
||||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||||
[ring "1.6.3"]
|
[ring "1.6.3"]
|
||||||
[metosin/muuntaja "0.5.0"]
|
[metosin/muuntaja "0.5.0"]
|
||||||
[metosin/reitit "0.1.1"]]
|
[metosin/reitit "0.1.2-SNAPSHOT"]]
|
||||||
:repl-options {:init-ns example.server})
|
:repl-options {:init-ns example.server})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-core "0.1.1"
|
(defproject metosin/reitit-core "0.1.2-SNAPSHOT"
|
||||||
:description "Snappy data-driven router for Clojure(Script)"
|
:description "Snappy data-driven router for Clojure(Script)"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,14 @@
|
||||||
(walk-one [pacc macc routes]
|
(walk-one [pacc macc routes]
|
||||||
(if (vector? (first routes))
|
(if (vector? (first routes))
|
||||||
(walk-many pacc macc routes)
|
(walk-many pacc macc routes)
|
||||||
(let [[path & [maybe-arg :as args]] routes
|
(when (string? (first routes))
|
||||||
[data childs] (if (vector? maybe-arg)
|
(let [[path & [maybe-arg :as args]] routes
|
||||||
[{} args]
|
[data childs] (if (or (vector? maybe-arg) (nil? maybe-arg))
|
||||||
[maybe-arg (rest args)])
|
[{} args]
|
||||||
macc (into macc (expand data opts))]
|
[maybe-arg (rest args)])
|
||||||
(if (seq childs)
|
macc (into macc (expand data opts))
|
||||||
(walk-many (str pacc path) macc childs)
|
child-routes (walk-many (str pacc path) macc (keep identity childs))]
|
||||||
[[(str pacc path) macc]]))))]
|
(if (seq childs) (seq child-routes) [[(str pacc path) macc]])))))]
|
||||||
(walk-one path (mapv identity data) raw-routes)))
|
(walk-one path (mapv identity data) raw-routes)))
|
||||||
|
|
||||||
(defn map-data [f routes]
|
(defn map-data [f routes]
|
||||||
|
|
@ -87,10 +87,10 @@
|
||||||
(conflicts-str conflicts)
|
(conflicts-str conflicts)
|
||||||
{:conflicts conflicts})))
|
{:conflicts conflicts})))
|
||||||
|
|
||||||
(defn name-lookup [[_ {:keys [name]}] opts]
|
(defn name-lookup [[_ {:keys [name]}] _]
|
||||||
(if name #{name}))
|
(if name #{name}))
|
||||||
|
|
||||||
(defn find-names [routes opts]
|
(defn find-names [routes _]
|
||||||
(into [] (keep #(-> % second :name)) routes))
|
(into [] (keep #(-> % second :name)) routes))
|
||||||
|
|
||||||
(defn- compile-route [[p m :as route] {:keys [compile] :as opts}]
|
(defn- compile-route [[p m :as route] {:keys [compile] :as opts}]
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,19 @@
|
||||||
|
|
||||||
(s/def ::path (s/with-gen string? #(gen/fmap (fn [s] (str "/" s)) (s/gen string?))))
|
(s/def ::path (s/with-gen string? #(gen/fmap (fn [s] (str "/" s)) (s/gen string?))))
|
||||||
|
|
||||||
(s/def ::arg (s/and any? (complement vector?)))
|
(s/def ::arg (s/and some? (complement vector?)))
|
||||||
(s/def ::data (s/map-of keyword? any?))
|
(s/def ::data (s/map-of keyword? any?))
|
||||||
(s/def ::result any?)
|
(s/def ::result any?)
|
||||||
|
|
||||||
(s/def ::raw-route
|
(s/def ::raw-route
|
||||||
(s/cat :path ::path
|
(s/nilable
|
||||||
:arg (s/? ::arg)
|
(s/cat :path ::path
|
||||||
:childs (s/* (s/and (s/nilable ::raw-route)))))
|
:arg (s/? ::arg)
|
||||||
|
:childs (s/* (s/and (s/nilable ::raw-routes))))))
|
||||||
|
|
||||||
(s/def ::raw-routes
|
(s/def ::raw-routes
|
||||||
(s/or :route ::raw-route
|
(s/or :route ::raw-route
|
||||||
:routes (s/coll-of ::raw-route :into [])))
|
:routes (s/coll-of ::raw-routes :into [])))
|
||||||
|
|
||||||
(s/def ::route
|
(s/def ::route
|
||||||
(s/cat :path ::path
|
(s/cat :path ::path
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-ring "0.1.1"
|
(defproject metosin/reitit-ring "0.1.2-SNAPSHOT"
|
||||||
:description "Reitit: Ring routing"
|
:description "Reitit: Ring routing"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@
|
||||||
| `:not-acceptable` | 406, handler returned `nil`"
|
| `:not-acceptable` | 406, handler returned `nil`"
|
||||||
([]
|
([]
|
||||||
(create-default-handler
|
(create-default-handler
|
||||||
{:not-found (constantly {:status 404, :body ""})
|
{:not-found (constantly {:status 404, :body "", :headers {}})
|
||||||
:method-not-allowed (constantly {:status 405, :body ""})
|
:method-not-allowed (constantly {:status 405, :body "", :headers {}})
|
||||||
:not-acceptable (constantly {:status 406, :body ""})}))
|
:not-acceptable (constantly {:status 406, :body "", :headers {}})}))
|
||||||
([{:keys [not-found method-not-allowed not-acceptable]}]
|
([{:keys [not-found method-not-allowed not-acceptable]}]
|
||||||
(fn
|
(fn
|
||||||
([request]
|
([request]
|
||||||
|
|
@ -96,24 +96,30 @@
|
||||||
(fn
|
(fn
|
||||||
([request] (handler request))
|
([request] (handler request))
|
||||||
([request respond _] (respond (handler request)))))
|
([request respond _] (respond (handler request)))))
|
||||||
|
join-paths (fn [& paths]
|
||||||
|
(str/replace (str/replace (str/join "/" paths) #"([/]+)" "/") #"/$" ""))
|
||||||
resource-response (fn [path]
|
resource-response (fn [path]
|
||||||
(if-let [response (or (paths path) (response/resource-response path options))]
|
(if-let [response (or (paths (join-paths "/" path))
|
||||||
|
(response/resource-response path options))]
|
||||||
(response/content-type response (mime-type/ext-mime-type path))))
|
(response/content-type response (mime-type/ext-mime-type path))))
|
||||||
path-or-index-response (fn [path]
|
path-or-index-response (fn [path uri]
|
||||||
(or (resource-response path)
|
(or (resource-response path)
|
||||||
(let [separator (if-not (str/ends-with? path "/") "/")]
|
(loop [[file & files] index-files]
|
||||||
(loop [[file & files] index-files]
|
(if file
|
||||||
(if file
|
(if (resource-response (join-paths path file))
|
||||||
(or (resource-response (str path separator file))
|
(response/redirect (join-paths uri file))
|
||||||
(recur files)))))))
|
(recur files))))))
|
||||||
handler (if path
|
handler (if path
|
||||||
(fn [request]
|
(fn [request]
|
||||||
(let [uri (:uri request)]
|
(let [uri (:uri request)]
|
||||||
(if-let [path (if (>= (count uri) path-size) (subs uri path-size))]
|
(if-let [path (if (>= (count uri) path-size) (subs uri path-size))]
|
||||||
(path-or-index-response path))))
|
(path-or-index-response path uri))))
|
||||||
(fn [request]
|
(fn [request]
|
||||||
(let [path (-> request :path-params parameter)]
|
(let [uri (:uri request)
|
||||||
(or (path-or-index-response path) {:status 404}))))]
|
path (-> request :path-params parameter)]
|
||||||
|
(or (path-or-index-response path uri)
|
||||||
|
;; TODO: use generic not-found handler
|
||||||
|
{:status 404}))))]
|
||||||
(create handler)))))
|
(create handler)))))
|
||||||
|
|
||||||
(defn ring-handler
|
(defn ring-handler
|
||||||
|
|
@ -129,7 +135,7 @@
|
||||||
(fn
|
(fn
|
||||||
([request]
|
([request]
|
||||||
(if-let [match (r/match-by-path router (:uri request))]
|
(if-let [match (r/match-by-path router (:uri request))]
|
||||||
(let [method (:request-method request :any)
|
(let [method (:request-method request)
|
||||||
path-params (:path-params match)
|
path-params (:path-params match)
|
||||||
result (:result match)
|
result (:result match)
|
||||||
handler (-> result method :handler (or default-handler))
|
handler (-> result method :handler (or default-handler))
|
||||||
|
|
@ -141,7 +147,7 @@
|
||||||
(default-handler request)))
|
(default-handler request)))
|
||||||
([request respond raise]
|
([request respond raise]
|
||||||
(if-let [match (r/match-by-path router (:uri request))]
|
(if-let [match (r/match-by-path router (:uri request))]
|
||||||
(let [method (:request-method request :any)
|
(let [method (:request-method request)
|
||||||
path-params (:path-params match)
|
path-params (:path-params match)
|
||||||
result (:result match)
|
result (:result match)
|
||||||
handler (-> result method :handler (or default-handler))
|
handler (-> result method :handler (or default-handler))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-schema "0.1.1"
|
(defproject metosin/reitit-schema "0.1.2-SNAPSHOT"
|
||||||
:description "Reitit: Plumatic Schema coercion"
|
:description "Reitit: Plumatic Schema coercion"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-spec "0.1.1"
|
(defproject metosin/reitit-spec "0.1.2-SNAPSHOT"
|
||||||
:description "Reitit: clojure.spec coercion"
|
:description "Reitit: clojure.spec coercion"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-swagger-ui "0.1.1"
|
(defproject metosin/reitit-swagger-ui "0.1.2-SNAPSHOT"
|
||||||
:description "Reitit: Swagger-ui support"
|
:description "Reitit: Swagger-ui support"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
;; with path and url set, swagger validator disabled
|
;; with path and url set, swagger validator disabled
|
||||||
(swagger-ui/create-swagger-ui-handler
|
(swagger-ui/create-swagger-ui-handler
|
||||||
{:path \"\"
|
{:path \"/\"
|
||||||
:url \"/api/swagger.json\"
|
:url \"/api/swagger.json\"
|
||||||
:config {:validator-url nil})"
|
:config {:validator-url nil})"
|
||||||
([]
|
([]
|
||||||
|
|
@ -42,11 +42,11 @@
|
||||||
(update $ :root (fnil identity "swagger-ui"))
|
(update $ :root (fnil identity "swagger-ui"))
|
||||||
(update $ :url (fnil identity "/swagger.json"))
|
(update $ :url (fnil identity "/swagger.json"))
|
||||||
(update $ :config #(->> % (map mixed-case-key) (into {})))
|
(update $ :config #(->> % (map mixed-case-key) (into {})))
|
||||||
(assoc $ :paths {"conf.js" {:headers {"Content-Type" "application/javascript"}
|
(assoc $ :paths {"/conf.js" {:headers {"Content-Type" "application/javascript"}
|
||||||
:status 200
|
:status 200
|
||||||
:body (conf-js $)}
|
:body (conf-js $)}
|
||||||
"config.json" {:headers {"Content-Type" "application/json"}
|
"/config.json" {:headers {"Content-Type" "application/json"}
|
||||||
:status 200
|
:status 200
|
||||||
:body (config-json $)}}))]
|
:body (config-json $)}}))]
|
||||||
(ring/routes
|
(ring/routes
|
||||||
(ring/create-resource-handler options))))))
|
(ring/create-resource-handler options))))))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-swagger "0.1.1"
|
(defproject metosin/reitit-swagger "0.1.2-SNAPSHOT"
|
||||||
:description "Reitit: Swagger-support"
|
:description "Reitit: Swagger-support"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit "0.1.1"
|
(defproject metosin/reitit "0.1.2-SNAPSHOT"
|
||||||
:description "Snappy data-driven router for Clojure(Script)"
|
:description "Snappy data-driven router for Clojure(Script)"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
[io.pedestal.http.route.definition.table :as table]
|
[io.pedestal.http.route.definition.table :as table]
|
||||||
[io.pedestal.http.route.map-tree :as map-tree]
|
[io.pedestal.http.route.map-tree :as map-tree]
|
||||||
[io.pedestal.http.route.router :as pedestal]
|
[io.pedestal.http.route.router :as pedestal]
|
||||||
[io.pedestal.http.route :as route]))
|
[io.pedestal.http.route :as route]
|
||||||
|
[reitit.ring :as ring]))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; start repl with `lein perf repl`
|
;; start repl with `lein perf repl`
|
||||||
|
|
@ -62,6 +63,26 @@
|
||||||
["/auth/recovery/token/:token" :auth/recovery]
|
["/auth/recovery/token/:token" :auth/recovery]
|
||||||
["/workspace/:project/:page" :workspace/page]]))
|
["/workspace/:project/:page" :workspace/page]]))
|
||||||
|
|
||||||
|
(def ring-app
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
[["/auth/login" {:get identity}]
|
||||||
|
["/auth/recovery/token/:token" {:get identity}]
|
||||||
|
["/workspace/:project/:page" {:get identity}]])))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
|
||||||
|
(ring-app {:request-method :get, :uri "/auth/login"})
|
||||||
|
|
||||||
|
;; 213ns
|
||||||
|
;; 204ns (remove if)
|
||||||
|
;; 163ns (inline fast-assoc)
|
||||||
|
;; 156ns (don't inline fast-assoc)
|
||||||
|
;; 128ns (single method dispatch)
|
||||||
|
;; 80ns --> (don't inject router & match)
|
||||||
|
(cc/quick-bench
|
||||||
|
(ring-app {:request-method :post, :uri "/auth/login"})))
|
||||||
|
|
||||||
(defn routing-test1 []
|
(defn routing-test1 []
|
||||||
|
|
||||||
(suite "static route")
|
(suite "static route")
|
||||||
|
|
|
||||||
109
perf-test/clj/reitit/json_perf.cljc
Normal file
109
perf-test/clj/reitit/json_perf.cljc
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
(ns reitit.json-perf
|
||||||
|
(:require [criterium.core :as cc]
|
||||||
|
[reitit.perf-utils :refer :all]
|
||||||
|
|
||||||
|
;; reitit
|
||||||
|
[reitit.ring :as ring]
|
||||||
|
[muuntaja.middleware :as mm]
|
||||||
|
|
||||||
|
;; bidi-yada
|
||||||
|
[yada.yada :as yada]
|
||||||
|
[bidi.ring :as bidi-ring]
|
||||||
|
[byte-streams :as bs]
|
||||||
|
|
||||||
|
;; defaults
|
||||||
|
[ring.middleware.defaults :as defaults]
|
||||||
|
[compojure.core :as compojure]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; start repl with `lein perf repl`
|
||||||
|
;; perf measured with the following setup:
|
||||||
|
;;
|
||||||
|
;; Model Name: MacBook Pro
|
||||||
|
;; Model Identifier: MacBookPro113
|
||||||
|
;; Processor Name: Intel Core i7
|
||||||
|
;; Processor Speed: 2,5 GHz
|
||||||
|
;; Number of Processors: 1
|
||||||
|
;; Total Number of Cores: 4
|
||||||
|
;; L2 Cache (per Core): 256 KB
|
||||||
|
;; L3 Cache: 6 MB
|
||||||
|
;; Memory: 16 GB
|
||||||
|
;;
|
||||||
|
|
||||||
|
;; TODO: naive implementation
|
||||||
|
(defn- with-security-headers [response]
|
||||||
|
(update
|
||||||
|
response
|
||||||
|
:headers
|
||||||
|
(fn [headers]
|
||||||
|
(-> headers
|
||||||
|
(assoc "x-frame-options" "SAMEORIGIN")
|
||||||
|
(assoc "x-xss-protection" "1; mode=block")
|
||||||
|
(assoc "x-content-type-options" "nosniff")))))
|
||||||
|
|
||||||
|
(def security-middleware
|
||||||
|
{:name ::security
|
||||||
|
:wrap (fn [handler]
|
||||||
|
(fn [request]
|
||||||
|
(with-security-headers (handler request))))})
|
||||||
|
|
||||||
|
(def reitit-app
|
||||||
|
(ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
["/api/ping"
|
||||||
|
{:get {:handler (fn [_] {:status 200, :body {:ping "pong"}})}}]
|
||||||
|
{:data {:middleware [mm/wrap-format
|
||||||
|
security-middleware]}})))
|
||||||
|
|
||||||
|
(def bidi-yada-app
|
||||||
|
(bidi-ring/make-handler
|
||||||
|
["/api/ping"
|
||||||
|
(yada/resource
|
||||||
|
{:produces {:media-type "application/json"}
|
||||||
|
:methods {:get {:response (fn [_] {:ping "pong"})}}})]))
|
||||||
|
|
||||||
|
(def defaults-app
|
||||||
|
(defaults/wrap-defaults
|
||||||
|
(mm/wrap-format
|
||||||
|
(compojure/GET "/api/ping" [] {:status 200, :body {:ping "pong"}}))
|
||||||
|
defaults/site-defaults))
|
||||||
|
|
||||||
|
(def request {:request-method :get, :uri "/api/ping"})
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(defaults-app request)
|
||||||
|
@(bidi-yada-app request)
|
||||||
|
(reitit-app request))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(slurp (:body (defaults-app request)))
|
||||||
|
(slurp (:body (reitit-app request)))
|
||||||
|
(bs/to-string (:body @(bidi-yada-app request))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn expect! [body]
|
||||||
|
(assert (str/starts-with? body "{\"ping\":\"pong\"}")))
|
||||||
|
|
||||||
|
(defn perf-test []
|
||||||
|
|
||||||
|
;; 176µs
|
||||||
|
(title "compojure + ring-defaults")
|
||||||
|
(let [f (fn [] (defaults-app request))]
|
||||||
|
(expect! (-> (f) :body slurp))
|
||||||
|
(cc/quick-bench (f)))
|
||||||
|
|
||||||
|
;; 60µs
|
||||||
|
(title "bidi + yada")
|
||||||
|
(let [f (fn [] (bidi-yada-app request))]
|
||||||
|
(expect! (-> (f) deref :body bs/to-string))
|
||||||
|
(cc/quick-bench (f)))
|
||||||
|
|
||||||
|
;; 5.0µs
|
||||||
|
(title "reitit-ring")
|
||||||
|
(let [f (fn [] (reitit-app request))]
|
||||||
|
(expect! (-> (f) :body slurp))
|
||||||
|
(cc/quick-bench (f))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(perf-test))
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
(defrecord RequestOrContext [values queue stack])
|
(defrecord RequestOrContext [values queue stack])
|
||||||
|
|
||||||
(def +items+ 100)
|
(def +items+ 10)
|
||||||
|
|
||||||
(defn expected! [x]
|
(defn expected! [x]
|
||||||
(assert (= (range +items+) (:values x))))
|
(assert (= (range +items+) (:values x))))
|
||||||
|
|
@ -47,18 +47,19 @@
|
||||||
map-request {}
|
map-request {}
|
||||||
record-request (map->RequestOrContext map-request)]
|
record-request (map->RequestOrContext map-request)]
|
||||||
|
|
||||||
;; 10.8 µs
|
;; 1000ns
|
||||||
(title "middleware - map")
|
(title "middleware - map")
|
||||||
(expected! (app map-request))
|
(expected! (app map-request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(app map-request))
|
(app map-request))
|
||||||
|
|
||||||
;; 4.7 µs
|
;; 365ns
|
||||||
(title "middleware - record")
|
(title "middleware - record")
|
||||||
(expected! (app record-request))
|
(expected! (app record-request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(app record-request))
|
(app record-request))
|
||||||
|
|
||||||
|
;; 6900ns
|
||||||
(title "middleware - dynamic")
|
(title "middleware - dynamic")
|
||||||
(expected! ((middleware/chain mw identity) record-request))
|
(expected! ((middleware/chain mw identity) record-request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
|
|
@ -110,21 +111,21 @@
|
||||||
{:enter (interceptor value)}) (range +items+)))
|
{:enter (interceptor value)}) (range +items+)))
|
||||||
ctx (io.pedestal.interceptor.chain/enqueue nil is)]
|
ctx (io.pedestal.interceptor.chain/enqueue nil is)]
|
||||||
|
|
||||||
;; 78 µs
|
;; 8400ns
|
||||||
(title "pedestal")
|
(title "pedestal")
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(io.pedestal.interceptor.chain/execute ctx))))
|
(io.pedestal.interceptor.chain/execute ctx))))
|
||||||
|
|
||||||
(defn pedestal-tuned-chain-text []
|
#_(defn pedestal-tuned-chain-text []
|
||||||
(let [is (map io.pedestal.interceptor/interceptor
|
(let [is (map io.pedestal.interceptor/interceptor
|
||||||
(map (fn [value]
|
(map (fn [value]
|
||||||
{:enter (interceptor value)}) (range +items+)))
|
{:enter (interceptor value)}) (range +items+)))
|
||||||
ctx (reitit.chain/map->Context (reitit.chain/enqueue nil is))]
|
ctx (reitit.chain/map->Context (reitit.chain/enqueue nil is))]
|
||||||
|
|
||||||
;; 67 µs
|
;; 67 µs
|
||||||
(title "pedestal - tuned")
|
(title "pedestal - tuned")
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(reitit.chain/execute ctx))))
|
(reitit.chain/execute ctx))))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Naive chain
|
;; Naive chain
|
||||||
|
|
@ -140,17 +141,17 @@
|
||||||
|
|
||||||
(defn interceptor-test []
|
(defn interceptor-test []
|
||||||
(let [interceptors (map (fn [value] [interceptor value]) (range +items+))
|
(let [interceptors (map (fn [value] [interceptor value]) (range +items+))
|
||||||
app (executor-reduce (interceptor/chain interceptors identity))
|
app (executor-reduce (interceptor/chain interceptors identity {}))
|
||||||
map-request {}
|
map-request {}
|
||||||
record-request (map->RequestOrContext map-request)]
|
record-request (map->RequestOrContext map-request)]
|
||||||
|
|
||||||
;; 13.5 µs (Map)
|
;; 1900ns
|
||||||
(title "interceptors - map")
|
(title "interceptors - map")
|
||||||
(expected! (app map-request))
|
(expected! (app map-request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(app map-request))
|
(app map-request))
|
||||||
|
|
||||||
;; 7.2 µs (Record)
|
;; 1300ns
|
||||||
(title "interceptors - record")
|
(title "interceptors - record")
|
||||||
(expected! (app record-request))
|
(expected! (app record-request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
|
|
@ -212,24 +213,24 @@
|
||||||
|
|
||||||
(defn interceptor-chain-test []
|
(defn interceptor-chain-test []
|
||||||
(let [interceptors (map (fn [value] [interceptor value]) (range +items+))
|
(let [interceptors (map (fn [value] [interceptor value]) (range +items+))
|
||||||
app-reduce (executor-reduce (interceptor/chain interceptors identity))
|
app-reduce (executor-reduce (interceptor/chain interceptors identity {}))
|
||||||
app-queue (executor-queue (interceptor/chain interceptors identity))
|
app-queue (executor-queue (interceptor/chain interceptors identity {}))
|
||||||
app-ctx-queue (executor-ctx-queue (interceptor/chain interceptors identity))
|
app-ctx-queue (executor-ctx-queue (interceptor/chain interceptors identity {}))
|
||||||
request {}]
|
request {}]
|
||||||
|
|
||||||
;; 14.2 µs
|
;; 2000ns
|
||||||
(title "interceptors - reduce")
|
(title "interceptors - reduce")
|
||||||
(expected! (app-reduce request))
|
(expected! (app-reduce request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(app-reduce request))
|
(app-reduce request))
|
||||||
|
|
||||||
;; 19.4 µs
|
;; 2500ns
|
||||||
(title "interceptors - queue")
|
(title "interceptors - queue")
|
||||||
(expected! (app-queue request))
|
(expected! (app-queue request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(app-queue request))
|
(app-queue request))
|
||||||
|
|
||||||
;; 30.9 µs
|
;; 3200ns
|
||||||
(title "interceptors - ctx-queue")
|
(title "interceptors - ctx-queue")
|
||||||
(expected! (app-ctx-queue request))
|
(expected! (app-ctx-queue request))
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
|
|
|
||||||
20
project.clj
20
project.clj
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject metosin/reitit-parent "0.1.1"
|
(defproject metosin/reitit-parent "0.1.2-SNAPSHOT"
|
||||||
:description "Snappy data-driven router for Clojure(Script)"
|
:description "Snappy data-driven router for Clojure(Script)"
|
||||||
:url "https://github.com/metosin/reitit"
|
:url "https://github.com/metosin/reitit"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
@ -9,13 +9,13 @@
|
||||||
:source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}"
|
:source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}"
|
||||||
:metadata {:doc/format :markdown}}
|
:metadata {:doc/format :markdown}}
|
||||||
|
|
||||||
:managed-dependencies [[metosin/reitit "0.1.1"]
|
:managed-dependencies [[metosin/reitit "0.1.2-SNAPSHOT"]
|
||||||
[metosin/reitit-core "0.1.1"]
|
[metosin/reitit-core "0.1.2-SNAPSHOT"]
|
||||||
[metosin/reitit-ring "0.1.1"]
|
[metosin/reitit-ring "0.1.2-SNAPSHOT"]
|
||||||
[metosin/reitit-spec "0.1.1"]
|
[metosin/reitit-spec "0.1.2-SNAPSHOT"]
|
||||||
[metosin/reitit-schema "0.1.1"]
|
[metosin/reitit-schema "0.1.2-SNAPSHOT"]
|
||||||
[metosin/reitit-swagger "0.1.1"]
|
[metosin/reitit-swagger "0.1.2-SNAPSHOT"]
|
||||||
[metosin/reitit-swagger-ui "0.1.1"]
|
[metosin/reitit-swagger-ui "0.1.2-SNAPSHOT"]
|
||||||
|
|
||||||
[meta-merge "1.0.0"]
|
[meta-merge "1.0.0"]
|
||||||
[ring/ring-core "1.6.3"]
|
[ring/ring-core "1.6.3"]
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
[ring "1.6.3"]
|
[ring "1.6.3"]
|
||||||
[ikitommi/immutant-web "3.0.0-alpha1"]
|
[ikitommi/immutant-web "3.0.0-alpha1"]
|
||||||
[metosin/muuntaja "0.5.0"]
|
[metosin/muuntaja "0.6.0-SNAPSHOT"]
|
||||||
[metosin/ring-swagger-ui "2.2.10"]
|
[metosin/ring-swagger-ui "2.2.10"]
|
||||||
[metosin/jsonista "0.2.1"]
|
[metosin/jsonista "0.2.1"]
|
||||||
|
|
||||||
|
|
@ -70,6 +70,8 @@
|
||||||
[ikitommi/immutant-web "3.0.0-alpha1"]
|
[ikitommi/immutant-web "3.0.0-alpha1"]
|
||||||
[io.pedestal/pedestal.route "0.5.3"]
|
[io.pedestal/pedestal.route "0.5.3"]
|
||||||
[org.clojure/core.async "0.4.474"]
|
[org.clojure/core.async "0.4.474"]
|
||||||
|
[yada "1.2.13"]
|
||||||
|
[ring/ring-defaults "0.3.1"]
|
||||||
[ataraxy "0.4.0"]
|
[ataraxy "0.4.0"]
|
||||||
[bidi "2.1.3"]]}
|
[bidi "2.1.3"]]}
|
||||||
:analyze {:jvm-opts ^:replace ["-server"
|
:analyze {:jvm-opts ^:replace ["-server"
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,12 @@
|
||||||
r/segment-router :segment-router
|
r/segment-router :segment-router
|
||||||
r/mixed-router :mixed-router))
|
r/mixed-router :mixed-router))
|
||||||
|
|
||||||
|
(testing "nil routes are stripped"
|
||||||
|
(is (= [] (r/routes (r/router nil))))
|
||||||
|
(is (= [] (r/routes (r/router [nil ["/ping"]]))))
|
||||||
|
(is (= [] (r/routes (r/router [nil [nil] [[nil nil nil]]]))))
|
||||||
|
(is (= [] (r/routes (r/router ["/ping" [nil "/pong"]])))))
|
||||||
|
|
||||||
(testing "route coercion & compilation"
|
(testing "route coercion & compilation"
|
||||||
|
|
||||||
(testing "custom compile"
|
(testing "custom compile"
|
||||||
|
|
|
||||||
|
|
@ -267,56 +267,154 @@
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(deftest resource-handler-test
|
(deftest resource-handler-test
|
||||||
(doseq [[test app] [["inside a router"
|
(let [redirect (fn [uri] {:status 302, :body "", :headers {"Location" uri}})
|
||||||
(ring/ring-handler
|
request (fn [uri] {:uri uri, :request-method :get})]
|
||||||
(ring/router
|
(testing "inside a router"
|
||||||
[["/ping" (constantly {:status 200, :body "pong"})]
|
|
||||||
["/files/*" (ring/create-resource-handler)]
|
|
||||||
["/*" (ring/create-resource-handler)]]
|
|
||||||
{:conflicts (constantly nil)})
|
|
||||||
(ring/create-default-handler))]
|
|
||||||
|
|
||||||
["outside of a router"
|
(testing "from root"
|
||||||
(ring/ring-handler
|
(let [app (ring/ring-handler
|
||||||
(ring/router
|
(ring/router
|
||||||
["/ping" (constantly {:status 200, :body "pong"})])
|
["/*" (ring/create-resource-handler)])
|
||||||
(ring/routes
|
(ring/create-default-handler))]
|
||||||
(ring/create-resource-handler {:path "/files"})
|
(testing test
|
||||||
(ring/create-resource-handler {:path "/"})
|
(testing "different file-types"
|
||||||
(ring/create-default-handler)))]]
|
(let [response (app (request "/hello.json"))]
|
||||||
prefix ["" "/" "/files" "/files/"]
|
(is (= "application/json" (get-in response [:headers "Content-Type"])))
|
||||||
:let [request (fn [uri] {:uri (str prefix uri), :request-method :get})]]
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
|
||||||
|
(let [response (app (request "/hello.xml"))]
|
||||||
|
(is (= "text/xml" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
|
||||||
|
|
||||||
(testing test
|
(testing "index-files"
|
||||||
(testing "different file-types"
|
(let [response (app (request "/docs"))]
|
||||||
(let [response (app (request "/hello.json"))]
|
(is (= (redirect "/docs/index.html") response)))
|
||||||
(is (= "application/json" (get-in response [:headers "Content-Type"])))
|
(let [response (app (request "/docs/"))]
|
||||||
(is (get-in response [:headers "Last-Modified"]))
|
(is (= (redirect "/docs/index.html") response))))
|
||||||
(is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
|
|
||||||
(let [response (app (request "/hello.xml"))]
|
|
||||||
(is (= "text/xml" (get-in response [:headers "Content-Type"])))
|
|
||||||
(is (get-in response [:headers "Last-Modified"]))
|
|
||||||
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
|
|
||||||
|
|
||||||
(testing "index-files"
|
(testing "not found"
|
||||||
(let [response (app (request "/docs"))]
|
(let [response (app (request "/not-found"))]
|
||||||
(is (= "text/html" (get-in response [:headers "Content-Type"])))
|
(is (= 404 (:status response)))))
|
||||||
(is (get-in response [:headers "Last-Modified"]))
|
|
||||||
(is (= "<h1>hello</h1>\n" (slurp (:body response)))))
|
|
||||||
(let [response (app (request "/docs/"))]
|
|
||||||
(is (= "text/html" (get-in response [:headers "Content-Type"])))
|
|
||||||
(is (get-in response [:headers "Last-Modified"]))
|
|
||||||
(is (= "<h1>hello</h1>\n" (slurp (:body response))))))
|
|
||||||
|
|
||||||
(testing "not found"
|
(testing "3-arity"
|
||||||
(let [response (app (request "/not-found"))]
|
(let [result (atom nil)
|
||||||
(is (= 404 (:status response)))))
|
respond (partial reset! result)
|
||||||
|
raise ::not-called]
|
||||||
|
(app (request "/hello.xml") respond raise)
|
||||||
|
(is (= "text/xml" (get-in @result [:headers "Content-Type"])))
|
||||||
|
(is (get-in @result [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))
|
||||||
|
|
||||||
(testing "3-arity"
|
(testing "from path"
|
||||||
(let [result (atom nil)
|
(let [app (ring/ring-handler
|
||||||
respond (partial reset! result)
|
(ring/router
|
||||||
raise ::not-called]
|
["/files/*" (ring/create-resource-handler)])
|
||||||
(app (request "/hello.xml") respond raise)
|
(ring/create-default-handler))
|
||||||
(is (= "text/xml" (get-in @result [:headers "Content-Type"])))
|
request #(request (str "/files" %))
|
||||||
(is (get-in @result [:headers "Last-Modified"]))
|
redirect #(redirect (str "/files" %))]
|
||||||
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result))))))))))
|
(testing test
|
||||||
|
(testing "different file-types"
|
||||||
|
(let [response (app (request "/hello.json"))]
|
||||||
|
(is (= "application/json" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
|
||||||
|
(let [response (app (request "/hello.xml"))]
|
||||||
|
(is (= "text/xml" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
|
||||||
|
|
||||||
|
(testing "index-files"
|
||||||
|
(let [response (app (request "/docs"))]
|
||||||
|
(is (= (redirect "/docs/index.html") response)))
|
||||||
|
(let [response (app (request "/docs/"))]
|
||||||
|
(is (= (redirect "/docs/index.html") response))))
|
||||||
|
|
||||||
|
(testing "not found"
|
||||||
|
(let [response (app (request "/not-found"))]
|
||||||
|
(is (= 404 (:status response)))))
|
||||||
|
|
||||||
|
(testing "3-arity"
|
||||||
|
(let [result (atom nil)
|
||||||
|
respond (partial reset! result)
|
||||||
|
raise ::not-called]
|
||||||
|
(app (request "/hello.xml") respond raise)
|
||||||
|
(is (= "text/xml" (get-in @result [:headers "Content-Type"])))
|
||||||
|
(is (get-in @result [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result))))))))))
|
||||||
|
|
||||||
|
(testing "outside a router"
|
||||||
|
|
||||||
|
(testing "from root"
|
||||||
|
(let [app (ring/ring-handler
|
||||||
|
(ring/router [])
|
||||||
|
(ring/routes
|
||||||
|
(ring/create-resource-handler {:path "/"})
|
||||||
|
(ring/create-default-handler)))]
|
||||||
|
(testing test
|
||||||
|
(testing "different file-types"
|
||||||
|
(let [response (app (request "/hello.json"))]
|
||||||
|
(is (= "application/json" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
|
||||||
|
(let [response (app (request "/hello.xml"))]
|
||||||
|
(is (= "text/xml" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
|
||||||
|
|
||||||
|
(testing "index-files"
|
||||||
|
(let [response (app (request "/docs"))]
|
||||||
|
(is (= (redirect "/docs/index.html") response)))
|
||||||
|
(let [response (app (request "/docs/"))]
|
||||||
|
(is (= (redirect "/docs/index.html") response))))
|
||||||
|
|
||||||
|
(testing "not found"
|
||||||
|
(let [response (app (request "/not-found"))]
|
||||||
|
(is (= 404 (:status response)))))
|
||||||
|
|
||||||
|
(testing "3-arity"
|
||||||
|
(let [result (atom nil)
|
||||||
|
respond (partial reset! result)
|
||||||
|
raise ::not-called]
|
||||||
|
(app (request "/hello.xml") respond raise)
|
||||||
|
(is (= "text/xml" (get-in @result [:headers "Content-Type"])))
|
||||||
|
(is (get-in @result [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))
|
||||||
|
|
||||||
|
(testing "from path"
|
||||||
|
(let [app (ring/ring-handler
|
||||||
|
(ring/router [])
|
||||||
|
(ring/routes
|
||||||
|
(ring/create-resource-handler {:path "/files"})
|
||||||
|
(ring/create-default-handler)))
|
||||||
|
request #(request (str "/files" %))
|
||||||
|
redirect #(redirect (str "/files" %))]
|
||||||
|
(testing test
|
||||||
|
(testing "different file-types"
|
||||||
|
(let [response (app (request "/hello.json"))]
|
||||||
|
(is (= "application/json" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "{\"hello\": \"file\"}" (slurp (:body response)))))
|
||||||
|
(let [response (app (request "/hello.xml"))]
|
||||||
|
(is (= "text/xml" (get-in response [:headers "Content-Type"])))
|
||||||
|
(is (get-in response [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body response))))))
|
||||||
|
|
||||||
|
(testing "index-files"
|
||||||
|
(let [response (app (request "/docs"))]
|
||||||
|
(is (= (redirect "/docs/index.html") response)))
|
||||||
|
(let [response (app (request "/docs/"))]
|
||||||
|
(is (= (redirect "/docs/index.html") response))))
|
||||||
|
|
||||||
|
(testing "not found"
|
||||||
|
(let [response (app (request "/not-found"))]
|
||||||
|
(is (= 404 (:status response)))))
|
||||||
|
|
||||||
|
(testing "3-arity"
|
||||||
|
(let [result (atom nil)
|
||||||
|
respond (partial reset! result)
|
||||||
|
raise ::not-called]
|
||||||
|
(app (request "/hello.xml") respond raise)
|
||||||
|
(is (= "text/xml" (get-in @result [:headers "Content-Type"])))
|
||||||
|
(is (get-in @result [:headers "Last-Modified"]))
|
||||||
|
(is (= "<xml><hello>file</hello></xml>\n" (slurp (:body @result)))))))))))))
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,20 @@
|
||||||
(ns reitit.spec-test
|
(ns reitit.spec-test
|
||||||
(:require [clojure.test :refer [deftest testing is are]]
|
(:require [clojure.test :refer [deftest testing is are use-fixtures]]
|
||||||
[#?(:clj clojure.spec.test.alpha :cljs cljs.spec.test.alpha) :as stest]
|
[#?(:clj clojure.spec.test.alpha :cljs cljs.spec.test.alpha) :as stest]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[reitit.core :as r]
|
[reitit.core :as r]
|
||||||
[reitit.spec :as rs]
|
[reitit.spec :as rs])
|
||||||
[expound.alpha :as e])
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(:import (clojure.lang ExceptionInfo))))
|
(:import (clojure.lang ExceptionInfo))))
|
||||||
|
|
||||||
(stest/instrument)
|
(defn instrument-all [f]
|
||||||
|
(try
|
||||||
|
(stest/instrument)
|
||||||
|
(f)
|
||||||
|
(finally
|
||||||
|
(stest/unstrument))))
|
||||||
|
|
||||||
|
(use-fixtures :each instrument-all)
|
||||||
|
|
||||||
(deftest router-spec-test
|
(deftest router-spec-test
|
||||||
|
|
||||||
|
|
@ -40,9 +46,9 @@
|
||||||
;; path
|
;; path
|
||||||
[:invalid {}]
|
[:invalid {}]
|
||||||
|
|
||||||
;; vector data
|
;; nested path
|
||||||
["/api" []
|
["/api"
|
||||||
["/ipa"]])))
|
[:ipa]])))
|
||||||
|
|
||||||
(testing "routes conform to spec (can't spec protocol functions)"
|
(testing "routes conform to spec (can't spec protocol functions)"
|
||||||
(is (s/valid? ::rs/routes (r/routes (r/router ["/ping"])))))
|
(is (s/valid? ::rs/routes (r/routes (r/router ["/ping"])))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue