Route data is the key feature of reitit. Routes can have any map-like data attached to them, to be interpreted by the client application, Router or routing components like Middleware or Interceptors.
[["/ping" {:name ::ping}]
["/pong" {:handler identity}]
["/users" {:get {:roles #{:admin}
:handler identity}}]]
Besides map-like data, raw routes can have any non-sequential route argument after the path. This argument is expanded by Router (via :expand option) into route data at router creation time.
By default, Keywords are expanded into :name (see Name-based Routing)
and functions into :handler keys.
(require '[reitit.core :as r])
(def router
(r/router
[["/ping" ::ping]
["/pong" identity]
["/users" {:get {:roles #{:admin}
:handler identity}}]]))
Expanded route data can be retrieved from a router with routes and is returned with match-by-path and match-by-name in case of a route match.
(r/routes router)
; [["/ping" {:name ::ping}]
; ["/pong" {:handler identity]}
; ["/users" {:get {:roles #{:admin}
; :handler identity}}]]
(r/match-by-path router "/ping")
; #Match{:template "/ping"
; :data {:name :user/ping}
; :result nil
; :path-params {}
; :path "/ping"}
(r/match-by-name router ::ping)
; #Match{:template "/ping"
; :data {:name :user/ping}
; :result nil
; :path-params {}
; :path "/ping"}
For nested route trees, route data is accumulated recursively from root towards leafs using meta-merge. Default behavior for collections is :append, but this can be overridden to :prepend, :replace or :displace using the target meta-data.
An example router with nested data:
(def router
(r/router
["/api" {:interceptors [::api]}
["/ping" ::ping]
["/admin" {:roles #{:admin}}
["/users" ::users]
["/db" {:interceptors [::db]
:roles ^:replace #{:db-admin}}]]]))
Resolved route tree:
(r/routes router)
; [["/api/ping" {:interceptors [::api]
; :name :user/ping}]
; ["/api/admin/users" {:interceptors [::api]
; :roles #{:admin}
; :name ::users}]
; ["/api/admin/db" {:interceptors [::api ::db]
; :roles #{:db-admin}}]]
See also nested parameter definitions for coercions
Just like fragments in React.js, we can create routing tree fragments by using empty path "". This allows us to add route data without accumulating to path.
Given a route tree:
[["/swagger.json" ::swagger]
["/api-docs" ::api-docs]
["/api/ping" ::ping]
["/api/pong" ::pong]]
Adding :no-doc route data to exclude the first routes from generated Swagger documentation:
[["" {:no-doc true}
["/swagger.json" ::swagger]
["/api-docs" ::api-docs]]
["/api/ping" ::ping]
["/api/pong" ::pong]]
Accumulated route data:
(def router
(r/router
[["" {:no-doc true}
["/swagger.json" ::swagger]
["/api-docs" ::api-docs]]
["/api/ping" ::ping]
["/api/pong" ::pong]]))
(r/routes router)
; [["/swagger.json" {:no-doc true, :name ::swagger}]
; ["/api-docs" {:no-doc true, :name ::api-docs}]
; ["/api/ping" {:name ::ping}]
; ["/api/pong" {:name ::pong}]]
Route data can be introduced also via Router option :data:
(def router
(r/router
["/api"
{:middleware [::api]}
["/ping" ::ping]
["/pong" ::pong]]
{:data {:middleware [::session]}}))
Expanded routes:
[["/api/ping" {:middleware [::session ::api], :name ::ping}]
["/api/pong" {:middleware [::session ::api], :name ::pong}]]
By default, router :expand option has value r/expand function, backed by a r/Expand protocol. Expansion can be customized either by swapping the :expand implementation or by extending the Protocol. r/Expand implementations can be recursive.
Naive example to add direct support for java.io.File route argument:
(extend-type java.io.File
r/Expand
(expand [file options]
(r/expand
#(slurp file)
options)))
(r/router
["/" (java.io.File. "index.html")])
Page shared routes has an example of an custom :expand implementation.
Can you improve this documentation? These fine people already did:
Tommi Reiman, Joel Kaasinen, zengxinhui, tjalkane & Kanwei LiEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |