diff --git a/advanced/composing_routers.html b/advanced/composing_routers.html index 1328fdfb..5d48095e 100644 --- a/advanced/composing_routers.html +++ b/advanced/composing_routers.html @@ -1150,7 +1150,7 @@ diff --git a/advanced/configuring_routers.html b/advanced/configuring_routers.html index 99eb69ab..0baf2fa1 100644 --- a/advanced/configuring_routers.html +++ b/advanced/configuring_routers.html @@ -856,7 +856,7 @@ diff --git a/advanced/dev_workflow.html b/advanced/dev_workflow.html index 9cdf166f..99467c1a 100644 --- a/advanced/dev_workflow.html +++ b/advanced/dev_workflow.html @@ -915,7 +915,7 @@ diff --git a/advanced/different_routers.html b/advanced/different_routers.html index b91771a8..c0e3b5fc 100644 --- a/advanced/different_routers.html +++ b/advanced/different_routers.html @@ -776,7 +776,7 @@ Matches the routes one-by-one starting from the top until a match is found. Slow, but works with all route trees. -:segment-router +:trie-router Router that creates a optimized search trie out of an route table. Much faster than :linear-router for wildcard routes. Valid only if there are no Route conflicts. @@ -789,7 +789,7 @@ :mixed-router -Contains two routers: :segment-router for wildcard routes and a :lookup-router or :single-static-path-router for static routes. Valid only if there are no Route conflicts. +Contains two routers: :trie-router for wildcard routes and a :lookup-router or :single-static-path-router for static routes. Valid only if there are no Route conflicts. :quarantine-router @@ -863,7 +863,7 @@ diff --git a/advanced/route_validation.html b/advanced/route_validation.html index db58c822..bbdc0dba 100644 --- a/advanced/route_validation.html +++ b/advanced/route_validation.html @@ -951,7 +951,7 @@ diff --git a/advanced/shared_routes.html b/advanced/shared_routes.html index 90cafbe9..8cb17825 100644 --- a/advanced/shared_routes.html +++ b/advanced/shared_routes.html @@ -871,7 +871,7 @@ diff --git a/basics/name_based_routing.html b/basics/name_based_routing.html index 5a04b93d..e5c33864 100644 --- a/basics/name_based_routing.html +++ b/basics/name_based_routing.html @@ -874,7 +874,7 @@ diff --git a/basics/path_based_routing.html b/basics/path_based_routing.html index f713e985..48201847 100644 --- a/basics/path_based_routing.html +++ b/basics/path_based_routing.html @@ -832,7 +832,7 @@ diff --git a/basics/route_conflicts.html b/basics/route_conflicts.html index 8d26416b..84bd6854 100644 --- a/basics/route_conflicts.html +++ b/basics/route_conflicts.html @@ -875,7 +875,7 @@ diff --git a/basics/route_data.html b/basics/route_data.html index c226ddd5..9047c883 100644 --- a/basics/route_data.html +++ b/basics/route_data.html @@ -762,8 +762,14 @@

Route Data

-

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 an architecture of both adaptive and principled components.

-

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.

+

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 and functions into :handler keys.

(require '[reitit.core :as r])
 
 (def router
@@ -773,9 +779,10 @@
      ["/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.

+

Using Route Data

+

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 :user/ping}]
+; [["/ping" {:name ::ping}]
 ;  ["/pong" {:handler identity]}
 ;  ["/users" {:get {:roles #{:admin}
 ;                   :handler identity}}]]
@@ -794,7 +801,7 @@
 ;        :path-params {}
 ;        :path "/ping"}
 
-

Nested route data

+

Nested Route Data

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
@@ -816,8 +823,52 @@
 ;  ["/api/admin/db" {:interceptors [::api ::db]
 ;                    :roles #{:db-admin}}]]
 
-

Expansion

-

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.

+

Route Data Fragments

+

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}]]
+
+

Top-level Route Data

+

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}]]
+
+

Customizing Expansion

+

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
@@ -829,7 +880,9 @@
 (r/router
   ["/" (java.io.File. "index.html")])
 
-

See router options for all available options.

+

Page shared routes has an example of an custom :expand implementation.

+

Route data validation

+

See Route data validation.

@@ -873,7 +926,7 @@ diff --git a/basics/route_data_validation.html b/basics/route_data_validation.html index 15b793e2..0abcc2f8 100644 --- a/basics/route_data_validation.html +++ b/basics/route_data_validation.html @@ -925,7 +925,7 @@ diff --git a/basics/route_syntax.html b/basics/route_syntax.html index 24c0418b..5c480c30 100644 --- a/basics/route_syntax.html +++ b/basics/route_syntax.html @@ -764,7 +764,7 @@

Route Syntax

Routes are defined as vectors of String path and optional (non-sequential) route argument child routes.

Routes can be wrapped in vectors and lists and nil routes are ignored.

-

Paths can have path-parameters (:id) or catch-all-parameters (*path).

+

Paths can have path-parameters (:id) or catch-all-parameters (*path). Since version 0.4.0, parameters can also be wrapped in brackets, enabling use of qualified keywords {user/id}, {*user/path}. The non-bracket syntax might be deprecated later.

Examples

Simple route:

["/ping"]
@@ -781,9 +781,14 @@
 
[["/users/:user-id"]
  ["/api/:version/ping"]]
 
+
[["/users/{user-id}"]
+ ["/files/file-{number}.pdf"]]
+

Route with catch-all parameter:

["/public/*path"]
 
+
["/public/{*path}"]
+

Nested routes:

["/api"
  ["/admin" {:middleware [::admin]}
@@ -796,13 +801,34 @@
  ["/api/admin/db" {:middleware [::admin], :name ::db}]
  ["/api/ping" {:name ::ping}]]
 
+

Encoding

+

Reitit does not apply any encoding to your paths. If you need that, you must encode them yourself. E.g., /foo bar should be /foo%20bar.

+

Wildcards

+

Normal path-parameters (:id) can start anywhere in the path string, but have to end either to slash / (currently hardcoded) or to en end of path string:

+
[["/api/:version"]
+ ["/files/file-:number"]
+ ["/user/:user-id/orders"]]
+
+

Bracket path-parameters can start and stop anywhere in the path-string, the following character is used as a terminator.

+
[["/api/{version}"]
+ ["/files/{name}.{extension}"]
+ ["/user/{user-id}/orders"]]
+
+

Having multiple terminators after a bracket path-path parameter with identical path prefix will cause a compile-time error at router creation:

+
[["/files/file-{name}.pdf"]            ;; terminator \.
+ ["/files/file-{name}-{version}.pdf"]] ;; terminator \-
+
+

Slash Free Routing

+
[["broker.{customer}.{device}.{*data}"]
+ ["events.{target}.{type}"]]
+

Generating routes

Routes are just data, so it's easy to create them programmatically:

(defn cqrs-routes [actions]
   ["/api" {:interceptors [::api ::db]}
    (for [[type interceptor] actions
          :let [path (str "/" (name interceptor))
-               method (condp = type
+               method (case type
                         :query :get
                         :command :post)]]
      [path {method {:interceptors [interceptor]}}])])
@@ -816,9 +842,6 @@
 ;   ["/add-user" {:post {:interceptors [add-user]}}]
 ;   ["/add-order" {:post {:interceptors [add-order]}}])]
 
-

Encoding

-

Reitit does not apply any encoding to your paths. If you need that, you must encode them yourself. -E.g., /foo bar should be /foo%20bar.

@@ -862,7 +885,7 @@ E.g., /foo bar should be /foo%20bar.

diff --git a/basics/router.html b/basics/router.html index 55ce5c30..d03e11b0 100644 --- a/basics/router.html +++ b/basics/router.html @@ -790,14 +790,58 @@ ; [["/api/ping" {:name :user/ping}] ; ["/api/user/:id" {:name :user/user}]]
+

With a router instance, we can do Path-based routing or Name-based (Reverse) routing.

+

More details

+

Router options:

+
(r/options router)
+{:lookup #object[...]
+ :expand #object[...]
+ :coerce #object[...]
+ :compile #object[...]
+ :conflicts #object[...]}
+
+

Route names:

+
(r/route-names router)
+; [:user/ping :user/user]
+
+

The compiled route tree:

+
(r/routes router)
+; [["/api/ping" {:name :user/ping} nil]
+;  ["/api/user/:id" {:name :user/user} nil]]
+
+

Composing

+

As routes are defined as plain data, it's easy to merge multiple route trees into a single router

+
(def user-routes
+  [["/users" ::users]
+   ["/users/:id" ::user]]) 
+
+(def admin-routes
+  ["/admin"
+   ["/ping" ::ping]
+   ["/users" ::users]]) 
+
+(r/router
+  [admin-routes
+   user-routes])
+
+

Merged route tree:

+
(r/routes router)
+; [["/admin/ping" {:name :user/ping}]
+;  ["/admin/db" {:name :user/db}]
+;  ["/users" {:name :user/users}]
+;  ["/users/:id" {:name :user/user}]]
+
+

More details on composing routers.

Behind the scenes

When router is created, the following steps are done:

@@ -842,7 +886,7 @@ diff --git a/coercion/clojure_spec_coercion.html b/coercion/clojure_spec_coercion.html index 6bc24772..075debfb 100644 --- a/coercion/clojure_spec_coercion.html +++ b/coercion/clojure_spec_coercion.html @@ -897,7 +897,7 @@ diff --git a/coercion/coercion.html b/coercion/coercion.html index c3a0aaa5..0fc9f23b 100644 --- a/coercion/coercion.html +++ b/coercion/coercion.html @@ -939,7 +939,7 @@ diff --git a/coercion/data_spec_coercion.html b/coercion/data_spec_coercion.html index 99bedbdc..32442dac 100644 --- a/coercion/data_spec_coercion.html +++ b/coercion/data_spec_coercion.html @@ -838,7 +838,7 @@ diff --git a/coercion/schema_coercion.html b/coercion/schema_coercion.html index 0b3c602a..39a1020c 100644 --- a/coercion/schema_coercion.html +++ b/coercion/schema_coercion.html @@ -839,7 +839,7 @@ diff --git a/development.html b/development.html index 18f809d8..3da161f5 100644 --- a/development.html +++ b/development.html @@ -829,7 +829,7 @@ lein test diff --git a/faq.html b/faq.html index b3764fe0..2d5acb9d 100644 --- a/faq.html +++ b/faq.html @@ -907,7 +907,7 @@ diff --git a/frontend/basics.html b/frontend/basics.html index 341498ac..98433c9b 100644 --- a/frontend/basics.html +++ b/frontend/basics.html @@ -827,7 +827,7 @@ React breaking due to errors.

diff --git a/frontend/browser.html b/frontend/browser.html index d40e1a8f..b66e07da 100644 --- a/frontend/browser.html +++ b/frontend/browser.html @@ -823,7 +823,7 @@ event handler for page change events.

diff --git a/frontend/controllers.html b/frontend/controllers.html index 5deb9ed5..8eb74ce2 100644 --- a/frontend/controllers.html +++ b/frontend/controllers.html @@ -907,7 +907,7 @@ missing resources.

diff --git a/http/default_interceptors.html b/http/default_interceptors.html index ae3e2fb6..d8183247 100644 --- a/http/default_interceptors.html +++ b/http/default_interceptors.html @@ -829,7 +829,7 @@ diff --git a/http/interceptors.html b/http/interceptors.html index 312fe944..6258fc8b 100644 --- a/http/interceptors.html +++ b/http/interceptors.html @@ -857,7 +857,7 @@ diff --git a/http/pedestal.html b/http/pedestal.html index 097763df..7c181b04 100644 --- a/http/pedestal.html +++ b/http/pedestal.html @@ -868,7 +868,7 @@ diff --git a/http/sieppari.html b/http/sieppari.html index 0b9623ae..6d4c313d 100644 --- a/http/sieppari.html +++ b/http/sieppari.html @@ -869,7 +869,7 @@ diff --git a/http/transforming_interceptor_chain.html b/http/transforming_interceptor_chain.html index 2c3c0e73..ccbd13fc 100644 --- a/http/transforming_interceptor_chain.html +++ b/http/transforming_interceptor_chain.html @@ -868,7 +868,7 @@ diff --git a/images/opensensors.png b/images/opensensors.png index 94bf228a..fd922808 100644 Binary files a/images/opensensors.png and b/images/opensensors.png differ diff --git a/index.html b/index.html index 68c8d256..980d9fe4 100644 --- a/index.html +++ b/index.html @@ -956,7 +956,7 @@ diff --git a/performance.html b/performance.html index 25a8cbbf..75a64fc3 100644 --- a/performance.html +++ b/performance.html @@ -762,16 +762,17 @@

Performance

-

Besides having great features, goal of reitit is to be really, really fast. The routing was originally exported from Pedestal, but since rewritten.

+

Reitit tries to be really, really fast.

Opensensors perf test

Rationale