Merge remote-tracking branch 'origin/master' into openapi

This commit is contained in:
Joel Kaasinen 2023-03-03 14:43:23 +02:00
commit 7842160656
58 changed files with 283 additions and 136 deletions

View file

@ -12,8 +12,10 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
[breakver]: https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md
## UNRELEASED
## 0.6.0 (2023-02-21)
* Add reitit-frontend support for fragment string [#581](https://github.com/metosin/reitit/pull/581)
* reloading-ring-handler [#584](https://github.com/metosin/reitit/pull/584)
* Remove redundant s/and [#552](https://github.com/metosin/reitit/pull/552)
* FIX: redirect-trailing-slash-handler strips query-params [#565](https://github.com/metosin/reitit/issues/565)
* **BREAKING**: Drop tests for Clojure 1.9, run tests with 1.10 & 1.11
@ -33,6 +35,8 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
[metosin/malli "0.10.1"] is available but we use "0.8.2"
[fipp "0.6.26"] is available but we use "0.6.25"
[ring/ring-core "1.9.6"] is available but we use "1.9.5"
[com.fasterxml.jackson.core/jackson-core "2.14.2"] is available but we use "2.14.1"
[com.fasterxml.jackson.core/jackson-databind "2.14.2"] is available but we use "2.14.1"
```
## 0.5.18 (2022-04-05)
@ -228,12 +232,12 @@ when called repeatedly (e.g. with hot code reload workflow)
### `reitit-malli`
* `:map-of` keys in JSON are correctly decoded using string-decoders
* `:map-of` keys in JSON are correctly decoded using string-decoders
* new `:encode-error` option in coercion:
```clj
(def coercion
(reitit.coercion.malli/create
(def coercion
(reitit.coercion.malli/create
{:encode-error (fn [error] {:errors (:humanized error)})}))
; results in... => {:status 400, :body {:errors {:x ["missing required key"]}}}
```
@ -343,13 +347,13 @@ is called the first time, so that `rfe/push-state` and such can be called
* `reitit.ring/routes` strips away `nil` routes, fixes [#394](https://github.com/metosin/reitit/issues/394)
* `reitit.ring/create-file-handler` to serve files from filesystem, fixes [#395](https://github.com/metosin/reitit/issues/395)
* **BREAKING**: router option `:reitit.ring/default-options-handler` is deprecated
* **BREAKING**: router option `:reitit.ring/default-options-handler` is deprecated
* fails with router creation time error
* use `:reitit.ring/default-options-endpoint` instead, takes an expandable route data instead just of a handler.
### `reitit-http`
* **BREAKING**: router option `:reitit.http/default-options-handler` is deprecated
* **BREAKING**: router option `:reitit.http/default-options-handler` is deprecated
* fails with router creation time error
* use `:reitit.http/default-options-endpoint` instead, takes an expandable route data instead just of a handler.
@ -428,7 +432,7 @@ is called the first time, so that `rfe/push-state` and such can be called
* **BREAKING**: Decode multi-valued query params correctly into seqs (e.g. `foo=bar&foo=baz``{:foo ["bar", "baz"]}`).
* Previously you'd get only the first value. (e.g. `foo=bar&foo=baz``{:foo "bar"}`)
### `reitit-ring`
* **BREAKING**: New validation rule: `:middleware` must be a vector, not a list. Fixes [#296](https://github.com/metosin/reitit/issues/296). ([#319](https://github.com/metosin/reitit/pull/319) by [Daw-Ran Liou](https://github.com/dawran6))
@ -546,23 +550,23 @@ is called the first time, so that `rfe/push-state` and such can be called
{:parameters {:body [s/Str]}}]]
{:exception pretty/exception})
; -- Router creation failed -------------------------------------------- user:7 --
;
;
; Error merging route-data:
;
;
; -- On route -----------------------
;
;
; /kikka/kakka
;
;
; -- Exception ----------------------
;
;
; Don't know how to create ISeq from: java.lang.Class
;
;
; {:parameters {:body {:id java.lang.String}}}
;
;
; {:parameters {:body [java.lang.String]}}
;
;
; https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-data
;
;
; --------------------------------------------------------------------------------
```
@ -581,7 +585,7 @@ is called the first time, so that `rfe/push-state` and such can be called
### `reitit-core`
* new options `:reitit.spec/wrap` to wrap top-level route data specs when spec validation is enabled. Using `spec-tools.spell/closed` closes top-level specs.
* new options `:reitit.spec/wrap` to wrap top-level route data specs when spec validation is enabled. Using `spec-tools.spell/closed` closes top-level specs.
* Updated swagger-examples to easily enable closed spec validation
```clj
@ -646,9 +650,9 @@ is called the first time, so that `rfe/push-state` and such can be called
* new module for friendly router creation time exception handling
* new option `:exception` in `r/router`, of type `Exception => Exception` (default `reitit.exception/exception`)
* new exception pretty-printer `reitit.dev.pretty/exception`, based on [fipp](https://github.com/brandonbloom/fipp) and [expound](https://github.com/bhb/expound) for human readable, newbie-friendly errors.
#### Conflicting paths
```clj
(require '[reitit.core :as r])
(require '[reitit.dev.pretty :as pretty])

View file

@ -52,7 +52,7 @@ There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians
All main modules bundled:
```clj
[metosin/reitit "0.5.18"]
[metosin/reitit "0.6.0"]
```
Optionally, the parts can be required separately.

View file

@ -40,7 +40,7 @@ There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians
All bundled:
```clj
[metosin/reitit "0.5.18"]
[metosin/reitit "0.6.0"]
```
Optionally, the parts can be required separately.
@ -110,9 +110,9 @@ Reverse-routing:
; :path "/api/orders/2"}
```
## Ring-router
## Ring router
Ring-router adds support for `:handler` functions, `:middleware` and routing based on `:request-method`. It also supports pluggable parameter coercion (`clojure.spec`), data-driven middleware, route and middleware compilation, dynamic extensions and more.
A Ring router function adds support for `:handler` functions, `:middleware` and routing based on `:request-method`. It also supports pluggable parameter coercion (`clojure.spec`), data-driven middleware, route and middleware compilation, dynamic extensions and more.
```clj
(require '[reitit.ring :as ring])

View file

@ -25,7 +25,7 @@
## Ring
* [Ring-router](ring/ring.md)
* [Ring Router](ring/ring.md)
* [Reverse-routing](ring/reverse_routing.md)
* [Default handler](ring/default_handler.md)
* [Slash handler](ring/slash_handler.md)

View file

@ -22,7 +22,7 @@ The default exception formatting uses `reitit.exception/exception`. It produces
## Pretty Errors
```clj
[metosin/reitit-dev "0.5.18"]
[metosin/reitit-dev "0.6.0"]
```
For human-readable and developer-friendly exception messages, there is `reitit.dev.pretty/exception` (in the `reitit-dev` module). It is inspired by the lovely errors messages of [ELM](https://elm-lang.org/blog/compiler-errors-for-humans) and [ETA](https://twitter.com/jyothsnasrin/status/1037703436043603968) and uses [fipp](https://github.com/brandonbloom/fipp), [expound](https://github.com/bhb/expound) and [spell-spec](https://github.com/bhauman/spell-spec) for most of heavy lifting.

View file

@ -31,7 +31,7 @@
["Data-specs" {:file "doc/coercion/data_spec_coercion.md"}]
["Malli" {:file "doc/coercion/malli_coercion.md"}]]
["Ring" {}
["Ring-router" {:file "doc/ring/ring.md"}]
["Ring Router" {:file "doc/ring/ring.md"}]
["Reverse-routing" {:file "doc/ring/reverse_routing.md"}]
["Default handler" {:file "doc/ring/default_handler.md"}]
["Slash handler" {:file "doc/ring/slash_handler.md"}]

View file

@ -49,7 +49,7 @@ git tag 1.0.0
lein test
# deploy to clojars
./scripts/lein-modules do clean, deploy clojars
CLOJARS_USERNAME=*** CLOJARS_PASSWORD=*** ./scripts/lein-modules do clean, deploy clojars
# push the commit and the tag
git push

View file

@ -1,7 +1,7 @@
# Default Interceptors
```clj
[metosin/reitit-interceptors "0.5.18"]
[metosin/reitit-interceptors "0.6.0"]
```
Just like the [ring default middleware](../ring/default_middleware.md), but for interceptors.

View file

@ -5,7 +5,7 @@ Reitit has also support for [interceptors](http://pedestal.io/reference/intercep
## Reitit-http
```clj
[metosin/reitit-http "0.5.18"]
[metosin/reitit-http "0.6.0"]
```
A module for http-routing using interceptors instead of middleware. Builds on top of the [`reitit-ring`](../ring/ring.md) module having all the same features.

View file

@ -3,7 +3,7 @@
[Pedestal](http://pedestal.io/) is a backend web framework for Clojure. `reitit-pedestal` provides an alternative routing engine for Pedestal.
```clj
[metosin/reitit-pedestal "0.5.18"]
[metosin/reitit-pedestal "0.6.0"]
```
Why should one use reitit instead of the Pedestal [default routing](http://pedestal.io/reference/routing-quick-reference)?
@ -26,8 +26,8 @@ A minimalistic example on how to to swap the default-router with a reitit router
```clj
; [io.pedestal/pedestal.service "0.5.5"]
; [io.pedestal/pedestal.jetty "0.5.5"]
; [metosin/reitit-pedestal "0.5.18"]
; [metosin/reitit "0.5.18"]
; [metosin/reitit-pedestal "0.6.0"]
; [metosin/reitit "0.6.0"]
(require '[io.pedestal.http :as server])
(require '[reitit.pedestal :as pedestal])

View file

@ -1,7 +1,7 @@
# Sieppari
```clj
[metosin/reitit-sieppari "0.5.18"]
[metosin/reitit-sieppari "0.6.0"]
```
[Sieppari](https://github.com/metosin/sieppari) is a new and fast interceptor implementation for Clojure, with pluggable async supporting [core.async](https://github.com/clojure/core.async), [Manifold](https://github.com/ztellman/manifold) and [Promesa](http://funcool.github.io/promesa/latest).

View file

@ -65,7 +65,7 @@ There is an extra option in http-router (actually, in the underlying interceptor
### Printing Context Diffs
```clj
[metosin/reitit-interceptors "0.5.18"]
[metosin/reitit-interceptors "0.6.0"]
```
Using `reitit.http.interceptors.dev/print-context-diffs` transformation, the context diffs between each interceptor are printed out to the console. To use it, add the following router option:

View file

@ -114,7 +114,7 @@ A quick poke to [the fast routers in Go](https://github.com/julienschmidt/go-htt
### Faster!
By default, `reitit.ring/ring-router`, `reitit.http/ring-router` and `reitit.http/routing-interceptor` inject both `Match` and `Router` into the request. You can remove the injections setting options `:inject-match?` and `:inject-router?` to `false`. This saves some tens of nanos (with the hw described above).
By default, `reitit.ring/router`, `reitit.http/router` and `reitit.http/routing-interceptor` inject both `Match` and `Router` into the request. You can remove the injections setting options `:inject-match?` and `:inject-router?` to `false`. This saves some tens of nanos (with the hw described above).
```clj
(require '[reitit.ring :as ring])

View file

@ -1,7 +1,7 @@
# Default Middleware
```clj
[metosin/reitit-middleware "0.5.18"]
[metosin/reitit-middleware "0.6.0"]
```
Any Ring middleware can be used with `reitit-ring`, but using data-driven middleware is preferred as they are easier to manage and in many cases yield better performance. `reitit-middleware` contains a set of common ring middleware, lifted into data-driven middleware.

View file

@ -1,7 +1,7 @@
# Exception Handling with Ring
```clj
[metosin/reitit-middleware "0.5.18"]
[metosin/reitit-middleware "0.6.0"]
```
Exceptions thrown in router creation can be [handled with custom exception handler](../basics/error_messages.md). By default, exceptions thrown at runtime from a handler or a middleware are not caught by the `reitit.ring/ring-handler`. A good practice is to have a top-level exception handler to log and format errors for clients.

View file

@ -5,12 +5,12 @@
Read more about the [Ring Concepts](https://github.com/ring-clojure/ring/wiki/Concepts).
```clj
[metosin/reitit-ring "0.5.18"]
[metosin/reitit-ring "0.6.0"]
```
## `reitit.ring/ring-router`
## `reitit.ring/router`
`ring-router` is a higher order router, which adds support for `:request-method` based routing, [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers) and [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware).
`reitit.ring/router` is a higher order router, which adds support for `:request-method` based routing, [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers) and [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware).
It accepts the following options:
@ -33,7 +33,7 @@ Example router:
["/ping" {:get handler}]))
```
Match contains `:result` compiled by the `ring-router`:
Match contains `:result` compiled by `reitit.ring/router`:
```clj
(require '[reitit.core :as r])
@ -49,7 +49,7 @@ Match contains `:result` compiled by the `ring-router`:
## `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](https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html) request handling. The following options are available:
Given a router from `reitit.ring/router`, optional default-handler & options, `ring-handler` function will return a valid ring handler supporting both synchronous and [asynchronous](https://www.booleanknot.com/blog/2016/07/15/asynchronous-ring.html) request handling. The following options are available:
| key | description |
| ------------------|-------------|

View file

@ -1,12 +1,12 @@
# Swagger Support
```
[metosin/reitit-swagger "0.5.18"]
[metosin/reitit-swagger "0.6.0"]
```
Reitit supports [Swagger2](https://swagger.io/) documentation, thanks to [schema-tools](https://github.com/metosin/schema-tools) and [spec-tools](https://github.com/metosin/spec-tools). Documentation is extracted from route definitions, coercion `:parameters` and `:responses` and from a set of new documentation keys.
To enable swagger-documentation for a ring-router:
To enable swagger-documentation for a Ring router:
1. annotate your routes with swagger-data
2. mount a swagger-handler to serve the swagger-spec
@ -45,7 +45,7 @@ If you need to post-process the generated spec, just wrap the handler with a cus
[Swagger-ui](https://github.com/swagger-api/swagger-ui) is a user interface to visualize and interact with the Swagger specification. To make things easy, there is a pre-integrated version of the swagger-ui as a separate module.
```
[metosin/reitit-swagger-ui "0.5.18"]
[metosin/reitit-swagger-ui "0.6.0"]
```
`reitit.swagger-ui/create-swagger-ui-handler` can be used to create a ring-handler to serve the swagger-ui. It accepts the following options:
@ -129,7 +129,7 @@ Another way to serve the swagger-ui is using the [default handler](default_handl
["/pong" {:post (constantly {:status 200, :body "pong"})}]]
["/swagger.json"
{:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]])
:handler (swagger/create-swagger-handler)}}]])
(swagger-ui/create-swagger-ui-handler {:path "/api-docs"})))
```

View file

@ -1,6 +1,6 @@
# Transforming the Middleware Chain
There is an extra option in ring-router (actually, in the underlying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. Value should be a function or a vector of functions that get a vector of compiled middleware and should return a new vector of middleware.
There is an extra option in the Ring router (actually, in the underlying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. Value should be a function or a vector of functions that get a vector of compiled middleware and should return a new vector of middleware.
## Example Application
@ -59,7 +59,7 @@ There is an extra option in ring-router (actually, in the underlying middleware-
### Printing Request Diffs
```clj
[metosin/reitit-middleware "0.5.18"]
[metosin/reitit-middleware "0.6.0"]
```
Using `reitit.ring.middleware.dev/print-request-diffs` transformation, the request diffs between each middleware are printed out to the console. To use it, add the following router option:
@ -71,4 +71,3 @@ Using `reitit.ring.middleware.dev/print-request-diffs` transformation, the reque
Sample output:
![Ring Request Diff](../images/ring-request-diff.png)

View file

@ -2,6 +2,6 @@
:description "Reitit Buddy Auth App"
:dependencies [[org.clojure/clojure "1.10.1"]
[ring/ring-jetty-adapter "1.8.1"]
[metosin/reitit "0.5.18"]
[metosin/reitit "0.6.0"]
[buddy "2.0.0"]]
:repl-options {:init-ns example.server})

View file

@ -10,9 +10,9 @@
[ring "1.7.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.439"]
[metosin/reitit "0.5.18"]
[metosin/reitit-schema "0.5.18"]
[metosin/reitit-frontend "0.5.18"]
[metosin/reitit "0.6.0"]
[metosin/reitit-schema "0.6.0"]
[metosin/reitit-frontend "0.6.0"]
;; Just for pretty printting the match
[fipp "0.6.14"]]

View file

@ -10,9 +10,9 @@
[ring "1.7.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.439"]
[metosin/reitit "0.5.18"]
[metosin/reitit-schema "0.5.18"]
[metosin/reitit-frontend "0.5.18"]
[metosin/reitit "0.6.0"]
[metosin/reitit-schema "0.6.0"]
[metosin/reitit-frontend "0.6.0"]
;; Just for pretty printting the match
[fipp "0.6.14"]]

View file

@ -10,9 +10,9 @@
[ring "1.7.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.520"]
[metosin/reitit "0.5.18"]
[metosin/reitit-spec "0.5.18"]
[metosin/reitit-frontend "0.5.18"]
[metosin/reitit "0.6.0"]
[metosin/reitit-spec "0.6.0"]
[metosin/reitit-frontend "0.6.0"]
;; Just for pretty printting the match
[fipp "0.6.14"]]

View file

@ -10,9 +10,9 @@
[ring "1.7.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.520"]
[metosin/reitit "0.5.18"]
[metosin/reitit-spec "0.5.18"]
[metosin/reitit-frontend "0.5.18"]
[metosin/reitit "0.6.0"]
[metosin/reitit-spec "0.6.0"]
[metosin/reitit-frontend "0.6.0"]
;; Just for pretty printting the match
[fipp "0.6.14"]]

View file

@ -1,7 +1,7 @@
(defproject frontend-re-frame "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/clojurescript "1.10.520"]
[metosin/reitit "0.5.18"]
[metosin/reitit "0.6.0"]
[reagent "0.8.1"]
[re-frame "0.10.6"]]

View file

@ -10,9 +10,9 @@
[ring "1.8.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.773"]
[metosin/reitit "0.5.18"]
[metosin/reitit-spec "0.5.18"]
[metosin/reitit-frontend "0.5.18"]
[metosin/reitit "0.6.0"]
[metosin/reitit-spec "0.6.0"]
[metosin/reitit-frontend "0.6.0"]
;; Just for pretty printting the match
[fipp "0.6.23"]]

View file

@ -3,5 +3,5 @@
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.1"]
[aleph "0.4.7-alpha5"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server})

View file

@ -5,5 +5,5 @@
[funcool/promesa "1.9.0"]
[manifold "0.1.8"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server})

View file

@ -2,4 +2,4 @@
:description "Reitit coercion with vanilla ring"
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]])
[metosin/reitit "0.6.0"]])

View file

@ -3,7 +3,7 @@
:dependencies [[org.clojure/clojure "1.10.0"]
[io.pedestal/pedestal.service "0.5.5"]
[io.pedestal/pedestal.jetty "0.5.5"]
[metosin/reitit-malli "0.5.18"]
[metosin/reitit-pedestal "0.5.18"]
[metosin/reitit "0.5.18"]]
[metosin/reitit-malli "0.6.0"]
[metosin/reitit-pedestal "0.6.0"]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns server})

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.10.0"]
[io.pedestal/pedestal.service "0.5.5"]
[io.pedestal/pedestal.jetty "0.5.5"]
[metosin/reitit-pedestal "0.5.18"]
[metosin/reitit "0.5.18"]]
[metosin/reitit-pedestal "0.6.0"]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server})

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.10.0"]
[io.pedestal/pedestal.service "0.5.5"]
[io.pedestal/pedestal.jetty "0.5.5"]
[metosin/reitit-pedestal "0.5.18"]
[metosin/reitit "0.5.18"]]
[metosin/reitit-pedestal "0.6.0"]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server})

View file

@ -2,5 +2,5 @@
:description "Reitit Ring App"
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server})

View file

@ -2,7 +2,7 @@
:description "Reitit Ring App with Integrant"
:dependencies [[org.clojure/clojure "1.10.1"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]
[metosin/reitit "0.6.0"]
[integrant "0.7.0"]]
:main example.server
:repl-options {:init-ns user}

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.10.0"]
[metosin/jsonista "0.2.6"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.3.2"]]}})

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.10.0"]
[metosin/jsonista "0.2.6"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.3.2"]]}})

View file

@ -2,6 +2,6 @@
:description "Reitit Ring App with Swagger"
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.3.2"]]}})

View file

@ -2,5 +2,5 @@
:description "Reitit Ring App with Swagger"
:dependencies [[org.clojure/clojure "1.10.0"]
[ring/ring-jetty-adapter "1.7.1"]
[metosin/reitit "0.5.18"]]
[metosin/reitit "0.6.0"]]
:repl-options {:init-ns example.server})

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-core "0.5.18"
(defproject metosin/reitit-core "0.6.0"
:description "Snappy data-driven router for Clojure(Script)"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -40,7 +40,8 @@
:request (->ParameterCoercion :body-params :request false false)
:form (->ParameterCoercion :form-params :string true true)
:header (->ParameterCoercion :headers :string true true)
:path (->ParameterCoercion :path-params :string true true)})
:path (->ParameterCoercion :path-params :string true true)
:fragment (->ParameterCoercion :fragment :string true true)})
(defn ^:no-doc request-coercion-failed! [result coercion value in request serialize-failed-result]
(throw

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-dev "0.5.18"
(defproject metosin/reitit-dev "0.6.0"
:description "Snappy data-driven router for Clojure(Script)"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-frontend "0.5.18"
(defproject metosin/reitit-frontend "0.6.0"
:description "Reitit: Clojurescript frontend routing core"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -37,12 +37,17 @@
coercion/coerce!)]
(if-let [match (r/match-by-path router (.getPath uri))]
(let [q (query-params uri)
match (assoc match :query-params q)
fragment (when (.hasFragment uri)
(.getFragment uri))
match (assoc match
:query-params q
:fragment fragment)
;; Return uncoerced values if coercion is not enabled - so
;; that tha parameters are always accessible from same property.
parameters (or (coerce! match)
{:path (:path-params match)
:query q})]
:query q
:fragment fragment})]
(assoc match :parameters parameters))))))
(defn match-by-name

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-http "0.5.18"
(defproject metosin/reitit-http "0.6.0"
:description "Reitit: HTTP routing with interceptors"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-interceptors "0.5.18"
(defproject metosin/reitit-interceptors "0.6.0"
:description "Reitit, common interceptors bundled"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-malli "0.5.18"
(defproject metosin/reitit-malli "0.6.0"
:description "Reitit: Malli coercion"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-middleware "0.5.18"
(defproject metosin/reitit-middleware "0.6.0"
:description "Reitit, common middleware bundled"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-pedestal "0.5.18"
(defproject metosin/reitit-pedestal "0.6.0"
:description "Reitit + Pedestal Integration"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-ring "0.5.18"
(defproject metosin/reitit-ring "0.6.0"
:description "Reitit: Ring routing"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -339,6 +339,22 @@
nil)))
{::r/router router}))))
(defn reloading-ring-handler
"Returns a ring-handler that recreates the actual ring-handler for each request.
Takes a 0-arity function that should return a valid ring-handler. Effectively creates
an auto-reloading ring-handler, which is good for REPL-driven development.
Example:
;; for dev-mode, recreate the ring-handler for each request, for prod, just once
(let [dev-mode ...
f (fn [] (reitit.ring/ring-handler ...)]
(if dev-mode (reitit.ring/reloading-ring-handler f) (f)))"
[f]
(fn
([request] ((f) request))
([request respond raise] ((f) request respond raise))))
(defn get-router [handler]
(-> handler meta ::r/router))

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-schema "0.5.18"
(defproject metosin/reitit-schema "0.6.0"
:description "Reitit: Plumatic Schema coercion"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-sieppari "0.5.18"
(defproject metosin/reitit-sieppari "0.6.0"
:description "Reitit: Sieppari Interceptors"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-spec "0.5.18"
(defproject metosin/reitit-spec "0.6.0"
:description "Reitit: clojure.spec coercion"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-swagger-ui "0.5.18"
(defproject metosin/reitit-swagger-ui "0.6.0"
:description "Reitit: Swagger-ui support"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-swagger "0.5.18"
(defproject metosin/reitit-swagger "0.6.0"
:description "Reitit: Swagger-support"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit "0.5.18"
(defproject metosin/reitit "0.6.0"
:description "Snappy data-driven router for Clojure(Script)"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,10 +1,13 @@
(defproject metosin/reitit-parent "0.5.18"
(defproject metosin/reitit-parent "0.6.0"
:description "Snappy data-driven router for Clojure(Script)"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:test-paths ["test/clj" "test/cljc"]
:deploy-repositories [["releases" :clojars]]
:deploy-repositories {"clojars" {:url "https://repo.clojars.org"
:sign-releases false
:username :env/clojars_username
:password :env/clojars_password}}
:codox {:output-path "doc"
:source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}"
:metadata {:doc/format :markdown}}
@ -12,21 +15,21 @@
:url "https://github.com/metosin/reitit"}
;; TODO: need to verify that the code actually worked with Java1.8, see #242
:javac-options ["-Xlint:unchecked" "-target" "1.8" "-source" "1.8"]
:managed-dependencies [[metosin/reitit "0.5.18"]
[metosin/reitit-core "0.5.18"]
[metosin/reitit-dev "0.5.18"]
[metosin/reitit-spec "0.5.18"]
[metosin/reitit-malli "0.5.18"]
[metosin/reitit-schema "0.5.18"]
[metosin/reitit-ring "0.5.18"]
[metosin/reitit-middleware "0.5.18"]
[metosin/reitit-http "0.5.18"]
[metosin/reitit-interceptors "0.5.18"]
[metosin/reitit-swagger "0.5.18"]
[metosin/reitit-swagger-ui "0.5.18"]
[metosin/reitit-frontend "0.5.18"]
[metosin/reitit-sieppari "0.5.18"]
[metosin/reitit-pedestal "0.5.18"]
:managed-dependencies [[metosin/reitit "0.6.0"]
[metosin/reitit-core "0.6.0"]
[metosin/reitit-dev "0.6.0"]
[metosin/reitit-spec "0.6.0"]
[metosin/reitit-malli "0.6.0"]
[metosin/reitit-schema "0.6.0"]
[metosin/reitit-ring "0.6.0"]
[metosin/reitit-middleware "0.6.0"]
[metosin/reitit-http "0.6.0"]
[metosin/reitit-interceptors "0.6.0"]
[metosin/reitit-swagger "0.6.0"]
[metosin/reitit-swagger-ui "0.6.0"]
[metosin/reitit-frontend "0.6.0"]
[metosin/reitit-sieppari "0.6.0"]
[metosin/reitit-pedestal "0.6.0"]
[metosin/ring-swagger-ui "4.15.5"]
[metosin/spec-tools "0.10.5"]
[metosin/schema-tools "0.12.3"]
@ -36,8 +39,8 @@
[metosin/malli "0.10.1"]
;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111
[com.fasterxml.jackson.core/jackson-core "2.14.1"]
[com.fasterxml.jackson.core/jackson-databind "2.14.1"]
[com.fasterxml.jackson.core/jackson-core "2.14.2"]
[com.fasterxml.jackson.core/jackson-databind "2.14.2"]
[meta-merge "1.0.0"]
[fipp "0.6.26" :exclusions [org.clojure/core.rrb-vector]]
@ -103,8 +106,8 @@
[criterium "0.4.6"]
[org.clojure/test.check "1.1.1"]
[org.clojure/tools.namespace "1.3.0"]
[com.gfredericks/test.chuck "0.2.13"]
[org.clojure/tools.namespace "1.4.1"]
[com.gfredericks/test.chuck "0.2.14"]
[nubank/matcher-combinators "3.8.3"]
[io.pedestal/pedestal.service "0.5.10"]

View file

@ -38,7 +38,7 @@
nil
nil)))))
(deftest ring-router-test
(deftest router-test
(testing "all paths should have a handler"
(is (thrown-with-msg?
@ -733,6 +733,25 @@
{::trie/trie-compiler compiler})]
(dotimes [_ 10]
(future
(dotimes [n 100000]
(let [body (:body (app {:request-method :get, :uri (str "/" n)}))]
(is (= body (str n))))))))))))
(dotimes [n 100000]
(let [body (:body (app {:request-method :get, :uri (str "/" n)}))]
(is (= body (str n))))))))))))
(declare routes)
(deftest reloading-ring-handler-test
(let [r (fn [body] {:status 200, :body body})]
(def routes ["/" (constantly (r "1"))]) ;; initial value
(let [create-handler (fn [] (ring/ring-handler (ring/router routes)))]
(testing "static ring handler does not see underlying route changes"
(let [app (create-handler)]
(is (= (r "1") (app {:uri "/", :request-method :get})))
(def routes ["/" (constantly (r "2"))]) ;; redefine
(is (= (r "1") (app {:uri "/", :request-method :get})))))
(testing "reloading ring handler sees underlying route changes"
(let [app (ring/reloading-ring-handler create-handler)]
(is (= (r "2") (app {:uri "/", :request-method :get})))
(def routes ["/" (constantly (r "3"))]) ;; redefine again
(is (= (r "3") (app {:uri "/", :request-method :get}))))))))

View file

@ -4,12 +4,23 @@
[reitit.frontend :as rf]
[reitit.coercion :as rc]
[schema.core :as s]
[reitit.coercion.schema :as rsc]
[reitit.coercion.schema :as rcs]
[reitit.coercion.malli :as rcm]
[reitit.frontend.test-utils :refer [capture-console]]))
(defn m [x]
(assoc x :data nil :result nil))
(defn decode-form [s]
;; RFC 6749 4.2.2 specifies OAuth token response uses
;; form-urlencoded format to encode values in the fragment string.
;; Use built-in JS function to decode.
;; ring.util.codec/decode-form works on Clj.
(when s
(->> (.entries (js/URLSearchParams. s))
(map (fn [[k v]] [(keyword k) v]))
(into {}))))
(deftest match-by-path-test
(testing "simple"
(let [router (r/router ["/"
@ -22,8 +33,10 @@
:path-params {}
:query-params {}
:path "/"
:fragment nil
:parameters {:query {}
:path {}}})
:path {}
:fragment nil}})
(rf/match-by-path router "/")))
(is (= "/"
@ -35,8 +48,10 @@
:path-params {}
:query-params {}
:path "/foo"
:fragment nil
:parameters {:query {}
:path {}}})
:path {}
:fragment nil}})
(rf/match-by-path router "/foo")))
(is (= (r/map->Match
@ -45,8 +60,10 @@
:path-params {}
:query-params {:mode ["foo", "bar"]}
:path "/foo"
:fragment nil
:parameters {:query {:mode ["foo", "bar"]}
:path {}}})
:path {}
:fragment nil}})
(rf/match-by-path router "/foo?mode=foo&mode=bar")))
(is (= "/foo"
@ -64,17 +81,20 @@
(let [router (r/router ["/"
[":id" {:name ::foo
:parameters {:path {:id s/Int}
:query {(s/optional-key :mode) s/Keyword}}}]]
:query {(s/optional-key :mode) s/Keyword}
:fragment (s/maybe s/Str)}}]]
{:compile rc/compile-request-coercers
:data {:coercion rsc/coercion}})]
:data {:coercion rcs/coercion}})]
(is (= (r/map->Match
{:template "/:id"
:path-params {:id "5"}
:query-params {}
:path "/5"
:fragment nil
:parameters {:query {}
:path {:id 5}}})
:path {:id 5}
:fragment nil}})
(m (rf/match-by-path router "/5"))))
(is (= "/5"
@ -99,21 +119,25 @@
:path-params {:id "5"}
:query-params {:mode "foo"}
:path "/5"
:fragment nil
:parameters {:path {:id 5}
:query {:mode :foo}}})
:query {:mode :foo}
:fragment nil}})
(m (rf/match-by-path router "/5?mode=foo"))))
(is (= "/5?mode=foo"
(r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo}))))
(testing "fragment is ignored"
(testing "fragment string is read"
(is (= (r/map->Match
{:template "/:id"
:path-params {:id "5"}
:query-params {:mode "foo"}
:path "/5"
:fragment "fragment"
:parameters {:path {:id 5}
:query {:mode :foo}}})
:query {:mode :foo}
:fragment "fragment"}})
(m (rf/match-by-path router "/5?mode=foo#fragment")))))
(testing "console warning about missing params"
@ -126,4 +150,80 @@
(:messages
(capture-console
(fn []
(rf/match-by-name! router ::foo {}))))))))))
(rf/match-by-name! router ::foo {})))))))))
(testing "malli coercion"
(let [router (r/router ["/"
[":id" {:name ::foo
:parameters {:path [:map
[:id :int]]
:query [:map
[:mode {:optional true} :keyword]]
:fragment [:maybe
[:map
{:decode/string decode-form}
[:access_token :string]
[:refresh_token :string]
[:expires_in :int]
[:provider_token :string]
[:token_type :string]]]}}]]
{:compile rc/compile-request-coercers
:data {:coercion rcm/coercion}})]
(is (= (r/map->Match
{:template "/:id"
:path-params {:id "5"}
:query-params {}
:path "/5"
:fragment nil
:parameters {:query {}
:path {:id 5}
:fragment nil}})
(m (rf/match-by-path router "/5"))))
(is (= "/5"
(r/match->path (rf/match-by-name router ::foo {:id 5}))))
(testing "coercion error"
(testing "throws without options"
(is (thrown? js/Error (m (rf/match-by-path router "/a")))))
(testing "thows and calles on-coercion-error"
(let [exception (atom nil)
match (atom nil)]
(is (thrown? js/Error (m (rf/match-by-path router "/a" {:on-coercion-error (fn [m e]
(reset! match m)
(reset! exception e))}))))
(is (= {:id "a"} (-> @match :path-params)))
(is (= {:id "a"} (-> @exception (ex-data) :value))))))
(testing "query param is read"
(is (= (r/map->Match
{:template "/:id"
:path-params {:id "5"}
:query-params {:mode "foo"}
:path "/5"
:fragment nil
:parameters {:path {:id 5}
:query {:mode :foo}
:fragment nil}})
(m (rf/match-by-path router "/5?mode=foo"))))
(is (= "/5?mode=foo"
(r/match->path (rf/match-by-name router ::foo {:id 5}) {:mode :foo}))))
(testing "fragment string is read"
(is (= (r/map->Match
{:template "/:id"
:path-params {:id "5"}
:query-params {:mode "foo"}
:path "/5"
:fragment "access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600"
:parameters {:path {:id 5}
:query {:mode :foo}
:fragment {:access_token "foo"
:refresh_token "bar"
:provider_token "baz"
:token_type "bearer"
:expires_in 3600}}})
(m (rf/match-by-path router "/5?mode=foo#access_token=foo&refresh_token=bar&provider_token=baz&token_type=bearer&expires_in=3600"))))))))