From f6c460d05c7ca1af8f439d01bdf910d45043481b Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 24 Jun 2018 18:36:55 +0300 Subject: [PATCH 1/7] If response body is not defined, response is passed as-is --- CHANGELOG.md | 1 + modules/reitit-core/src/reitit/coercion.cljc | 3 +- test/cljc/reitit/ring_coercion_test.cljc | 30 +++++++++++++------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aa591cd..0245ce3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## `reitit-core` * `reitit.coercion/coerce!` coerced all parameters found in match, e.g. injecting in `:query-parameters` into `Match` with coerce those too if `:query` coercion is defined. +* if response coercion is not defined for a response status, response is still returned * `spec-tools.data-spec/maybe` can be used in spec-coercion. ```clj diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 4fdababa..91a02231 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -116,7 +116,8 @@ (defn coerce-response [coercers request response] (if response (if-let [coercer (or (coercers (:status response)) (coercers :default))] - (impl/fast-assoc response :body (coercer request response))))) + (impl/fast-assoc response :body (coercer request response)) + response))) (defn request-coercers [coercion parameters opts] (->> (for [[k v] parameters diff --git a/test/cljc/reitit/ring_coercion_test.cljc b/test/cljc/reitit/ring_coercion_test.cljc index ea767457..d212a150 100644 --- a/test/cljc/reitit/ring_coercion_test.cljc +++ b/test/cljc/reitit/ring_coercion_test.cljc @@ -5,9 +5,8 @@ [reitit.ring.coercion :as rrc] [reitit.coercion.spec :as spec] [reitit.coercion.schema :as schema] - #?@(:clj [ - [muuntaja.middleware] - [jsonista.core :as j]])) + #?@(:clj [[muuntaja.middleware] + [jsonista.core :as j]])) #?(:clj (:import (clojure.lang ExceptionInfo) (java.io ByteArrayInputStream)))) @@ -17,8 +16,11 @@ {:keys [c]} :form {:keys [d]} :header {:keys [e]} :path} :parameters}] - {:status 200 - :body {:total (+ a b c d e)}}) + (if (= 666 a) + {:status 500 + :body {:evil true}} + {:status 200 + :body {:total (+ a b c d e)}})) (def valid-request {:uri "/api/plus/5" @@ -51,19 +53,23 @@ :form {:c int?} :header {:d int?} :path {:e int?}} - :responses {200 {:body {:total pos-int?}}} + :responses {200 {:body {:total pos-int?}} + 500 {:description "fail"}} :handler handler}}]] {:data {:middleware middleware :coercion spec/coercion}})))] - (testing "withut exception handling" + (testing "without exception handling" (let [app (create [rrc/coerce-request-middleware rrc/coerce-response-middleware])] (testing "all good" (is (= {:status 200 :body {:total 15}} - (app valid-request)))) + (app valid-request))) + (is (= {:status 500 + :body {:evil true}} + (app (assoc-in valid-request [:query-params "a"] "666"))))) (testing "invalid request" (is (thrown-with-msg? @@ -106,7 +112,8 @@ :form {:c s/Int} :header {:d s/Int} :path {:e s/Int}} - :responses {200 {:body {:total (s/constrained s/Int pos? 'positive)}}} + :responses {200 {:body {:total (s/constrained s/Int pos? 'positive)}} + 500 {:description "fail"}} :handler handler}}]] {:data {:middleware middleware :coercion schema/coercion}})))] @@ -118,7 +125,10 @@ (testing "all good" (is (= {:status 200 :body {:total 15}} - (app valid-request)))) + (app valid-request))) + (is (= {:status 500 + :body {:evil true}} + (app (assoc-in valid-request [:query-params "a"] "666"))))) (testing "invalid request" (is (thrown-with-msg? From 3af1bd20830d93025f2e655439ca2161cc24c874 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 24 Jun 2018 19:20:08 +0300 Subject: [PATCH 2/7] Allow empty response :body for Swagger --- .../src/reitit/coercion/schema.cljc | 9 ++++++--- .../reitit-spec/src/reitit/coercion/spec.cljc | 20 ++++++++++++++----- project.clj | 2 +- test/cljc/reitit/swagger_test.clj | 12 +++++++---- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/modules/reitit-schema/src/reitit/coercion/schema.cljc b/modules/reitit-schema/src/reitit/coercion/schema.cljc index 1f626886..c7bbc7e6 100644 --- a/modules/reitit-schema/src/reitit/coercion/schema.cljc +++ b/modules/reitit-schema/src/reitit/coercion/schema.cljc @@ -61,9 +61,12 @@ {::swagger/responses (into (empty responses) - (for [[k response] responses - :let [response (set/rename-keys response {:body :schema})]] - [k (update response :schema #(coercion/-compile-model this % nil))]))}))) + (for [[k response] responses] + [k (as-> response $ + (set/rename-keys $ {:body :schema}) + (if (:schema $) + (update $ :schema #(coercion/-compile-model this % nil)) + $))]))}))) (throw (ex-info (str "Can't produce Schema apidocs for " spesification) diff --git a/modules/reitit-spec/src/reitit/coercion/spec.cljc b/modules/reitit-spec/src/reitit/coercion/spec.cljc index 18025ae8..db3e6206 100644 --- a/modules/reitit-spec/src/reitit/coercion/spec.cljc +++ b/modules/reitit-spec/src/reitit/coercion/spec.cljc @@ -29,7 +29,11 @@ :default-encoder stt/any->any})) (def no-op-transformer - st/no-op-transformer) + (reify + st/Transformer + (-name [_] ::no-op) + (-encoder [_ _ _]) + (-decoder [_ _ _]))) (defprotocol IntoSpec (into-spec [this name])) @@ -59,7 +63,10 @@ #?(:clj Object :cljs default) (into-spec [this _] - (st/create-spec {:spec this}))) + (st/create-spec {:spec this})) + + nil + (into-spec [this _])) (defn stringify-pred [pred] (str (if (seq? pred) (seq pred) pred))) @@ -93,9 +100,12 @@ {::swagger/responses (into (empty responses) - (for [[k response] responses - :let [response (set/rename-keys response {:body :schema})]] - [k (update response :schema #(coercion/-compile-model this % nil))]))}))) + (for [[k response] responses] + [k (as-> response $ + (set/rename-keys $ {:body :schema}) + (if (:schema $) + (update $ :schema #(coercion/-compile-model this % nil)) + $))]))}))) (throw (ex-info (str "Can't produce Spec apidocs for " spesification) diff --git a/project.clj b/project.clj index 0bdfe394..7233f9e2 100644 --- a/project.clj +++ b/project.clj @@ -19,7 +19,7 @@ [meta-merge "1.0.0"] [ring/ring-core "1.6.3"] - [metosin/spec-tools "0.7.0"] + [metosin/spec-tools "0.7.1"] [metosin/schema-tools "0.10.3"] [metosin/ring-swagger-ui "2.2.10"] [metosin/jsonista "0.2.1"]] diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index c1d0631c..1b4722fa 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -23,7 +23,8 @@ {:get {:summary "plus" :parameters {:query {:x int?, :y int?} :path {:z int?}} - :responses {200 {:body {:total int?}}} + :responses {200 {:body {:total int?}} + 500 {:description "fail"}} :handler (fn [{{{:keys [x y]} :query {:keys [z]} :path} :parameters}] {:status 200, :body {:total (+ x y z)}})}}]] @@ -33,7 +34,8 @@ {:get {:summary "plus" :parameters {:query {:x Int, :y Int} :path {:z Int}} - :responses {200 {:body {:total Int}}} + :responses {200 {:body {:total Int}} + 500 {:description "fail"}} :handler (fn [{{{:keys [x y]} :query {:keys [z]} :path} :parameters}] {:status 200, :body {:total (+ x y z)}})}}]]] @@ -87,7 +89,8 @@ :properties {"total" {:format "int32" :type "integer"}} :required ["total"] - :type "object"}}} + :type "object"}} + 500 {:description "fail"}} :summary "plus"}} "/api/spec/plus/{z}" {:get {:parameters [{:description "" :format "int64" @@ -111,7 +114,8 @@ :schema {:properties {"total" {:format "int64" :type "integer"}} :required ["total"] - :type "object"}}} + :type "object"}} + 500 {:description "fail"}} :summary "plus"}}}} spec))))) From 1bab89b1a00bba27913ab335a6ca5ac09b3c5014 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 24 Jun 2018 19:28:50 +0300 Subject: [PATCH 3/7] more tests --- test/cljc/reitit/ring_spec_test.cljc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/cljc/reitit/ring_spec_test.cljc b/test/cljc/reitit/ring_spec_test.cljc index 2c930728..73c41c5c 100644 --- a/test/cljc/reitit/ring_spec_test.cljc +++ b/test/cljc/reitit/ring_spec_test.cljc @@ -89,7 +89,9 @@ :form {:c string?} :header {:d string?} :path {:e string?}} - :responses {200 {:body {:total pos-int?}}} + :responses {200 {:body {:total pos-int?}} + 400 {:description "fail"} + 500 {}} :handler identity}}]] {:data {:middleware [rrc/coerce-exceptions-middleware rrc/coerce-request-middleware From 8bf725f600b97d2e14021c5d83f9737a18703af4 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 24 Jun 2018 22:29:08 +0300 Subject: [PATCH 4/7] 0.1.3-SNAPSHOT --- CHANGELOG.md | 16 +++++++++++++++- project.clj | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0245ce3d..739aa182 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.1.3-SNAPSHOT ## `reitit-core` @@ -38,6 +38,20 @@ ; "/olipa/kerran?iso=p%C3%B6ril%C3%A4inen" ``` +### `reitit-spec` + +* `[metosin/spec-tools "0.7.1"]` with swagger generation enhancements, see the [CHANGELOG](https://github.com/metosin/spec-tools/blob/master/CHANGELOG.md) +* if response coercion is not defined for a response status, no `:schema` is not emitted. +* updated dependencies: + +```clj +[metosin/spec-tools "0.7.1"] is available but we use "0.7.0" +``` + +### `reitit-schema` + +* if response coercion is not defined for a response status, no `:schema` is not emitted. + ## 0.1.2 (2018-6-6) ### `reitit-core` diff --git a/project.clj b/project.clj index 7233f9e2..ca6979d0 100644 --- a/project.clj +++ b/project.clj @@ -19,7 +19,7 @@ [meta-merge "1.0.0"] [ring/ring-core "1.6.3"] - [metosin/spec-tools "0.7.1"] + [metosin/spec-tools "0.7.1-SNAPSHOT"] [metosin/schema-tools "0.10.3"] [metosin/ring-swagger-ui "2.2.10"] [metosin/jsonista "0.2.1"]] From 18bd2e684f0ad8a8a9dc60fa1ef7e67d4d08e0a2 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 24 Jun 2018 22:32:23 +0300 Subject: [PATCH 5/7] bump up version (all but docs) --- doc/ring/default_handler.md | 2 +- examples/just-coercion-with-ring/project.clj | 2 +- examples/ring-example/project.clj | 2 +- examples/ring-swagger/project.clj | 2 +- modules/reitit-core/project.clj | 2 +- modules/reitit-ring/project.clj | 2 +- modules/reitit-schema/project.clj | 2 +- modules/reitit-spec/project.clj | 2 +- modules/reitit-swagger-ui/project.clj | 2 +- modules/reitit-swagger/project.clj | 2 +- modules/reitit/project.clj | 2 +- project.clj | 16 ++++++++-------- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/ring/default_handler.md b/doc/ring/default_handler.md index 7fc38604..ea5656cf 100644 --- a/doc/ring/default_handler.md +++ b/doc/ring/default_handler.md @@ -79,4 +79,4 @@ With custom responses: (app {:request-method :get, :uri "/pong"}) ; {:status 406, :body "kosh"} -``` \ No newline at end of file +``` diff --git a/examples/just-coercion-with-ring/project.clj b/examples/just-coercion-with-ring/project.clj index be84f8bd..c82e6ec6 100644 --- a/examples/just-coercion-with-ring/project.clj +++ b/examples/just-coercion-with-ring/project.clj @@ -3,4 +3,4 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.4.1"] - [metosin/reitit "0.1.2"]]) + [metosin/reitit "0.1.3-SNAPSHOT"]]) diff --git a/examples/ring-example/project.clj b/examples/ring-example/project.clj index 33d8831f..bbeb15f9 100644 --- a/examples/ring-example/project.clj +++ b/examples/ring-example/project.clj @@ -3,4 +3,4 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.4.1"] - [metosin/reitit "0.1.2"]]) + [metosin/reitit "0.1.3-SNAPSHOT"]]) diff --git a/examples/ring-swagger/project.clj b/examples/ring-swagger/project.clj index ea0abc6b..72966cf9 100644 --- a/examples/ring-swagger/project.clj +++ b/examples/ring-swagger/project.clj @@ -3,5 +3,5 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.5.0"] - [metosin/reitit "0.1.2"]] + [metosin/reitit "0.1.3-SNAPSHOT"]] :repl-options {:init-ns example.server}) diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index 48a26269..25349576 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-core "0.1.2" +(defproject metosin/reitit-core "0.1.3-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index 862bbf6c..498ae725 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-ring "0.1.2" +(defproject metosin/reitit-ring "0.1.3-SNAPSHOT" :description "Reitit: Ring routing" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-schema/project.clj b/modules/reitit-schema/project.clj index f51bc8fd..19c96453 100644 --- a/modules/reitit-schema/project.clj +++ b/modules/reitit-schema/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-schema "0.1.2" +(defproject metosin/reitit-schema "0.1.3-SNAPSHOT" :description "Reitit: Plumatic Schema coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-spec/project.clj b/modules/reitit-spec/project.clj index 913c29d3..2e3815dc 100644 --- a/modules/reitit-spec/project.clj +++ b/modules/reitit-spec/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-spec "0.1.2" +(defproject metosin/reitit-spec "0.1.3-SNAPSHOT" :description "Reitit: clojure.spec coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-swagger-ui/project.clj b/modules/reitit-swagger-ui/project.clj index d086934f..e259d9bb 100644 --- a/modules/reitit-swagger-ui/project.clj +++ b/modules/reitit-swagger-ui/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-swagger-ui "0.1.2" +(defproject metosin/reitit-swagger-ui "0.1.3-SNAPSHOT" :description "Reitit: Swagger-ui support" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-swagger/project.clj b/modules/reitit-swagger/project.clj index 37fabcd3..3ea4f8ea 100644 --- a/modules/reitit-swagger/project.clj +++ b/modules/reitit-swagger/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-swagger "0.1.2" +(defproject metosin/reitit-swagger "0.1.3-SNAPSHOT" :description "Reitit: Swagger-support" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index fededf42..a6335947 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit "0.1.2" +(defproject metosin/reitit "0.1.3-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/project.clj b/project.clj index ca6979d0..89f2475b 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-parent "0.1.2" +(defproject metosin/reitit-parent "0.1.3-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" @@ -9,13 +9,13 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :managed-dependencies [[metosin/reitit "0.1.2"] - [metosin/reitit-core "0.1.2"] - [metosin/reitit-ring "0.1.2"] - [metosin/reitit-spec "0.1.2"] - [metosin/reitit-schema "0.1.2"] - [metosin/reitit-swagger "0.1.2"] - [metosin/reitit-swagger-ui "0.1.2"] + :managed-dependencies [[metosin/reitit "0.1.3-SNAPSHOT"] + [metosin/reitit-core "0.1.3-SNAPSHOT"] + [metosin/reitit-ring "0.1.3-SNAPSHOT"] + [metosin/reitit-spec "0.1.3-SNAPSHOT"] + [metosin/reitit-schema "0.1.3-SNAPSHOT"] + [metosin/reitit-swagger "0.1.3-SNAPSHOT"] + [metosin/reitit-swagger-ui "0.1.3-SNAPSHOT"] [meta-merge "1.0.0"] [ring/ring-core "1.6.3"] From 1993dee5f25e21e5fce82a49197364eb0c3df96c Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 25 Jun 2018 10:18:40 +0300 Subject: [PATCH 6/7] demo normal swagger-responses --- test/cljc/reitit/swagger_test.clj | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 1b4722fa..97ed485d 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -23,10 +23,12 @@ {:get {:summary "plus" :parameters {:query {:x int?, :y int?} :path {:z int?}} + :swagger {:responses {400 {:schema {:type "string"} + :description "kosh"}}} :responses {200 {:body {:total int?}} 500 {:description "fail"}} :handler (fn [{{{:keys [x y]} :query - {:keys [z]} :path} :parameters}] + {:keys [z]} :path} :parameters}] {:status 200, :body {:total (+ x y z)}})}}]] ["/schema" {:coercion schema/coercion} @@ -34,10 +36,12 @@ {:get {:summary "plus" :parameters {:query {:x Int, :y Int} :path {:z Int}} + :swagger {:responses {400 {:schema {:type "string"} + :description "kosh"}}} :responses {200 {:body {:total Int}} 500 {:description "fail"}} :handler (fn [{{{:keys [x y]} :query - {:keys [z]} :path} :parameters}] + {:keys [z]} :path} :parameters}] {:status 200, :body {:total (+ x y z)}})}}]]] {:data {:middleware [swagger/swagger-feature @@ -90,6 +94,8 @@ :type "integer"}} :required ["total"] :type "object"}} + 400 {:schema {:type "string"} + :description "kosh"} 500 {:description "fail"}} :summary "plus"}} "/api/spec/plus/{z}" {:get {:parameters [{:description "" @@ -115,6 +121,8 @@ :type "integer"}} :required ["total"] :type "object"}} + 400 {:schema {:type "string"} + :description "kosh"} 500 {:description "fail"}} :summary "plus"}}}} spec))))) From cb0297ac8586491f755721e916624165d991eef3 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 25 Jun 2018 10:33:27 +0300 Subject: [PATCH 7/7] reverse-routing docs --- doc/basics/name_based_routing.md | 18 +++++++++++++ doc/ring/reverse_routing.md | 43 ++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/doc/basics/name_based_routing.md b/doc/basics/name_based_routing.md index 3e5c7d8c..4687dbdc 100644 --- a/doc/basics/name_based_routing.md +++ b/doc/basics/name_based_routing.md @@ -81,3 +81,21 @@ There is also a exception throwing version: (r/match-by-name! router ::user) ; ExceptionInfo missing path-params for route /api/user/:id: #{:id} ``` + +To turn a Match into a path, there is `reitit.core/match->path`: + +```clj +(-> router + (r/match-by-name ::user {:id 1}) + (r/match->path)) +; "/api/user/1" +``` + +It can take an optional map of query-parameters too: + +```clj +(-> router + (r/match-by-name ::user {:id 1}) + (r/match->path {:iso "möly"})) +; "/api/user/1?iso=m%C3%B6ly" +``` diff --git a/doc/ring/reverse_routing.md b/doc/ring/reverse_routing.md index 9cfd61c7..e2d7b5af 100644 --- a/doc/ring/reverse_routing.md +++ b/doc/ring/reverse_routing.md @@ -1,8 +1,8 @@ # Reverse routing with Ring -Both the `router` and the `match` are injected into Ring Request (as `::r/router` and `::r/match`) by the `reitit.ring/ring-handler` and with that, available to middleware and endpoints. +Both the `router` and the `match` are injected into Ring Request (as `::r/router` and `::r/match`) by the `reitit.ring/ring-handler` and with that, available to middleware and endpoints. To convert a `Match` into a path, one can use `r/match->path`, which optionally takes a map of query-parameters too. -Below is an example how to use the `router` to do reverse routing from a ring handler: +Below is an example how to do reverse routing from a ring handler: ```clj (require '[reitit.core :as r]) @@ -11,23 +11,28 @@ Below is an example how to use the `router` to do reverse routing from a ring ha (def app (ring/ring-handler (ring/router - [["/users" {:get (fn [{:keys [::r/router]}] - {:status 200 - :body (for [i (range 10)] - {:uri (:path (r/match-by-name router ::user {:id i}))})})}] - ["/users/:id" {:name ::user - :get (constantly {:status 200, :body "user..."})}]]))) + [["/users" + {:get (fn [{:keys [::r/router]}] + {:status 200 + :body (for [i (range 10)] + {:uri (-> router + (r/match-by-name ::user {:id i}) + ;; with extra query-params + (r/match->path {:iso "möly"}))})})}] + ["/users/:id" + {:name ::user + :get (constantly {:status 200, :body "user..."})}]]))) (app {:request-method :get, :uri "/users"}) -;{:status 200, -; :body [{:uri "/users/0"} -; {:uri "/users/1"} -; {:uri "/users/2"} -; {:uri "/users/3"} -; {:uri "/users/4"} -; {:uri "/users/5"} -; {:uri "/users/6"} -; {:uri "/users/7"} -; {:uri "/users/8"} -; {:uri "/users/9"}]} +; {:status 200, +; :body ({:uri "/users/0?iso=m%C3%B6ly"} +; {:uri "/users/1?iso=m%C3%B6ly"} +; {:uri "/users/2?iso=m%C3%B6ly"} +; {:uri "/users/3?iso=m%C3%B6ly"} +; {:uri "/users/4?iso=m%C3%B6ly"} +; {:uri "/users/5?iso=m%C3%B6ly"} +; {:uri "/users/6?iso=m%C3%B6ly"} +; {:uri "/users/7?iso=m%C3%B6ly"} +; {:uri "/users/8?iso=m%C3%B6ly"} +; {:uri "/users/9?iso=m%C3%B6ly"})} ```