mirror of
https://github.com/metosin/reitit.git
synced 2026-01-09 00:29:51 +00:00
Merge pull request #17 from metosin/MiddlewareRouter
Middleware router (approved with #16)
This commit is contained in:
commit
6a8f94283a
5 changed files with 313 additions and 166 deletions
192
README.md
192
README.md
|
|
@ -25,15 +25,22 @@ Simple route:
|
|||
Two routes:
|
||||
|
||||
```clj
|
||||
[["/ping]
|
||||
["/pong]]
|
||||
[["/ping"]
|
||||
["/pong"]]
|
||||
```
|
||||
|
||||
Routes with meta-data:
|
||||
|
||||
```clj
|
||||
[["/ping ::ping]
|
||||
["/pong {:name ::pong}]]
|
||||
[["/ping" ::ping]
|
||||
["/pong" {:name ::pong}]]
|
||||
```
|
||||
|
||||
Routes with path and catch-all parameters:
|
||||
|
||||
```clj
|
||||
[["/users/:user-id"]
|
||||
["/public/*path"]]
|
||||
```
|
||||
|
||||
Nested routes with meta-data:
|
||||
|
|
@ -60,7 +67,7 @@ For actual routing, we need to create a `Router`. Reitit ships with 2 different
|
|||
|
||||
`Router` is created with `reitit.core/router`, which takes routes and optionally an options map as arguments. The route-tree gets expanded, optionally coerced and compiled to support both fast path- and name-based lookups.
|
||||
|
||||
Create a router:
|
||||
Creating a router:
|
||||
|
||||
```clj
|
||||
(require '[reitit.core :as reitit])
|
||||
|
|
@ -70,12 +77,16 @@ Create a router:
|
|||
[["/api"
|
||||
["/ping" ::ping]
|
||||
["/user/:id" ::user]]))
|
||||
```
|
||||
|
||||
`LinearRouter` is created (as there are wildcard):
|
||||
|
||||
```clj
|
||||
(class router)
|
||||
; reitit.core.LinearRouter
|
||||
```
|
||||
|
||||
Get the expanded routes:
|
||||
The expanded routes:
|
||||
|
||||
```clj
|
||||
(reitit/routes router)
|
||||
|
|
@ -102,11 +113,7 @@ Name-based (reverse) routing:
|
|||
```clj
|
||||
(reitit/match-by-name router ::user)
|
||||
; ExceptionInfo missing path-params for route '/api/user/:id': #{:id}
|
||||
```
|
||||
|
||||
Oh, that didn't work, retry:
|
||||
|
||||
```clj
|
||||
(reitit/match-by-name router ::user {:id "1"})
|
||||
; #Match{:template "/api/user/:id"
|
||||
; :meta {:name :user/user}
|
||||
|
|
@ -122,57 +129,192 @@ Routes can have arbitrary meta-data. For nested routes, the meta-data is accumul
|
|||
A router based on nested route tree:
|
||||
|
||||
```clj
|
||||
(def ring-router
|
||||
(def router
|
||||
(reitit/router
|
||||
["/api" {:middleware [:api-mw]}
|
||||
["/api" {:interceptors [::api]}
|
||||
["/ping" ::ping]
|
||||
["/public/*path" ::resources]
|
||||
["/user/:id" {:name ::get-user
|
||||
:parameters {:id String}}
|
||||
["/orders" ::user-orders]]
|
||||
["/admin" {:middleware [:admin-mw]
|
||||
["/admin" {:interceptors [::admin]
|
||||
:roles #{:admin}}
|
||||
["/root" {:name ::root
|
||||
:roles ^:replace #{:root}}]
|
||||
["/db" {:name ::db
|
||||
:middleware [:db-mw]}]]]))
|
||||
:interceptors [::db]}]]]))
|
||||
```
|
||||
|
||||
Expanded and merged route tree:
|
||||
Resolved route tree:
|
||||
|
||||
```clj
|
||||
(reitit/routes ring-router)
|
||||
(reitit/routes router)
|
||||
; [["/api/ping" {:name :user/ping
|
||||
; :middleware [:api-mw]}]
|
||||
; :interceptors [::api]}]
|
||||
; ["/api/public/*path" {:name :user/resources
|
||||
; :middleware [:api-mw]}]
|
||||
; :interceptors [::api]}]
|
||||
; ["/api/user/:id/orders" {:name :user/user-orders
|
||||
; :middleware [:api-mw]
|
||||
; :interceptors [::api]
|
||||
; :parameters {:id String}}]
|
||||
; ["/api/admin/root" {:name :user/root
|
||||
; :middleware [:api-mw :admin-mw]
|
||||
; :interceptors [::api ::admin]
|
||||
; :roles #{:root}}]
|
||||
; ["/api/admin/db" {:name :user/db
|
||||
; :middleware [:api-mw :admin-mw :db-mw]
|
||||
; :interceptors [::api ::admin ::db]
|
||||
; :roles #{:admin}}]]
|
||||
```
|
||||
|
||||
Path-based routing:
|
||||
|
||||
```clj
|
||||
(reitit/match-by-path ring-router "/api/admin/root")
|
||||
(reitit/match-by-path router "/api/admin/root")
|
||||
; #Match{:template "/api/admin/root"
|
||||
; :meta {:name :user/root
|
||||
; :middleware [:api-mw :admin-mw]
|
||||
; :interceptors [::api ::admin]
|
||||
; :roles #{:root}}
|
||||
; :path "/api/admin/root"
|
||||
; :handler nil
|
||||
; :params {}}
|
||||
```
|
||||
|
||||
Route meta-data is just data and the actual interpretation is left to the application. Custom coercion and route compilation can be defined via router options enabling things like [`clojure.spec`](https://clojure.org/about/spec) validation for route-meta data and pre-compiled route handlers ([Ring](https://github.com/ring-clojure/ring)-handlers or [Pedestal](pedestal.io)-style interceptors).
|
||||
On match, route meta-data is returned and can interpreted by the application.
|
||||
|
||||
**TODO**: examples / implementations of different kind of routers. See [Open issues](https://github.com/metosin/reitit/issues/).
|
||||
Routers also support meta-data compilation enabling things like fast [Ring](https://github.com/ring-clojure/ring) or [Pedestal](http://pedestal.io/) -style handlers. Compilation results are found under `:handler` in the match. See [configuring routers](configuring-routers) for details.
|
||||
|
||||
## Ring
|
||||
|
||||
Simple [Ring](https://github.com/ring-clojure/ring)-based routing app:
|
||||
|
||||
```clj
|
||||
(require '[reitit.ring :as ring])
|
||||
|
||||
(defn handler [_]
|
||||
{:status 200, :body "ok"})
|
||||
|
||||
(def app
|
||||
(ring/ring-handler
|
||||
(ring/router
|
||||
["/ping" handler])))
|
||||
```
|
||||
|
||||
It's backed by a `LookupRouter` (no wildcards!)
|
||||
|
||||
```clj
|
||||
(-> app (ring/get-router) class)
|
||||
; reitit.core.LookupRouter
|
||||
```
|
||||
|
||||
The expanded routes:
|
||||
|
||||
```clj
|
||||
(-> app (ring/get-router) (reitit/routes))
|
||||
; [["/ping" {:handler #object[...]}]]
|
||||
```
|
||||
|
||||
Applying the handler:
|
||||
|
||||
```clj
|
||||
(app {:request-method :get, :uri "/favicon.ico"})
|
||||
; nil
|
||||
|
||||
(app {:request-method :get, :uri "/ping"})
|
||||
; {:status 200, :body "ok"}
|
||||
```
|
||||
|
||||
Routing based on `:request-method`:
|
||||
|
||||
```clj
|
||||
(def app
|
||||
(ring/ring-handler
|
||||
(ring/router
|
||||
["/ping" {:get handler
|
||||
:post handler}])))
|
||||
|
||||
(app {:request-method :get, :uri "/ping"})
|
||||
; {:status 200, :body "ok"}
|
||||
|
||||
(app {:request-method :put, :uri "/ping"})
|
||||
; nil
|
||||
```
|
||||
|
||||
Define some middleware and a new handler:
|
||||
|
||||
```clj
|
||||
(defn wrap [handler id]
|
||||
(fn [request]
|
||||
(handler (update request ::acc (fnil conj []) id))))
|
||||
|
||||
(defn wrap-api [handler]
|
||||
(wrap handler :api))
|
||||
|
||||
(defn handler [{:keys [::acc]}]
|
||||
{:status 200, :body (conj acc :handler)})
|
||||
```
|
||||
|
||||
App with nested middleware:
|
||||
|
||||
```clj
|
||||
(def app
|
||||
(ring/ring-handler
|
||||
(ring/router
|
||||
["/api" {:middleware [wrap-api]}
|
||||
["/ping" handler]
|
||||
["/admin" {:middleware [[wrap :admin]]}
|
||||
["/db" {:middleware [[wrap :db]]
|
||||
:delete {:middleware [#(wrap % :delete)]
|
||||
:handler handler}}]]])))
|
||||
```
|
||||
|
||||
Middleware is applied correctly:
|
||||
|
||||
```clj
|
||||
(app {:request-method :delete, :uri "/api/ping"})
|
||||
; {:status 200, :body [:api :handler]}
|
||||
```
|
||||
|
||||
Nested middleware works too:
|
||||
|
||||
```clj
|
||||
(app {:request-method :delete, :uri "/api/admin/db"})
|
||||
; {:status 200, :body [:api :admin :db :delete :handler]}
|
||||
```
|
||||
|
||||
Ring-router supports also 3-arity [Async Ring](https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html), so it can be used on [Node.js](https://nodejs.org/en/) too.
|
||||
|
||||
## Validating route-tree
|
||||
|
||||
**TODO**
|
||||
|
||||
## Merging route-trees
|
||||
|
||||
**TODO**
|
||||
|
||||
## Schema, Spec, Swagger & Openapi
|
||||
|
||||
**TODO**
|
||||
|
||||
## Interceptors
|
||||
|
||||
**TODO**
|
||||
|
||||
## Custom extensions
|
||||
|
||||
**TODO**
|
||||
|
||||
## Configuring Routers
|
||||
|
||||
Routers can be configured via options to do things like custom coercion and compilatin of meta-data. These can be used to do things like [`clojure.spec`](https://clojure.org/about/spec) validation of meta-data and fast, compiled [Ring](https://github.com/ring-clojure/ring/wiki/Concepts) or [Pedestal](http://pedestal.io/) -style handlers.
|
||||
|
||||
The following options are available for the `Router`:
|
||||
|
||||
| key | description |
|
||||
| -----------|-------------|
|
||||
| `:path` | Base-path for routes (default `""`)
|
||||
| `:routes` | Initial resolved routes (default `[]`)
|
||||
| `:meta` | Initial expanded route-meta vector (default `[]`)
|
||||
| `:expand` | Function of `arg => meta` to expand route arg to route meta-data (default `reitit.core/expand`)
|
||||
| `:coerce` | Function of `[path meta] opts => [path meta]` to coerce resolved route, can throw or return `nil`
|
||||
| `:compile` | Function of `[path meta] opts => handler` to compile a route handler
|
||||
|
||||
## Special thanks
|
||||
|
||||
|
|
|
|||
|
|
@ -142,14 +142,14 @@
|
|||
If routes contain wildcards, a [[LinearRouter]] is used, otherwise a
|
||||
[[LookupRouter]]. The following options are available:
|
||||
|
||||
| keys | description |
|
||||
| key | description |
|
||||
| -----------|-------------|
|
||||
| `:path` | Base-path for routes (default `\"\"`)
|
||||
| `:routes` | Initial resolved routes (default `[]`)
|
||||
| `:meta` | Initial expanded route-meta vector (default `[]`)
|
||||
| `:expand` | Function `arg => meta` to expand route arg to route meta-data (default `reitit.core/expand`)
|
||||
| `:coerce` | Function `[path meta] opts => [path meta]` to coerce resolved route, can throw or return `nil`
|
||||
| `:compile` | Function `[path meta] opts => handler` to compile a route handler"
|
||||
| `:expand` | Function of `arg => meta` to expand route arg to route meta-data (default `reitit.core/expand`)
|
||||
| `:coerce` | Function of `[path meta] opts => [path meta]` to coerce resolved route, can throw or return `nil`
|
||||
| `:compile` | Function of `[path meta] opts => handler` to compile a route handler"
|
||||
([data]
|
||||
(router data {}))
|
||||
([data opts]
|
||||
|
|
|
|||
44
src/reitit/middleware.cljc
Normal file
44
src/reitit/middleware.cljc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
(ns reitit.middleware
|
||||
(:require [reitit.core :as reitit]))
|
||||
|
||||
(defprotocol ExpandMiddleware
|
||||
(expand-middleware [this]))
|
||||
|
||||
(extend-protocol ExpandMiddleware
|
||||
|
||||
#?(:clj clojure.lang.APersistentVector
|
||||
:cljs cljs.core.PersistentVector)
|
||||
(expand-middleware [[f & args]]
|
||||
(fn [handler]
|
||||
(apply f handler args)))
|
||||
|
||||
#?(:clj clojure.lang.Fn
|
||||
:cljs function)
|
||||
(expand-middleware [this] this)
|
||||
|
||||
nil
|
||||
(expand-middleware [_]))
|
||||
|
||||
(defn- ensure-handler! [path meta scope]
|
||||
(when-not (:handler meta)
|
||||
(throw (ex-info
|
||||
(str "path \"" path "\" doesn't have a :handler defined"
|
||||
(if scope (str " for " scope)))
|
||||
(merge {:path path, :meta meta}
|
||||
(if scope {:scope scope}))))))
|
||||
|
||||
(defn compose-middleware [middleware]
|
||||
(->> middleware
|
||||
(keep identity)
|
||||
(map expand-middleware)
|
||||
(apply comp identity)))
|
||||
|
||||
(defn compile-handler
|
||||
([route opts]
|
||||
(compile-handler route opts nil))
|
||||
([[path {:keys [middleware handler] :as meta}] _ scope]
|
||||
(ensure-handler! path meta scope)
|
||||
((compose-middleware middleware) handler)))
|
||||
|
||||
(defn router [data]
|
||||
(reitit/router data {:compile compile-handler}))
|
||||
|
|
@ -1,47 +1,17 @@
|
|||
(ns reitit.ring
|
||||
(:require [meta-merge.core :refer [meta-merge]]
|
||||
[reitit.middleware :as middleware]
|
||||
[reitit.core :as reitit]))
|
||||
|
||||
(defprotocol ExpandMiddleware
|
||||
(expand-middleware [this]))
|
||||
(def http-methods #{:get :head :patch :delete :options :post :put})
|
||||
(defrecord MethodHandlers [get head patch delete options post put])
|
||||
|
||||
(extend-protocol ExpandMiddleware
|
||||
|
||||
#?(:clj clojure.lang.APersistentVector
|
||||
:cljs cljs.core.PersistentVector)
|
||||
(expand-middleware [[f & args]]
|
||||
(fn [handler]
|
||||
(apply f handler args)))
|
||||
|
||||
#?(:clj clojure.lang.Fn
|
||||
:cljs function)
|
||||
(expand-middleware [this] this)
|
||||
|
||||
nil
|
||||
(expand-middleware [_]))
|
||||
|
||||
(defn- ensure-handler! [path meta method]
|
||||
(when-not (:handler meta)
|
||||
(throw (ex-info
|
||||
(str "path \"" path "\" doesn't have a :handler defined"
|
||||
(if method (str " for method " method)))
|
||||
{:path path, :method method, :meta meta}))))
|
||||
|
||||
(defn- compose-middleware [middleware]
|
||||
(->> middleware
|
||||
(keep identity)
|
||||
(map expand-middleware)
|
||||
(apply comp identity)))
|
||||
|
||||
(defn- compile-handler
|
||||
([route opts]
|
||||
(compile-handler route opts nil))
|
||||
([[path {:keys [middleware handler] :as meta}] _ method]
|
||||
(ensure-handler! path meta method)
|
||||
((compose-middleware middleware) handler)))
|
||||
|
||||
(defn simple-router [data]
|
||||
(reitit/router data {:compile compile-handler}))
|
||||
(defn- group-keys [meta]
|
||||
(reduce-kv
|
||||
(fn [[top childs] k v]
|
||||
(if (http-methods k)
|
||||
[top (assoc childs k v)]
|
||||
[(assoc top k v) childs])) [{} {}] meta))
|
||||
|
||||
(defn ring-handler [router]
|
||||
(with-meta
|
||||
|
|
@ -57,33 +27,24 @@
|
|||
(defn get-router [handler]
|
||||
(some-> handler meta ::router))
|
||||
|
||||
(def http-methods #{:get :head :patch :delete :options :post :put})
|
||||
(defrecord MethodHandlers [get head patch delete options post put])
|
||||
|
||||
(defn- group-keys [meta]
|
||||
(reduce-kv
|
||||
(fn [[top childs] k v]
|
||||
(if (http-methods k)
|
||||
[top (assoc childs k v)]
|
||||
[(assoc top k v) childs])) [{} {}] meta))
|
||||
|
||||
(defn coerce-method-handler [[path meta] {:keys [expand]}]
|
||||
(defn coerce-handler [[path meta] {:keys [expand]}]
|
||||
[path (reduce
|
||||
(fn [acc method]
|
||||
(if (contains? acc method)
|
||||
(update acc method expand)
|
||||
acc)) meta http-methods)])
|
||||
|
||||
(defn compile-method-handler [[path meta] opts]
|
||||
(defn compile-handler [[path meta] opts]
|
||||
(let [[top childs] (group-keys meta)]
|
||||
(if-not (seq childs)
|
||||
(compile-handler [path meta] opts)
|
||||
(middleware/compile-handler [path meta] opts)
|
||||
(let [handlers (map->MethodHandlers
|
||||
(reduce-kv
|
||||
#(assoc %1 %2 (compile-handler [path (meta-merge top %3)] opts %2))
|
||||
#(assoc %1 %2 (middleware/compile-handler
|
||||
[path (meta-merge top %3)] opts %2))
|
||||
{} childs))
|
||||
default-handler (if (:handler top) (compile-handler [path meta] opts))
|
||||
resolved-handler (fn [method] (or (method handlers) default-handler))]
|
||||
default-handler (if (:handler top) (middleware/compile-handler [path meta] opts))
|
||||
resolved-handler #(or (% handlers) default-handler)]
|
||||
(fn
|
||||
([request]
|
||||
(if-let [handler (resolved-handler (:request-method request))]
|
||||
|
|
@ -92,6 +53,6 @@
|
|||
(if-let [handler (resolved-handler (:request-method request))]
|
||||
(handler request respond raise))))))))
|
||||
|
||||
(defn method-router [data]
|
||||
(reitit/router data {:coerce coerce-method-handler
|
||||
:compile compile-method-handler}))
|
||||
(defn router [data]
|
||||
(reitit/router data {:coerce coerce-handler
|
||||
:compile compile-handler}))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
(ns reitit.ring-test
|
||||
(:require [clojure.test :refer [deftest testing is]]
|
||||
[reitit.middleware :as middleware]
|
||||
[reitit.ring :as ring])
|
||||
#?(:clj
|
||||
(:import (clojure.lang ExceptionInfo))))
|
||||
|
|
@ -23,102 +24,101 @@
|
|||
([request respond raise]
|
||||
(respond (handler request))))
|
||||
|
||||
(deftest ring-test
|
||||
(deftest middleware-router-test
|
||||
|
||||
(testing "simple-router"
|
||||
(testing "all paths should have a handler"
|
||||
(is (thrown-with-msg?
|
||||
ExceptionInfo
|
||||
#"path \"/ping\" doesn't have a :handler defined"
|
||||
(middleware/router ["/ping"]))))
|
||||
|
||||
(testing "all paths should have a handler"
|
||||
(is (thrown-with-msg?
|
||||
ExceptionInfo
|
||||
#"path \"/ping\" doesn't have a :handler defined"
|
||||
(ring/simple-router ["/ping"]))))
|
||||
(testing "ring-handler"
|
||||
(let [api-mw #(mw % :api)
|
||||
router (middleware/router
|
||||
[["/ping" handler]
|
||||
["/api" {:middleware [api-mw]}
|
||||
["/ping" handler]
|
||||
["/admin" {:middleware [[mw :admin]]}
|
||||
["/ping" handler]]]])
|
||||
app (ring/ring-handler router)]
|
||||
|
||||
(testing "ring-handler"
|
||||
(let [api-mw #(mw % :api)
|
||||
router (ring/simple-router
|
||||
[["/ping" handler]
|
||||
["/api" {:middleware [api-mw]}
|
||||
["/ping" handler]
|
||||
["/admin" {:middleware [[mw :admin]]}
|
||||
["/ping" handler]]]])
|
||||
app (ring/ring-handler router)]
|
||||
(testing "router can be extracted"
|
||||
(is (= router (ring/get-router app))))
|
||||
|
||||
(testing "router can be extracted"
|
||||
(is (= router (ring/get-router app))))
|
||||
(testing "not found"
|
||||
(is (= nil (app {:uri "/favicon.ico"}))))
|
||||
|
||||
(testing "not found"
|
||||
(is (= nil (app {:uri "/favicon.ico"}))))
|
||||
(testing "normal handler"
|
||||
(is (= {:status 200, :body [:ok]}
|
||||
(app {:uri "/ping"}))))
|
||||
|
||||
(testing "normal handler"
|
||||
(is (= {:status 200, :body [:ok]}
|
||||
(app {:uri "/ping"}))))
|
||||
(testing "with middleware"
|
||||
(is (= {:status 200, :body [:api :ok :api]}
|
||||
(app {:uri "/api/ping"}))))
|
||||
|
||||
(testing "with middleware"
|
||||
(is (= {:status 200, :body [:api :ok :api]}
|
||||
(app {:uri "/api/ping"}))))
|
||||
(testing "with nested middleware"
|
||||
(is (= {:status 200, :body [:api :admin :ok :admin :api]}
|
||||
(app {:uri "/api/admin/ping"}))))
|
||||
|
||||
(testing "with nested middleware"
|
||||
(testing "3-arity"
|
||||
(let [result (atom nil)
|
||||
respond (partial reset! result), raise ::not-called]
|
||||
(app {:uri "/api/admin/ping"} respond raise)
|
||||
(is (= {:status 200, :body [:api :admin :ok :admin :api]}
|
||||
(app {:uri "/api/admin/ping"}))))
|
||||
@result)))))))
|
||||
|
||||
(testing "3-arity"
|
||||
(let [result (atom nil)
|
||||
respond (partial reset! result), raise ::not-called]
|
||||
(app {:uri "/api/admin/ping"} respond raise)
|
||||
(is (= {:status 200, :body [:api :admin :ok :admin :api]}
|
||||
@result)))))))
|
||||
|
||||
(testing "method-router"
|
||||
(deftest ring-router-test
|
||||
|
||||
(testing "all paths should have a handler"
|
||||
(is (thrown-with-msg?
|
||||
ExceptionInfo
|
||||
#"path \"/ping\" doesn't have a :handler defined for method :get"
|
||||
(ring/method-router ["/ping" {:get {}}]))))
|
||||
(testing "all paths should have a handler"
|
||||
(is (thrown-with-msg?
|
||||
ExceptionInfo
|
||||
#"path \"/ping\" doesn't have a :handler defined for :get"
|
||||
(ring/router ["/ping" {:get {}}]))))
|
||||
|
||||
(testing "ring-handler"
|
||||
(let [api-mw #(mw % :api)
|
||||
router (ring/method-router
|
||||
[["/api" {:middleware [api-mw]}
|
||||
["/all" handler]
|
||||
["/get" {:get handler}]
|
||||
["/users" {:middleware [[mw :users]]
|
||||
:get handler
|
||||
:post {:handler handler
|
||||
:middleware [[mw :post]]}
|
||||
:handler handler}]]])
|
||||
app (ring/ring-handler router)]
|
||||
(testing "ring-handler"
|
||||
(let [api-mw #(mw % :api)
|
||||
router (ring/router
|
||||
[["/api" {:middleware [api-mw]}
|
||||
["/all" handler]
|
||||
["/get" {:get handler}]
|
||||
["/users" {:middleware [[mw :users]]
|
||||
:get handler
|
||||
:post {:handler handler
|
||||
:middleware [[mw :post]]}
|
||||
:handler handler}]]])
|
||||
app (ring/ring-handler router)]
|
||||
|
||||
(testing "router can be extracted"
|
||||
(is (= router (ring/get-router app))))
|
||||
(testing "router can be extracted"
|
||||
(is (= router (ring/get-router app))))
|
||||
|
||||
(testing "not found"
|
||||
(is (= nil (app {:uri "/favicon.ico"}))))
|
||||
(testing "not found"
|
||||
(is (= nil (app {:uri "/favicon.ico"}))))
|
||||
|
||||
(testing "catch all handler"
|
||||
(is (= {:status 200, :body [:api :ok :api]}
|
||||
(app {:uri "/api/all" :request-method :get}))))
|
||||
(testing "catch all handler"
|
||||
(is (= {:status 200, :body [:api :ok :api]}
|
||||
(app {:uri "/api/all" :request-method :get}))))
|
||||
|
||||
(testing "just get handler"
|
||||
(is (= {:status 200, :body [:api :ok :api]}
|
||||
(app {:uri "/api/get" :request-method :get})))
|
||||
(is (= nil (app {:uri "/api/get" :request-method :post}))))
|
||||
(testing "just get handler"
|
||||
(is (= {:status 200, :body [:api :ok :api]}
|
||||
(app {:uri "/api/get" :request-method :get})))
|
||||
(is (= nil (app {:uri "/api/get" :request-method :post}))))
|
||||
|
||||
(testing "expanded method handler"
|
||||
(is (= {:status 200, :body [:api :users :ok :users :api]}
|
||||
(app {:uri "/api/users" :request-method :get}))))
|
||||
(testing "expanded method handler"
|
||||
(is (= {:status 200, :body [:api :users :ok :users :api]}
|
||||
(app {:uri "/api/users" :request-method :get}))))
|
||||
|
||||
(testing "method handler with middleware"
|
||||
(testing "method handler with middleware"
|
||||
(is (= {:status 200, :body [:api :users :post :ok :post :users :api]}
|
||||
(app {:uri "/api/users" :request-method :post}))))
|
||||
|
||||
(testing "fallback handler"
|
||||
(is (= {:status 200, :body [:api :users :ok :users :api]}
|
||||
(app {:uri "/api/users" :request-method :put}))))
|
||||
|
||||
(testing "3-arity"
|
||||
(let [result (atom nil)
|
||||
respond (partial reset! result), raise ::not-called]
|
||||
(app {:uri "/api/users" :request-method :post} respond raise)
|
||||
(is (= {:status 200, :body [:api :users :post :ok :post :users :api]}
|
||||
(app {:uri "/api/users" :request-method :post}))))
|
||||
|
||||
(testing "fallback handler"
|
||||
(is (= {:status 200, :body [:api :users :ok :users :api]}
|
||||
(app {:uri "/api/users" :request-method :put}))))
|
||||
|
||||
(testing "3-arity"
|
||||
(let [result (atom nil)
|
||||
respond (partial reset! result), raise ::not-called]
|
||||
(app {:uri "/api/users" :request-method :post} respond raise)
|
||||
(is (= {:status 200, :body [:api :users :post :ok :post :users :api]}
|
||||
@result))))))))
|
||||
@result)))))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue