Ring is a Clojure web applications library inspired by Python's WSGI and Ruby's Rack. By abstracting the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks.
Read more about the Ring Concepts.
[metosin/reitit-ring "0.3.0"]
reitit.ring/ring-router
ring-router
is a higher order router, which adds support for :request-method
based routing, handlers and middleware.
It accepts the following options:
key | description |
---|---|
:reitit.middleware/transform | Function of [Middleware] => [Middleware] to transform the expanded Middleware (default: identity). |
:reitit.middleware/registry | Map of keyword => IntoMiddleware to replace keyword references into Middleware |
:reitit.ring/default-options-handler | Default handler for :options method in endpoints (default: default-options-handler) |
Example router:
(require '[reitit.ring :as ring])
(defn handler [_]
{:status 200, :body "ok"})
(def router
(ring/router
["/ping" {:get handler}]))
Match contains :result
compiled by the ring-router
:
(require '[reitit.core :as r])
(r/match-by-path router "/ping")
;#Match{:template "/ping"
; :data {:get {:handler #object[...]}}
; :result #Methods{:get #Endpoint{...}
; :options #Endpoint{...}}
; :path-params {}
; :path "/ping"}
reitit.ring/ring-handler
Given a ring-router
, optional default-handler & options, ring-handler
function will return a valid ring handler supporting both synchronous and asynchronous request handling. The following options are available:
key | description |
---|---|
:middleware | Optional sequence of middleware that wrap the ring-handler" |
:inject-match? | Boolean to inject match into request under :reitit.core/match key (default true) |
:inject-router? | Boolean to inject router into request under :reitit.core/router key (default true) |
Simple Ring app:
(def app (ring/ring-handler router))
Applying the handler:
(app {:request-method :get, :uri "/favicon.ico"})
; nil
(app {:request-method :get, :uri "/ping"})
; {:status 200, :body "ok"}
The router can be accessed via get-router
:
(-> app (ring/get-router) (r/compiled-routes))
;[["/ping"
; {:handler #object[...]}
; #Methods{:get #Endpoint{:data {:handler #object[...]}
; :handler #object[...]
; :middleware []}
; :options #Endpoint{:data {:handler #object[...]}
; :handler #object[...]
; :middleware []}}]]
Handlers can be placed either to the top-level (all methods) or under a specific method (:get
, :head
, :patch
, :delete
, :options
, :post
, :put
or :trace
). Top-level handler is used if request-method based handler is not found.
By default, the :options
route is generated for all paths - to enable thing like CORS.
(def app
(ring/ring-handler
(ring/router
[["/all" handler]
["/ping" {:name ::ping
:get handler
:post handler}]])))
Top-level handler catches all methods:
(app {:request-method :delete, :uri "/all"})
; {:status 200, :body "ok"}
Method-level handler catches only the method:
(app {:request-method :get, :uri "/ping"})
; {:status 200, :body "ok"}
(app {:request-method :put, :uri "/ping"})
; nil
By default, :options
is also supported (see router options to change this):
(app {:request-method :options, :uri "/ping"})
; {:status 200, :body ""}
Name-based reverse routing:
(-> app
(ring/get-router)
(r/match-by-name ::ping)
(r/match->path))
; "/ping"
Middleware can be mounted using a :middleware
key - either to top-level or under request method submap. Its value should be a vector of reitit.middleware/IntoMiddleware
values. These include:
handler -> request -> response
[handler args*] -> request -> response
and it's argumentsA middleware and a handler:
(defn wrap [handler id]
(fn [request]
(handler (update request ::acc (fnil conj []) id))))
(defn handler [{:keys [::acc]}]
{:status 200, :body (conj acc :handler)})
App with nested middleware:
(def app
(ring/ring-handler
(ring/router
;; a middleware function
["/api" {:middleware [#(wrap % :api)]}
["/ping" handler]
;; a middleware vector at top level
["/admin" {:middleware [[wrap :admin]]}
["/db" {:middleware [[wrap :db]]
;; a middleware vector at under a method
:delete {:middleware [[wrap :delete]]
:handler handler}}]]])))
Middleware is applied correctly:
(app {:request-method :delete, :uri "/api/ping"})
; {:status 200, :body [:api :handler]}
(app {:request-method :delete, :uri "/api/admin/db"})
; {:status 200, :body [:api :admin :db :delete :handler]}
Top-level middleware, applied before any routing is done:
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[mw :api]]}
["/get" {:get handler}]])
nil
{:middleware [[mw :top]]}))
(app {:request-method :get, :uri "/api/get"})
; {:status 200, :body [:top :api :ok]}
Can you improve this documentation? These fine people already did:
Tommi Reiman & Juho TeperiEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close