reitit/doc/basics/route_data.md

96 lines
3 KiB
Markdown
Raw Normal View History

2017-12-10 14:57:09 +00:00
# Route Data
2017-10-29 07:29:06 +00:00
2018-06-10 04:45:23 +00:00
Route data is the core feature of reitit. Routes can have any map-like data attached to them. This data is interpreted either by the client application or the `Router` via its `:coerce` and `:compile` hooks. Route data format can be defined and validated with `clojure.spec` enabling a architecture of both [adaptive and principled](https://youtu.be/x9pxbnFC4aQ?t=1907) components.
2018-02-11 17:15:25 +00:00
Raw routes can have a non-sequential route argument that is expanded (via router `:expand` hook) into route data at router creation time. By default, Keywords are expanded into `:name` and functions into `:handler` keys.
```clj
(require '[reitit.core :as r])
(def router
(r/router
[["/ping" ::ping]
["/pong" identity]
["/users" {:get {:roles #{:admin}
:handler identity}}]]))
```
The 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.
```clj
(r/routes router)
; [["/ping" {:name :user/ping}]
; ["/pong" {:handler identity]}
; ["/users" {:get {:roles #{:admin}
; :handler identity}}]]
2018-02-11 17:15:25 +00:00
```
2018-02-11 17:15:25 +00:00
```clj
(r/match-by-path router "/ping")
; #Match{:template "/ping"
2017-11-18 10:47:16 +00:00
; :data {:name :user/ping}
; :result nil
2018-02-01 14:23:44 +00:00
; :path-params {}
; :path "/ping"}
2018-02-11 17:15:25 +00:00
```
2018-02-11 17:15:25 +00:00
```clj
(r/match-by-name router ::ping)
; #Match{:template "/ping"
2017-11-18 10:47:16 +00:00
; :data {:name :user/ping}
; :result nil
2018-02-01 14:23:44 +00:00
; :path-params {}
; :path "/ping"}
```
## Nested route data
For nested route trees, route data is accumulated recursively from root towards leafs using [meta-merge](https://github.com/weavejester/meta-merge). Default behavior for colections is `:append`, but this can be overridden to `:prepend`, `:replace` or `:displace` using the target meta-data.
2017-10-29 07:29:06 +00:00
An example router with nested data:
```clj
(def router
(r/router
["/api" {:interceptors [::api]}
["/ping" ::ping]
["/admin" {:roles #{:admin}}
["/users" ::users]
["/db" {:interceptors [::db]
:roles ^:replace #{:db-admin}}]]]))
2017-10-29 07:29:06 +00:00
```
Resolved route tree:
```clj
(r/routes router)
2017-10-29 07:29:06 +00:00
; [["/api/ping" {:interceptors [::api]
; :name :user/ping}]
2017-10-29 07:29:06 +00:00
; ["/api/admin/users" {:interceptors [::api]
; :roles #{:admin}
; :name ::users} nil]
; ["/api/admin/db" {:interceptors [::api ::db]
; :roles #{:db-admin}}]]
2017-10-29 07:29:06 +00:00
```
## Expansion
2018-02-11 17:15:25 +00:00
By default, router `:expand` hook maps to `reitit.core/expand` function, backed by a `reitit.core/Expand` protocol. One can provide either a totally different function or add new implementations to that protocol. Expand implementations can be recursive.
2017-10-29 07:29:06 +00:00
2018-02-11 17:15:25 +00:00
Naive example to add direct support for `java.io.File` route argument:
2018-02-11 17:15:25 +00:00
```clj
(extend-type java.io.File
r/Expand
(expand [file options]
(r/expand
#(slurp file)
options)))
(r/router
["/" (java.io.File. "index.html")])
2017-10-29 07:29:06 +00:00
```
2018-02-11 17:15:25 +00:00
See [router options](../advanced/configuring_routers.md) for all available options.