mirror of
https://github.com/metosin/reitit.git
synced 2025-12-16 16:01:11 +00:00
Update docs
This commit is contained in:
parent
8a411b13de
commit
dfc3455f16
20 changed files with 295 additions and 282 deletions
12
README.md
12
README.md
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
A friendly data-driven router for Clojure(Script).
|
||||
|
||||
* Simple data-driven [route syntax](https://metosin.github.io/reitit/basics.html#route-syntax)
|
||||
* First-class [route meta-data](https://metosin.github.io/reitit/basics.html#route-data)
|
||||
* Generic, not tied to HTTP
|
||||
* [Route conflict resolution](https://metosin.github.io/reitit/route_conflicts.html)
|
||||
* [Pluggable coercion](https://metosin.github.io/reitit/parameter_coercion.html) ([clojure.spec](https://clojure.org/about/spec))
|
||||
* both [Middleware](https://metosin.github.io/reitit/compiling_middleware.html) & Interceptors
|
||||
* Simple data-driven [route syntax](https://metosin.github.io/reitit/basics/route_syntax.md)
|
||||
* [Route conflict resolution](https://metosin.github.io/reitit/advanced/route_conflicts.md)
|
||||
* First-class [route meta-data](https://metosin.github.io/reitit/basics/route_data.md)
|
||||
* Bi-directional routing
|
||||
* [Pluggable coercion](https://metosin.github.io/reitit/ring/parameter_coercion.md) ([clojure.spec](https://clojure.org/about/spec))
|
||||
* supports both [Middleware](https://metosin.github.io/reitit/ring/compiling_middleware.md) & Interceptors
|
||||
* Extendable
|
||||
* Fast
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
[Reitit](https://github.com/metosin/reitit) is a small Clojure(Script) library for data-driven routing.
|
||||
|
||||
* Simple data-driven [route syntax](./basics.md#route-syntax)
|
||||
* First-class [route meta-data](./basics.md#route-data)
|
||||
* Bi-directional-routing
|
||||
* [Route conflict resolution](./route_conflicts.md)
|
||||
* [Pluggable coercion](./parameter_coercion.md) ([clojure.spec](https://clojure.org/about/spec))
|
||||
* Both [Middleware](./ring.md#middleware) & Interceptors
|
||||
* Simple data-driven [route syntax](./basics/route_syntax.md)
|
||||
* [Route conflict resolution](./advanced/route_conflicts.md)
|
||||
* First-class [route meta-data](./basics/route_data.md)
|
||||
* Bi-directional routing
|
||||
* [Pluggable coercion](./ring/parameter_coercion.md) ([clojure.spec](https://clojure.org/about/spec))
|
||||
* supports both [Middleware](./ring/compiling_middleware.md) & Interceptors
|
||||
* Extendable
|
||||
* Fast
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
# Summary
|
||||
|
||||
* [Introduction](README.md)
|
||||
* Basics
|
||||
* [Route syntax](basics.md#route-syntax)
|
||||
* [Router](basics.md#router)
|
||||
* [Path-based Routing](basics.md#path-based-routing)
|
||||
* [Name-based Routing](basics.md#name-based-routing)
|
||||
* [Route data](basics.md#route-data)
|
||||
* [Different Routers](basics.md#different-routers)
|
||||
* Advanced
|
||||
* [Route conflicts](route_conflicts.md)
|
||||
* [Route Validation](route_validation.md)
|
||||
* [Configuring routers](configuring_routers.md)
|
||||
* Ring
|
||||
* [Ring-router](ring.md)
|
||||
* [Dynamic extensions](dynamic_extensions.md)
|
||||
* [Parameter coercion](parameter_coercion.md)
|
||||
* [Compiling middleware](compiling_middleware.md)
|
||||
* [Basics](basics/README.md)
|
||||
* [Route syntax](basics/route_syntax.md)
|
||||
* [Router](basics/router.md)
|
||||
* [Path-based Routing](basics/path_based_routing.md)
|
||||
* [Name-based Routing](basics/name_based_routing.md)
|
||||
* [Route data](basics/route_data.md)
|
||||
* [Different Routers](basics/different_routers.md)
|
||||
* [Advanced](advanced/README.md)
|
||||
* [Route conflicts](advanced/route_conflicts.md)
|
||||
* [Route Validation](advanced/route_validation.md)
|
||||
* [Configuring routers](advanced/configuring_routers.md)
|
||||
* [Ring](ring/README.md)
|
||||
* [Ring-router](ring/ring.md)
|
||||
* [Dynamic extensions](ring/dynamic_extensions.md)
|
||||
* [Parameter coercion](ring/parameter_coercion.md)
|
||||
* [Compiling middleware](ring/compiling_middleware.md)
|
||||
* TODO: Swagger & OpenAPI
|
||||
* TODO: Interceptors
|
||||
|
|
|
|||
5
doc/advanced/README.md
Normal file
5
doc/advanced/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Advanced
|
||||
|
||||
* [Route conflicts](advanced/route_conflicts.md)
|
||||
* [Route Validation](advanced/route_validation.md)
|
||||
* [Configuring routers](advanced/configuring_routers.md)
|
||||
254
doc/basics.md
254
doc/basics.md
|
|
@ -1,254 +0,0 @@
|
|||
# Route Syntax
|
||||
|
||||
Raw routes are defined as vectors, which have a String path, optional (non-sequential) route argument and optional 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`).
|
||||
|
||||
Simple route:
|
||||
|
||||
```clj
|
||||
["/ping"]
|
||||
```
|
||||
|
||||
Two routes:
|
||||
|
||||
```clj
|
||||
[["/ping"]
|
||||
["/pong"]]
|
||||
```
|
||||
|
||||
Routes with route arguments:
|
||||
|
||||
```clj
|
||||
[["/ping" ::ping]
|
||||
["/pong" {:name ::pong}]]
|
||||
```
|
||||
|
||||
Routes with path parameters:
|
||||
|
||||
```clj
|
||||
[["/users/:user-id"]
|
||||
["/api/:version/ping"]]
|
||||
```
|
||||
|
||||
Route with catch-all parameter:
|
||||
|
||||
```clj
|
||||
["/public/*path"]
|
||||
```
|
||||
|
||||
Nested routes:
|
||||
|
||||
```clj
|
||||
["/api"
|
||||
["/admin" {:middleware [::admin]}
|
||||
["" ::admin]
|
||||
["/db" ::db]]
|
||||
["/ping" ::ping]]
|
||||
```
|
||||
|
||||
Same routes flattened:
|
||||
|
||||
```clj
|
||||
[["/api/admin" {:middleware [::admin], :name ::admin}]
|
||||
["/api/admin/db" {:middleware [::admin], :name ::db}]
|
||||
["/api/ping" {:name ::ping}]]
|
||||
```
|
||||
|
||||
As routes are just data, it's easy to create them programamtically:
|
||||
|
||||
```clj
|
||||
(defn cqrs-routes [actions dev-mode?]
|
||||
["/api" {:interceptors [::api ::db]}
|
||||
(for [[type interceptor] actions
|
||||
:let [path (str "/" (name interceptor))
|
||||
method (condp = type
|
||||
:query :get
|
||||
:command :post)]]
|
||||
[path {method {:interceptors [interceptor]}}])
|
||||
(if dev-mode? ["/dev-tools" ::dev-tools])])
|
||||
```
|
||||
|
||||
```clj
|
||||
(cqrs-routes
|
||||
[[:query 'get-user]
|
||||
[:command 'add-user]
|
||||
[:command 'add-order]]
|
||||
false)
|
||||
; ["/api" {:interceptors [::api ::db]}
|
||||
; (["/get-user" {:get {:interceptors [get-user]}}]
|
||||
; ["/add-user" {:post {:interceptors [add-user]}}]
|
||||
; ["/add-order" {:post {:interceptors [add-order]}}])
|
||||
; nil]
|
||||
```
|
||||
|
||||
|
||||
# Router
|
||||
|
||||
Routes are just data and to do actual routing, we need a Router satisfying the `reitit.core/Router` protocol. Routers are created with `reitit.core/router` function, taking the raw routes and optionally an options map. Raw routes gets expanded and optionally coerced and compiled.
|
||||
|
||||
`Router` protocol:
|
||||
|
||||
```clj
|
||||
(defprotocol Router
|
||||
(router-name [this])
|
||||
(routes [this])
|
||||
(options [this])
|
||||
(route-names [this])
|
||||
(match-by-path [this path])
|
||||
(match-by-name [this name] [this name params]))
|
||||
```
|
||||
|
||||
Creating a router:
|
||||
|
||||
```clj
|
||||
(require '[reitit.core :as r])
|
||||
|
||||
(def router
|
||||
(r/router
|
||||
[["/api"
|
||||
["/ping" ::ping]
|
||||
["/user/:id" ::user]]]))
|
||||
```
|
||||
|
||||
Router flattens the raw routes and expands the route arguments using `reitit.core/Expand` protocol. By default, `Keyword`s are expanded to `:name` and functions are expaned to `:handler`. `nil` routes are removed. The expanded routes can be retrieved with router:
|
||||
|
||||
```clj
|
||||
(r/routes router)
|
||||
; [["/api/ping" {:name :user/ping}]
|
||||
; ["/api/user/:id" {:name :user/user}]]
|
||||
```
|
||||
|
||||
## Path-based routing
|
||||
|
||||
Path-based routing is done using the `reitit.core/match-by-path` function. It takes the router and path as arguments and returns one of the following:
|
||||
|
||||
* `nil`, no match
|
||||
* `PartialMatch`, path matched, missing path-parameters (only in reverse-routing)
|
||||
* `Match`, exact match
|
||||
|
||||
```clj
|
||||
(r/match-by-path router "/hello")
|
||||
; nil
|
||||
```
|
||||
|
||||
```clj
|
||||
(r/match-by-path router "/api/user/1")
|
||||
; #Match{:template "/api/user/:id"
|
||||
; :meta {:name :user/user}
|
||||
; :path "/api/user/1"
|
||||
; :result nil
|
||||
; :params {:id "1"}}
|
||||
```
|
||||
|
||||
## Name-based routing
|
||||
|
||||
All routes which `:name` route data defined, can be matched by name.
|
||||
|
||||
Listing all route names:
|
||||
|
||||
```clj
|
||||
(r/route-names router)
|
||||
; [:user/ping :user/user]
|
||||
```
|
||||
|
||||
Matching by name:
|
||||
|
||||
```clj
|
||||
(r/match-by-name router ::user)
|
||||
; #PartialMatch{:template "/api/user/:id",
|
||||
; :meta {:name :user/user},
|
||||
; :result nil,
|
||||
; :params nil,
|
||||
; :required #{:id}}
|
||||
|
||||
(r/partial-match? (r/match-by-name router ::user))
|
||||
; true
|
||||
```
|
||||
|
||||
We only got a partial match as we didn't provide the needed path-parameters. Let's provide the them too:
|
||||
|
||||
```clj
|
||||
(r/match-by-name router ::user {:id "1"})
|
||||
; #Match{:template "/api/user/:id"
|
||||
; :meta {:name :user/user}
|
||||
; :path "/api/user/1"
|
||||
; :result nil
|
||||
; :params {:id "1"}}
|
||||
```
|
||||
|
||||
There is also a exception throwing version:
|
||||
|
||||
```clj
|
||||
(r/match-by-name! router ::user)
|
||||
; ExceptionInfo missing path-params for route /api/user/:id: #{:id}
|
||||
```
|
||||
|
||||
# Route data
|
||||
|
||||
Routes can have arbitrary meta-data, interpreted by the router (via it's `:compile` hook) or the application itself. For nested routes, route data is accumulated recursively using [meta-merge](https://github.com/weavejester/meta-merge). By default, it appends collections, but it can be overridden to do `:prepend`, `:replace` or `:displace`.
|
||||
|
||||
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}}
|
||||
["/:db" {:parameters {:db String}}
|
||||
["/drop" ::drop-db]
|
||||
["/stats" ::db-stats]]]]]))
|
||||
```
|
||||
|
||||
Resolved route tree:
|
||||
|
||||
```clj
|
||||
(reitit/routes router)
|
||||
; [["/api/ping" {:interceptors [::api]
|
||||
; :name ::ping}]
|
||||
; ["/api/admin/users" {:interceptors [::api]
|
||||
; :roles #{:admin}
|
||||
; :name ::users}]
|
||||
; ["/api/admin/db/:db/drop" {:interceptors [::api ::db]
|
||||
; :roles #{:db-admin}
|
||||
; :parameters {:db String}
|
||||
; :name ::drop-db}]
|
||||
; ["/api/admin/db/:db/stats" {:interceptors [::api ::db]
|
||||
; :roles #{:db-admin}
|
||||
; :parameters {:db String}
|
||||
; :name ::db-stats}]]
|
||||
```
|
||||
|
||||
Route data is returned with `Match` and the application can act based on it.
|
||||
|
||||
```clj
|
||||
(r/match-by-path router "/api/admin/db/users/drop")
|
||||
; #Match{:template "/api/admin/db/:db/drop"
|
||||
; :meta {:interceptors [::api ::db]
|
||||
; :roles #{:db-admin}
|
||||
; :parameters {:db String}
|
||||
; :name ::drop-db}
|
||||
; :result nil
|
||||
; :params {:db "users"}
|
||||
; :path "/api/admin/db/users/drop"}
|
||||
```
|
||||
|
||||
# Different Routers
|
||||
|
||||
Reitit ships with several different implementations for the `Router` protocol, originally based on the awesome [Pedestal](https://github.com/pedestal/pedestal/tree/master/route) implementation. `router` selects the most suitable implementation by inspecting the expanded routes. The implementation can be set manually using `:router` ROUTER OPTION.
|
||||
|
||||
| router | description |
|
||||
| ----------------------|-------------|
|
||||
| `:linear-router` | Matches the routes one-by-one starting from the top until a match is found. Works with any kind of routes.
|
||||
| `:lookup-router` | Fastest router, uses hash-lookup to resolve the route. Valid if no paths have path or catch-all parameters.
|
||||
| `:mixed-router` | Creates internally a `:linear-router` and a `:lookup-router` and used them to effectively get best-of-both-worlds. Valid if there are no CONFLICTING ROUTES.
|
||||
| `:prefix-tree-router` | [TODO](https://github.com/julienschmidt/httprouter#how-does-it-work)
|
||||
|
||||
The router name can be asked from the router
|
||||
|
||||
```clj
|
||||
(r/router-name router)
|
||||
; :mixed-router
|
||||
```
|
||||
8
doc/basics/README.md
Normal file
8
doc/basics/README.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Basics
|
||||
|
||||
* [Route syntax](basics/route_syntax.md)
|
||||
* [Router](basics/router.md)
|
||||
* [Path-based Routing](basics/path_based_routing.md)
|
||||
* [Name-based Routing](basics/name_based_routing.md)
|
||||
* [Route data](basics/route_data.md)
|
||||
* [Different Routers](basics/different_routers.md)
|
||||
17
doc/basics/different_routers.md
Normal file
17
doc/basics/different_routers.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Different Routers
|
||||
|
||||
Reitit ships with several different implementations for the `Router` protocol, originally based on the awesome [Pedestal](https://github.com/pedestal/pedestal/tree/master/route) implementation. `router` selects the most suitable implementation by inspecting the expanded routes. The implementation can be set manually using `:router` ROUTER OPTION.
|
||||
|
||||
| router | description |
|
||||
| ----------------------|-------------|
|
||||
| `:linear-router` | Matches the routes one-by-one starting from the top until a match is found. Works with any kind of routes.
|
||||
| `:lookup-router` | Fastest router, uses hash-lookup to resolve the route. Valid if no paths have path or catch-all parameters.
|
||||
| `:mixed-router` | Creates internally a `:linear-router` and a `:lookup-router` and used them to effectively get best-of-both-worlds. Valid if there are no CONFLICTING ROUTES.
|
||||
| `:prefix-tree-router` | [TODO](https://github.com/julienschmidt/httprouter#how-does-it-work)
|
||||
|
||||
The router name can be asked from the router
|
||||
|
||||
```clj
|
||||
(r/router-name router)
|
||||
; :mixed-router
|
||||
```
|
||||
42
doc/basics/name_based_routing.md
Normal file
42
doc/basics/name_based_routing.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
## Name-based routing
|
||||
|
||||
All routes which `:name` route data defined, can be matched by name.
|
||||
|
||||
Listing all route names:
|
||||
|
||||
```clj
|
||||
(r/route-names router)
|
||||
; [:user/ping :user/user]
|
||||
```
|
||||
|
||||
Matching by name:
|
||||
|
||||
```clj
|
||||
(r/match-by-name router ::user)
|
||||
; #PartialMatch{:template "/api/user/:id",
|
||||
; :meta {:name :user/user},
|
||||
; :result nil,
|
||||
; :params nil,
|
||||
; :required #{:id}}
|
||||
|
||||
(r/partial-match? (r/match-by-name router ::user))
|
||||
; true
|
||||
```
|
||||
|
||||
We only got a partial match as we didn't provide the needed path-parameters. Let's provide the them too:
|
||||
|
||||
```clj
|
||||
(r/match-by-name router ::user {:id "1"})
|
||||
; #Match{:template "/api/user/:id"
|
||||
; :meta {:name :user/user}
|
||||
; :path "/api/user/1"
|
||||
; :result nil
|
||||
; :params {:id "1"}}
|
||||
```
|
||||
|
||||
There is also a exception throwing version:
|
||||
|
||||
```clj
|
||||
(r/match-by-name! router ::user)
|
||||
; ExceptionInfo missing path-params for route /api/user/:id: #{:id}
|
||||
```
|
||||
21
doc/basics/path_based_routing.md
Normal file
21
doc/basics/path_based_routing.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
## Path-based routing
|
||||
|
||||
Path-based routing is done using the `reitit.core/match-by-path` function. It takes the router and path as arguments and returns one of the following:
|
||||
|
||||
* `nil`, no match
|
||||
* `PartialMatch`, path matched, missing path-parameters (only in reverse-routing)
|
||||
* `Match`, exact match
|
||||
|
||||
```clj
|
||||
(r/match-by-path router "/hello")
|
||||
; nil
|
||||
```
|
||||
|
||||
```clj
|
||||
(r/match-by-path router "/api/user/1")
|
||||
; #Match{:template "/api/user/:id"
|
||||
; :meta {:name :user/user}
|
||||
; :path "/api/user/1"
|
||||
; :result nil
|
||||
; :params {:id "1"}}
|
||||
```
|
||||
52
doc/basics/route_data.md
Normal file
52
doc/basics/route_data.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Route data
|
||||
|
||||
Routes can have arbitrary meta-data, interpreted by the router (via it's `:compile` hook) or the application itself. For nested routes, route data is accumulated recursively using [meta-merge](https://github.com/weavejester/meta-merge). By default, it appends collections, but it can be overridden to do `:prepend`, `:replace` or `:displace`.
|
||||
|
||||
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}}
|
||||
["/:db" {:parameters {:db String}}
|
||||
["/drop" ::drop-db]
|
||||
["/stats" ::db-stats]]]]]))
|
||||
```
|
||||
|
||||
Resolved route tree:
|
||||
|
||||
```clj
|
||||
(reitit/routes router)
|
||||
; [["/api/ping" {:interceptors [::api]
|
||||
; :name ::ping}]
|
||||
; ["/api/admin/users" {:interceptors [::api]
|
||||
; :roles #{:admin}
|
||||
; :name ::users}]
|
||||
; ["/api/admin/db/:db/drop" {:interceptors [::api ::db]
|
||||
; :roles #{:db-admin}
|
||||
; :parameters {:db String}
|
||||
; :name ::drop-db}]
|
||||
; ["/api/admin/db/:db/stats" {:interceptors [::api ::db]
|
||||
; :roles #{:db-admin}
|
||||
; :parameters {:db String}
|
||||
; :name ::db-stats}]]
|
||||
```
|
||||
|
||||
Route data is returned with `Match` and the application can act based on it.
|
||||
|
||||
```clj
|
||||
(r/match-by-path router "/api/admin/db/users/drop")
|
||||
; #Match{:template "/api/admin/db/:db/drop"
|
||||
; :meta {:interceptors [::api ::db]
|
||||
; :roles #{:db-admin}
|
||||
; :parameters {:db String}
|
||||
; :name ::drop-db}
|
||||
; :result nil
|
||||
; :params {:db "users"}
|
||||
; :path "/api/admin/db/users/drop"}
|
||||
```
|
||||
81
doc/basics/route_syntax.md
Normal file
81
doc/basics/route_syntax.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# Route Syntax
|
||||
|
||||
Raw routes are defined as vectors, which have a String path, optional (non-sequential) route argument and optional 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`).
|
||||
|
||||
Simple route:
|
||||
|
||||
```clj
|
||||
["/ping"]
|
||||
```
|
||||
|
||||
Two routes:
|
||||
|
||||
```clj
|
||||
[["/ping"]
|
||||
["/pong"]]
|
||||
```
|
||||
|
||||
Routes with route arguments:
|
||||
|
||||
```clj
|
||||
[["/ping" ::ping]
|
||||
["/pong" {:name ::pong}]]
|
||||
```
|
||||
|
||||
Routes with path parameters:
|
||||
|
||||
```clj
|
||||
[["/users/:user-id"]
|
||||
["/api/:version/ping"]]
|
||||
```
|
||||
|
||||
Route with catch-all parameter:
|
||||
|
||||
```clj
|
||||
["/public/*path"]
|
||||
```
|
||||
|
||||
Nested routes:
|
||||
|
||||
```clj
|
||||
["/api"
|
||||
["/admin" {:middleware [::admin]}
|
||||
["" ::admin]
|
||||
["/db" ::db]]
|
||||
["/ping" ::ping]]
|
||||
```
|
||||
|
||||
Same routes flattened:
|
||||
|
||||
```clj
|
||||
[["/api/admin" {:middleware [::admin], :name ::admin}]
|
||||
["/api/admin/db" {:middleware [::admin], :name ::db}]
|
||||
["/api/ping" {:name ::ping}]]
|
||||
```
|
||||
|
||||
As routes are just data, it's easy to create them programamtically:
|
||||
|
||||
```clj
|
||||
(defn cqrs-routes [actions dev-mode?]
|
||||
["/api" {:interceptors [::api ::db]}
|
||||
(for [[type interceptor] actions
|
||||
:let [path (str "/" (name interceptor))
|
||||
method (condp = type
|
||||
:query :get
|
||||
:command :post)]]
|
||||
[path {method {:interceptors [interceptor]}}])
|
||||
(if dev-mode? ["/dev-tools" ::dev-tools])])
|
||||
```
|
||||
|
||||
```clj
|
||||
(cqrs-routes
|
||||
[[:query 'get-user]
|
||||
[:command 'add-user]
|
||||
[:command 'add-order]]
|
||||
false)
|
||||
; ["/api" {:interceptors [::api ::db]}
|
||||
; (["/get-user" {:get {:interceptors [get-user]}}]
|
||||
; ["/add-user" {:post {:interceptors [add-user]}}]
|
||||
; ["/add-order" {:post {:interceptors [add-order]}}])
|
||||
; nil]
|
||||
```
|
||||
35
doc/basics/router.md
Normal file
35
doc/basics/router.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Router
|
||||
|
||||
Routes are just data and to do actual routing, we need a Router satisfying the `reitit.core/Router` protocol. Routers are created with `reitit.core/router` function, taking the raw routes and optionally an options map. Raw routes gets expanded and optionally coerced and compiled.
|
||||
|
||||
`Router` protocol:
|
||||
|
||||
```clj
|
||||
(defprotocol Router
|
||||
(router-name [this])
|
||||
(routes [this])
|
||||
(options [this])
|
||||
(route-names [this])
|
||||
(match-by-path [this path])
|
||||
(match-by-name [this name] [this name params]))
|
||||
```
|
||||
|
||||
Creating a router:
|
||||
|
||||
```clj
|
||||
(require '[reitit.core :as r])
|
||||
|
||||
(def router
|
||||
(r/router
|
||||
[["/api"
|
||||
["/ping" ::ping]
|
||||
["/user/:id" ::user]]]))
|
||||
```
|
||||
|
||||
Router flattens the raw routes and expands the route arguments using `reitit.core/Expand` protocol. By default, `Keyword`s are expanded to `:name` and functions are expaned to `:handler`. `nil` routes are removed. The expanded routes can be retrieved with router:
|
||||
|
||||
```clj
|
||||
(r/routes router)
|
||||
; [["/api/ping" {:name :user/ping}]
|
||||
; ["/api/user/:id" {:name :user/user}]]
|
||||
```
|
||||
6
doc/ring/README.md
Normal file
6
doc/ring/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Ring
|
||||
|
||||
* [Ring-router](ring.md)
|
||||
* [Dynamic extensions](dynamic_extensions.md)
|
||||
* [Parameter coercion](parameter_coercion.md)
|
||||
* [Compiling middleware](compiling_middleware.md)
|
||||
Loading…
Reference in a new issue