-
Notifications
You must be signed in to change notification settings - Fork 0
Middleware
Gate middleware is just standard Ring middleware, but Gate does a few things which makes it even nicer to use.
Ring middleware is any function that accepts a handler and returns a function accepting a request.
(defn upperware
[handler]
(fn [request]
(let [response (handler request)
body (get response :body)]
(assoc response :body (clojure.string/upper-case body)))))
There are a bunch of different ways you can apply middleware to handlers with Gate.
First off, you can apply middleware to all the routes in a router by adding that middleware to the :middleware
vector of a router's settings. In the following example the middleware upperware
will be added to all of the routes in the router.
(defrouter your-router
[{:path "/hello"
:get (fn [_] "Hello!")}
{:path "/goodbye"
:get (fn [_] "Goodbye!")}]
{:middleware [upperware]})
Many times, however, you don't want middleware to apply to all of your routes. In that case you can apply middleware to just a single route by adding a :middleware
vector to that route. In the following example upperware
will only be applied on the route /hello
.
(defrouter your-router
[{:path "/hello"
:middleware [upperware]
:get (fn [_] "Hello!")}
{:path "/goodbye"
:get (fn [_] "Goodbye!")}])
Middleware from a parent route is applied to all child routes. In the following example the route /hello/:name
has upperware
applied to it because the /hello/:name
is a child route to /hello
.
(defrouter your-router
[{:path "/hello"
:middleware [upperware]
:get (fn [_] "Hello!")
:children [
{:path "/:name"
:get (fn [req]
(let [name (get-in req [:params :name])]
(str "Hello, " name "!")))}]}])
You can even restrict middleware to a certain method of a route. In the following example upperware
is applied to GET requests, but not to POST requests.
(defrouter your-router
[{:path "/hello"
:get {:handler (fn [_] "Hello!")
:middleware [upperware]}
:post (fn [_] "Nothing here!")}])
If more than one middleware is added to a middleware vector, they are applied in left-to-right/top-to-bottom order.
:middleware
vectors accept middleware functions, as shown above, but they can also accept sequences of middleware functions. This makes it exceedingly simple to combine middlewares that need to be used together into a single middleware.
Compojure has a middleware compojure.handler/api
that combines together three ring middlewares and is defined like this:
(defn api
[routes]
(-> routes
wrap-keyword-params
wrap-nested-params
wrap-params))
Gate could define a similar middleware thusly:
(def api
[wrap-params
wrap-nested-params
wrap-keyword-params])
Notice that unlike threaded middleware which are defined in reverse order of application, the vector of middleware are in order of application.
To use this combined middleware, you would just add it to a vector of middlewares like normal.
(defrouter your-router
[{:path "/hello"
:middleware [api]
:get (fn [_] "Hello!")}])