Compare commits

..

1 commit

Author SHA1 Message Date
Daniel Compton
cd1f3a9777
Merge 7a707f042b into c3a152a44e 2025-11-24 08:31:24 -05:00
78 changed files with 186 additions and 283 deletions

View file

@ -1,6 +1,5 @@
{;;:skip-comments true
:lint-as {potemkin/def-derived-map clojure.core/defrecord
clojure.test.check.clojure-test/defspec clojure.test/deftest}
:lint-as {potemkin/def-derived-map clojure.core/defrecord}
:linters {:missing-else-branch {:level :off}
:unused-binding {:level :off}
:unused-referred-var {:exclude {clojure.test [deftest testing is are]

View file

@ -2,19 +2,16 @@ name: testsuite
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build-clj:
strategy:
matrix:
# Supported Java versions: LTS releases and latest
jdk: [11, 17, 21, 25]
clojure: [11, 12]
jdk: [11, 17, 21]
name: Clojure ${{ matrix.clojure }} (Java ${{ matrix.jdk }})
name: Clojure (Java ${{ matrix.jdk }})
runs-on: ubuntu-latest
@ -39,18 +36,14 @@ jobs:
uses: DeLaGuardo/setup-clojure@13.1
with:
lein: 2.9.5
clj-kondo: 2025.12.23
# Install openapi-schema-validator for openapi-tests
# Uses node version from the ubuntu-latest
- name: Install dependencies
run: npm ci
- name: Run Linter
run: ./lint.sh
- name: Run tests
run: ./scripts/test.sh clj${{ matrix.clojure }}
run: ./scripts/test.sh clj
build-cljs:
name: ClojureScript

View file

@ -12,20 +12,11 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
[breakver]: https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md
## 0.10.0 (2026-01-09)
## UNRELEASED
* Improve & document how response schemas get picked in per-content-type coercion. See [docs](./doc/ring/coercion.md#per-content-type-coercion). [#745](https://github.com/metosin/reitit/issues/745).
* **BREAKING** Remove unused `reitit.dependency` ns. [#763](https://github.com/metosin/reitit/pull/763)
* Support passing options to malli humanize. See [docs](./doc/coercion/malli_coercion.md). [#467](https://github.com/metosin/reitit/issues/467)
* **FIX** Handling of ex-type keyword hierarchies in create-exception-middleware. [#768](https://github.com/metosin/reitit/issues/768)
* Updated dependencies:
```
[metosin/malli "0.20.0"] is available but we use "0.19.2"
[com.fasterxml.jackson.core/jackson-core "2.20.1"] is available but we use "2.20.0"
[com.fasterxml.jackson.core/jackson-databind "2.20.1"] is available but we use "2.20.0"
[org.clojure/core.rrb-vector "0.2.1"] is available but we use "0.2.0"
```
## 0.9.2 (2025-10-28)

View file

@ -66,14 +66,14 @@ modules will continue to be released under `metosin` for compatibility purposes.
All main modules bundled:
```clj
[metosin/reitit "0.10.0"]
[metosin/reitit "0.9.2"]
```
Optionally, the parts can be required separately.
Reitit requires Clojure 1.11 and Java 11.
Reitit is tested with the LTS releases Java 11, 17, 21 and 25
Reitit is tested with the LTS releases Java 11, 17 and 21.
## Quick start

View file

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

View file

@ -22,7 +22,7 @@ The default exception formatting uses `reitit.exception/exception`. It produces
## Pretty Errors
```clj
[metosin/reitit-dev "0.10.0"]
[metosin/reitit-dev "0.9.2"]
```
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

@ -1,7 +1,7 @@
# Default Interceptors
```clj
[metosin/reitit-interceptors "0.10.0"]
[metosin/reitit-interceptors "0.9.2"]
```
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.10.0"]
[metosin/reitit-http "0.9.2"]
```
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.10.0"]
[metosin/reitit-pedestal "0.9.2"]
```
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.10.0"]
; [metosin/reitit "0.10.0"]
; [metosin/reitit-pedestal "0.9.2"]
; [metosin/reitit "0.9.2"]
(require '[io.pedestal.http :as server])
(require '[reitit.pedestal :as pedestal])

View file

@ -1,7 +1,7 @@
# Sieppari
```clj
[metosin/reitit-sieppari "0.10.0"]
[metosin/reitit-sieppari "0.9.2"]
```
[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.10.0"]
[metosin/reitit-interceptors "0.9.2"]
```
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

@ -1,7 +1,7 @@
# Default Middleware
```clj
[metosin/reitit-middleware "0.10.0"]
[metosin/reitit-middleware "0.9.2"]
```
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.10.0"]
[metosin/reitit-middleware "0.9.2"]
```
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,7 +5,7 @@
Read more about the [Ring Concepts](https://github.com/ring-clojure/ring/wiki/Concepts).
```clj
[metosin/reitit-ring "0.10.0"]
[metosin/reitit-ring "0.9.2"]
```
## `reitit.ring/router`

View file

@ -1,7 +1,7 @@
# Swagger Support
```
[metosin/reitit-swagger "0.10.0"]
[metosin/reitit-swagger "0.9.2"]
```
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.
@ -47,7 +47,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.10.0"]
[metosin/reitit-swagger-ui "0.9.2"]
```
`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:

View file

@ -59,7 +59,7 @@ There is an extra option in the Ring router (actually, in the underlying middlew
### Printing Request Diffs
```clj
[metosin/reitit-middleware "0.10.0"]
[metosin/reitit-middleware "0.9.2"]
```
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:

View file

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

View file

@ -10,9 +10,9 @@
[ring "1.12.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.11.132"]
[metosin/reitit "0.10.0"]
[metosin/reitit-schema "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/reitit-schema "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]
;; Just for pretty printting the match

View file

@ -10,9 +10,9 @@
[ring "1.12.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.11.132"]
[metosin/reitit "0.10.0"]
[metosin/reitit-schema "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/reitit-schema "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]
;; Just for pretty printting the match

View file

@ -10,9 +10,9 @@
[ring "1.12.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.520"]
[metosin/reitit "0.10.0"]
[metosin/reitit-spec "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/reitit-spec "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]
;; Just for pretty printting the match

View file

@ -10,9 +10,9 @@
[ring "1.12.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.11.132"]
[metosin/reitit "0.10.0"]
[metosin/reitit-malli "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/reitit-malli "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]
;; Just for pretty printting the match

View file

@ -10,9 +10,9 @@
[ring "1.12.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.11.132"]
[metosin/reitit "0.10.0"]
[metosin/reitit-spec "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/reitit-spec "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]
;; Just for pretty printting the match

View file

@ -1,7 +1,7 @@
(defproject frontend-re-frame "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.11.2"]
[org.clojure/clojurescript "1.11.132"]
[metosin/reitit "0.10.0"]
[metosin/reitit "0.9.2"]
[reagent "1.2.0"]
[re-frame "0.10.6"]
[cljsjs/react "17.0.2-0"]

View file

@ -1,5 +1,6 @@
(ns frontend-re-frame.core
(:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[reagent.dom :as rd]
[reitit.core :as r]
[reitit.coercion.spec :as rss]

View file

@ -10,9 +10,9 @@
[ring "1.12.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.11.132"]
[metosin/reitit "0.10.0"]
[metosin/reitit-spec "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/reitit-spec "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]
;; Just for pretty printting the match

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[ring/ring-jetty-adapter "1.12.1"]
[aleph "0.7.1"]
[metosin/reitit "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/ring-swagger-ui "5.9.0"]]
:repl-options {:init-ns example.server})

View file

@ -5,5 +5,5 @@
[funcool/promesa "11.0.678"]
[manifold "0.4.2"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]]
[metosin/reitit "0.9.2"]]
:repl-options {:init-ns example.server})

View file

@ -2,4 +2,4 @@
:description "Reitit coercion with vanilla ring"
:dependencies [[org.clojure/clojure "1.11.2"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]])
[metosin/reitit "0.9.2"]])

View file

@ -3,8 +3,7 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[metosin/jsonista "0.3.8"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]
[metosin/ring-swagger-ui "5.9.0"]
[org.slf4j/slf4j-simple "2.0.9"]]
[metosin/reitit "0.9.2"]
[metosin/ring-swagger-ui "5.9.0"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}})

View file

@ -12,6 +12,7 @@
[reitit.ring.middleware.multipart :as multipart]
[reitit.ring.middleware.parameters :as parameters]
[ring.adapter.jetty :as jetty]
[malli.core :as malli]
[muuntaja.core :as m]))
(def Transaction
@ -156,22 +157,22 @@
[:regex [:re "[0-9]+"]]
[:enum [:enum 1 3 5 42]]
[:multi [:multi {:dispatch :type}
["literal" [:map
[:type [:= "literal"]]
[:literal [:map
[:type [:= :literal]]
[:value [:or :int :string]]]]
["reference" [:map
[:type [:= "reference"]]
[:reference [:map
[:type [:= :reference]]
[:description :string]
[:ref :uuid]]]]]]
:example {:vector-of-tuples [["a" 1] ["b" 2]]
:regex "01234"
:enum 5
:multi {:type "literal"
:multi {:type :literal
:value "x"}}}}}
:responses {200 {:content {:default {:schema [:map-of :keyword :any]}}}}
:responses {200 {:content {:default {:schema [:map]}}}}
:handler (fn [request]
{:status 200
:body (get-in request [:parameters :request])})}}]
:body (:body request)})}}]
["/secure"
{:tags #{"secure"}

View file

@ -3,7 +3,7 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[io.pedestal/pedestal.service "0.6.3"]
[io.pedestal/pedestal.jetty "0.6.3"]
[metosin/reitit-malli "0.10.0"]
[metosin/reitit-pedestal "0.10.0"]
[metosin/reitit "0.10.0"]]
[metosin/reitit-malli "0.9.2"]
[metosin/reitit-pedestal "0.9.2"]
[metosin/reitit "0.9.2"]]
:repl-options {:init-ns server})

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[io.pedestal/pedestal.service "0.6.3"]
[io.pedestal/pedestal.jetty "0.6.3"]
[metosin/reitit-pedestal "0.10.0"]
[metosin/reitit "0.10.0"]]
[metosin/reitit-pedestal "0.9.2"]
[metosin/reitit "0.9.2"]]
:repl-options {:init-ns example.server})

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[io.pedestal/pedestal.service "0.6.3"]
[io.pedestal/pedestal.jetty "0.6.3"]
[metosin/reitit-pedestal "0.10.0"]
[metosin/reitit "0.10.0"]]
[metosin/reitit-pedestal "0.9.2"]
[metosin/reitit "0.9.2"]]
:repl-options {:init-ns example.server})

View file

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

View file

@ -2,7 +2,7 @@
:description "Reitit Ring App with Integrant"
:dependencies [[org.clojure/clojure "1.11.2"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]
[metosin/reitit "0.9.2"]
[integrant "0.8.1"]]
:main example.server
:repl-options {:init-ns user}

View file

@ -3,6 +3,6 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[metosin/jsonista "0.3.8"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]]
[metosin/reitit "0.9.2"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}})

View file

@ -3,7 +3,7 @@
:dependencies [[org.clojure/clojure "1.11.2"]
[metosin/jsonista "0.3.8"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/ring-swagger-ui "5.9.0"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}})

View file

@ -2,7 +2,7 @@
:description "Reitit Ring App with Swagger"
:dependencies [[org.clojure/clojure "1.11.2"]
[ring/ring-jetty-adapter "1.12.1"]
[metosin/reitit "0.10.0"]
[metosin/reitit "0.9.2"]
[metosin/ring-swagger-ui "5.9.0"]]
:repl-options {:init-ns example.server}
:profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}})

View file

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

View file

@ -244,7 +244,7 @@
(if coercer
(let [result (coercer query-params :default)]
(if (error? result)
(throw (ex-info "Query parameters coercion failed"
(throw (ex-info (str "Query parameters coercion failed")
result))
result))
query-params))))

View file

@ -7,10 +7,6 @@
([type data]
(throw (ex-info (str type) {:type type, :data data}))))
(defn unsupported-protocol-method!
[method]
(fail! :unsupported-protocol-method {:method method}))
(defn get-message [e]
#?(:clj (.getMessage ^Exception e) :cljs (ex-message e)))

View file

@ -1,6 +1,7 @@
(ns ^:no-doc reitit.impl
#?(:cljs (:require-macros [reitit.impl]))
(:require [clojure.string :as str]
(:require [clojure.set :as set]
[clojure.string :as str]
[meta-merge.core :as mm]
[reitit.exception :as ex]
[reitit.trie :as trie])

View file

@ -71,17 +71,11 @@
(and bracket? (= \{ c))
(let [^long to' (or (str/index-of s "}" to) (ex/fail! ::unclosed-brackets {:path s}))]
(cond
(= \* (get s (inc to)))
(if (= \* (get s (inc to)))
(recur (concat ss (-static from to) (-catch-all (inc to) to')) (long (inc to')) (long (inc to')))
(= \: (get s (inc to)))
(recur (concat ss (-static from to) (-wild (inc to) to')) (long (inc to')) (long (inc to')))
:else
(recur (concat ss (-static from to) (-wild to to')) (long (inc to')) (long (inc to')))))
(and colon? (= \: c) (not= \{ (get s (dec to))))
(and colon? (= \: c))
(let [^long to' (or (str/index-of s "/" to) (count s))]
(if (= 1 (- to' to))
(recur ss from (inc to))

View file

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

View file

@ -174,7 +174,7 @@
;; TODO: this is hack, but seems to work and is safe.
(defn source-str [[target _ file line]]
(try
(if (not= 1 line)
(if (and (not= 1 line))
(let [file-name (str/replace file #"(.*?)\.\S[^\.]+" "$1")
target-name (name target)
ns (str (subs target-name 0 (or (str/index-of target-name (str file-name "$")) 0)) file-name)]
@ -190,7 +190,7 @@
(color :title message " ")
(color :title-dark (repeat-str "-" between) " ")
(color :title source) " "
(color :title-dark "--")]))
(color :title-dark (str "--"))]))
(defn footer [{:keys [width]}]
(color :title-dark (repeat-str "-" width)))

View file

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

View file

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

View file

@ -22,12 +22,12 @@
compile (fn [[path data] opts scope]
(interceptor/compile-result [path data] opts scope))
->endpoint (fn [p d m s]
(let [d (ring/-compile-coercion d)
compiled (compile [p d] opts s)]
(-> compiled
(map->Endpoint)
(assoc :path p)
(assoc :method m))))
(let [d (ring/-compile-coercion d)]
(let [compiled (compile [p d] opts s)]
(-> compiled
(map->Endpoint)
(assoc :path p)
(assoc :method m)))))
->methods (fn [any? data]
(reduce
(fn [acc method]

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-interceptors "0.10.0"
(defproject metosin/reitit-interceptors "0.9.2"
: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.10.0"
(defproject metosin/reitit-malli "0.9.2"
: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.10.0"
(defproject metosin/reitit-middleware "0.9.2"
:description "Reitit, common middleware bundled"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -19,17 +19,17 @@
(recur (.getSuperclass sk) (conj ks sk))
ks)))
(defn- find-closest-ancestor [val m]
(or (get m val)
(some #(find-closest-ancestor % m) (parents val))))
(defn- descendants-safe [type]
(when-not (class? type) (descendants type)))
(defn- call-error-handler [handlers error request]
(let [type (:type (ex-data error))
ex-class (class error)
error-handler (or (get handlers type)
(get handlers ex-class)
(when-not (class? type)
(find-closest-ancestor type handlers))
(some
(partial get handlers)
(descendants-safe type))
(some
(partial get handlers)
(super-classes ex-class))
@ -143,9 +143,6 @@
4) Super Classes of exception
5) The ::default handler
Note! If the closest ancestor for `:type` is not unique, an
arbitrary one is picked.
Example:
(require '[reitit.ring.middleware.exception :as exception])

View file

@ -1,4 +1,4 @@
(defproject fi.metosin/reitit-openapi "0.10.0"
(defproject fi.metosin/reitit-openapi "0.9.2"
:description "Reitit: OpenAPI-support"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

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

View file

@ -2,10 +2,10 @@
(:require [io.pedestal.http :as http]
[io.pedestal.interceptor :as interceptor]
[io.pedestal.interceptor.chain :as chain]
[reitit.exception :as ex]
[reitit.http]
[reitit.interceptor])
(:import (java.lang.reflect Method)))
(:import (java.lang.reflect Method)
(reitit.interceptor Executor)))
;; TODO: variadic
(defn- arities [f]
@ -46,16 +46,12 @@
(def pedestal-executor
(reify
reitit.interceptor/Executor
Executor
(queue [_ interceptors]
(->> interceptors
(map (fn [{::interceptor/keys [handler] :as interceptor}]
(or handler interceptor)))
(keep ->interceptor)))
(execute [_ _ _]
(ex/unsupported-protocol-method! 'reitit.interceptor/execute))
(execute [_ _ _ _ _]
(ex/unsupported-protocol-method! 'reitit.interceptor/execute))
(enqueue [_ context interceptors]
(chain/enqueue context interceptors))))

View file

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

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-schema "0.10.0"
(defproject metosin/reitit-schema "0.9.2"
: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.10.0"
(defproject metosin/reitit-sieppari "0.9.2"
:description "Reitit: Sieppari Interceptors"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -1,6 +1,5 @@
(ns reitit.interceptor.sieppari
(:require [reitit.exception :as ex]
[reitit.interceptor :as interceptor]
(:require [reitit.interceptor :as interceptor]
[sieppari.core :as sieppari]
[sieppari.queue :as queue]))
@ -16,6 +15,4 @@
(execute [_ interceptors request]
(sieppari/execute interceptors request))
(execute [_ interceptors request respond raise]
(sieppari/execute interceptors request respond raise))
(enqueue [_ _ _]
(ex/unsupported-protocol-method! 'reitit.interceptor/enqueue))))
(sieppari/execute interceptors request respond raise))))

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-spec "0.10.0"
(defproject metosin/reitit-spec "0.9.2"
: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.10.0"
(defproject metosin/reitit-swagger-ui "0.9.2"
: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.10.0"
(defproject metosin/reitit-swagger "0.9.2"
: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.10.0"
(defproject metosin/reitit "0.9.2"
:description "Snappy data-driven router for Clojure(Script)"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"

View file

@ -80,15 +80,12 @@
(defrecord NoOpCoercion []
coercion/Coercion
(-get-name [_] :no-op)
(-get-options [_])
(-get-apidocs [_ _ {:keys [parameters responses] :as info}])
(-get-model-apidocs [_ _ _ _])
(-compile-model [_ model _] model)
(-open-model [_ spec] spec)
(-encode-error [_ error] error)
(-request-coercer [_ type spec] (fn [value format] value))
(-response-coercer [this spec] (coercion/request-coercer this :response spec {}))
(-query-string-coercer [_ _]))
(-response-coercer [this spec] (coercion/request-coercer this :response spec {})))
(comment
(doseq [coercion [nil (->NoOpCoercion) spec/coercion]]

View file

@ -53,27 +53,27 @@
request (json-request data)
request! (request-stream request)]]
;; # 10b
"10b"
;; 38µs (c-api 1.x)
;; 14µs (c-api 2.0.0-alpha21)
;; 6µs
;; # 100b
"100b"
;; 74µs (c-api 1.x)
;; 16µs (c-api 2.0.0-alpha21)
;; 8µs
;; # 1k
"1k"
;; 322µs (c-api 1.x)
;; 24µs (c-api 2.0.0-alpha21)
;; 16µs
;; # 10k
"10k"
;; 3300µs (c-api 1.x)
;; 120µs (c-api 2.0.0-alpha21)
;; 110µs
;; # 100k
"100k"
;; 10600µs (c-api 1.x)
;; 1100µs (c-api 2.0.0-alpha21)
;; 1100µs

View file

@ -37,40 +37,40 @@
(defn routing-test []
;; 21385 / 14337
;; "barista"
"barista"
;; 26259 / 25571
;; "choreographer"
"choreographer"
;; 24277 / 19174
;; "clutch"
"clutch"
;; 26158 / 25584
;; "connect"
"connect"
;; 24614 / 25413
;; "escort"
"escort"
;; 21979 / 18595
;; "express"
"express"
;; 23123 / 25405
;; "find-my-way"
"find-my-way"
;; 24798 / 25286
;; "http-hash"
"http-hash"
;; 24215 / 23670
;; "i40"
"i40"
;; 23561 / 26278
;; "light-router"
"light-router"
;; 28362 / 30056
;; "http-raw"
"http-raw"
;; 25310 / 25126
;; "regex"
"regex"
;; 112719 / 113959
(title "reitit")

View file

@ -1,4 +1,4 @@
(defproject metosin/reitit-parent "0.10.0"
(defproject metosin/reitit-parent "0.9.2"
:description "Snappy data-driven router for Clojure(Script)"
:url "https://github.com/metosin/reitit"
:license {:name "Eclipse Public License"
@ -18,38 +18,38 @@
:url "https://github.com/metosin/reitit"}
;; Ring 1.13.1 drops support for Java 1.8 so lets target 11
:javac-options ["-Xlint:unchecked" "-target" "11" "-source" "11"]
:managed-dependencies [[metosin/reitit "0.10.0"]
[metosin/reitit-core "0.10.0"]
[metosin/reitit-dev "0.10.0"]
[metosin/reitit-spec "0.10.0"]
[metosin/reitit-malli "0.10.0"]
[metosin/reitit-schema "0.10.0"]
[metosin/reitit-ring "0.10.0"]
[metosin/reitit-middleware "0.10.0"]
[metosin/reitit-http "0.10.0"]
[metosin/reitit-interceptors "0.10.0"]
[metosin/reitit-swagger "0.10.0"]
[fi.metosin/reitit-openapi "0.10.0"]
[metosin/reitit-swagger-ui "0.10.0"]
[metosin/reitit-frontend "0.10.0"]
[metosin/reitit-sieppari "0.10.0"]
[metosin/reitit-pedestal "0.10.0"]
:managed-dependencies [[metosin/reitit "0.9.2"]
[metosin/reitit-core "0.9.2"]
[metosin/reitit-dev "0.9.2"]
[metosin/reitit-spec "0.9.2"]
[metosin/reitit-malli "0.9.2"]
[metosin/reitit-schema "0.9.2"]
[metosin/reitit-ring "0.9.2"]
[metosin/reitit-middleware "0.9.2"]
[metosin/reitit-http "0.9.2"]
[metosin/reitit-interceptors "0.9.2"]
[metosin/reitit-swagger "0.9.2"]
[fi.metosin/reitit-openapi "0.9.2"]
[metosin/reitit-swagger-ui "0.9.2"]
[metosin/reitit-frontend "0.9.2"]
[metosin/reitit-sieppari "0.9.2"]
[metosin/reitit-pedestal "0.9.2"]
[metosin/ring-swagger-ui "5.20.0"]
[metosin/spec-tools "0.10.8"]
[metosin/schema-tools "0.13.1"]
[metosin/muuntaja "0.6.11"]
[metosin/jsonista "0.3.13"]
[metosin/sieppari "0.0.0-alpha13"]
[metosin/malli "0.20.0"]
[metosin/malli "0.19.2"]
;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111
[com.fasterxml.jackson.core/jackson-core "2.20.1"]
[com.fasterxml.jackson.core/jackson-databind "2.20.1"]
[com.fasterxml.jackson.core/jackson-core "2.20.0"]
[com.fasterxml.jackson.core/jackson-databind "2.20.0"]
[meta-merge "1.0.0"]
[fipp "0.6.29" :exclusions [org.clojure/core.rrb-vector]]
;; Deep-diff uses this version, override olders versiom from fipp.
[org.clojure/core.rrb-vector "0.2.1"]
[org.clojure/core.rrb-vector "0.2.0"]
[expound "0.9.0"]
[lambdaisland/deep-diff "0.0-47"]
[com.bhauman/spell-spec "0.1.2"]
@ -67,8 +67,7 @@
[lein-codox "0.10.8"]
[metosin/bat-test "0.4.4"]]
:profiles {:clj11 {:dependencies [[org.clojure/clojure "1.11.4"]]}
:dev {:jvm-opts ^:replace ["-server"]
:profiles {:dev {:jvm-opts ^:replace ["-server"]
;; all module sources for development
:source-paths ["modules/reitit/src"
@ -90,9 +89,9 @@
:java-source-paths ["modules/reitit-core/java-src"]
:dependencies [[org.clojure/clojure "1.12.4"]
[thheller/shadow-cljs "3.3.4"]
[org.clojure/clojurescript "1.12.134"]
:dependencies [[org.clojure/clojure "1.11.4"]
[thheller/shadow-cljs "3.2.1"]
[org.clojure/clojurescript "1.12.42"]
;; modules dependencies
[metosin/schema-tools "0.13.1"]
@ -100,7 +99,7 @@
[metosin/muuntaja "0.6.11"]
[metosin/sieppari "0.0.0-alpha13"]
[metosin/jsonista "0.3.13"]
[metosin/malli "0.20.0"]
[metosin/malli "0.19.2"]
[lambdaisland/deep-diff "0.0-47"]
[meta-merge "1.0.0"]
[com.bhauman/spell-spec "0.1.2"]
@ -113,11 +112,11 @@
[ikitommi/immutant-web "3.0.0-alpha1"]
[metosin/ring-http-response "0.9.5"]
[metosin/ring-swagger-ui "5.20.0"]
[org.clojure/tools.analyzer "1.2.1"]
[org.clojure/tools.analyzer "1.2.0"]
[criterium "0.4.6"]
[org.clojure/test.check "1.1.3"]
[org.clojure/tools.namespace "1.5.1"]
[org.clojure/test.check "1.1.1"]
[org.clojure/tools.namespace "1.5.0"]
[com.gfredericks/test.chuck "0.2.15"]
[nubank/matcher-combinators "3.9.2"]
@ -125,10 +124,10 @@
[io.pedestal/pedestal.service "0.6.4" :upgrade false]
[org.clojure/core.async "1.8.741"]
[manifold "0.5.0"]
[manifold "0.4.3"]
[funcool/promesa "11.0.678"]
[com.clojure-goes-fast/clj-async-profiler "1.7.0"]
[com.clojure-goes-fast/clj-async-profiler "1.6.2"]
[ring-cors "0.1.13"]
[com.bhauman/rebel-readline "0.1.5"]]}
@ -144,7 +143,7 @@
[io.pedestal/pedestal.jetty "0.6.4" :upgrade false]
[calfpath "0.8.1"]
[org.clojure/core.async "1.8.741"]
[manifold "0.5.0"]
[manifold "0.4.3"]
[funcool/promesa "11.0.678"]
[metosin/sieppari]
[yada "1.2.16"]
@ -160,7 +159,6 @@
:aliases {"all" ["with-profile" "dev,default"]
"perf" ["with-profile" "default,dev,perf"]
"test-clj" ["all" "do" ["bat-test"] ["check"]]
"test-clj11" ["with-profile" "dev,default,clj11" "do" ["bat-test"] ["check"]]
;; NOTE: These are deprecated, kept around for ensuring shadow-cljs works
;; the same way.
"test-browser" ["doo" "chrome-headless" "test"]

View file

@ -13,14 +13,11 @@ case $1 in
npx shadow-cljs release karma
npx karma start --single-run
;;
clj11)
lein test-clj11
;;
clj12)
clj)
lein test-clj
;;
*)
echo "Please select [clj11|clj12|cljs]"
echo "Please select [clj|cljs]"
exit 1
;;
esac

View file

@ -308,10 +308,10 @@
["/ping" {:get {:interceptors [{:enter #(a/go %)}]
:handler (fn [_] (a/go response))}}])
(ring/create-default-handler)
{:executor sieppari/executor})
respond (promise)]
(app {:request-method :get, :uri "/ping"} respond ::irrelevant)
(is (= response (deref respond 100 ::timeout))))))
{:executor sieppari/executor})]
(let [respond (promise)]
(app {:request-method :get, :uri "/ping"} respond ::irrelevant)
(is (= response (deref respond 100 ::timeout)))))))
(defrecord MyAsyncContext [])

View file

@ -11,7 +11,7 @@
(:import (clojure.lang ExceptionInfo)
(java.sql SQLException SQLWarning)))
(derive ::kukka ::kikka)
(derive ::kikka ::kukka)
(deftest exception-test
(letfn [(create
@ -147,55 +147,6 @@
(is (= status 500))
(is (= body "too many tries")))))))
(derive ::table ::object)
(derive ::living ::object)
(derive ::plant ::living)
(derive ::animal ::living)
(derive ::dog ::animal)
(derive ::cat ::animal)
(derive ::garfield ::cat)
(deftest exception-hierarchy-test
(letfn [(create [f]
(ring/ring-handler
(ring/router
[["/defaults"
{:handler f}]]
{:data {:middleware [(exception/create-exception-middleware
(merge
exception/default-handlers
{::object (constantly (http-response/bad-request "object"))
::living (constantly (http-response/bad-request "living"))
::animal (constantly (http-response/bad-request "animal"))
::cat (constantly (http-response/bad-request "cat"))}))]}})))
(call [ex-typ]
(let [app (create (fn [_] (throw (ex-info "fail" {:type ex-typ}))))]
(app {:request-method :get, :uri "/defaults"})))]
(let [{:keys [status body]} (call ::object)]
(is (= status 400))
(is (= body "object")))
(let [{:keys [status body]} (call ::table)]
(is (= status 400))
(is (= body "object")))
(let [{:keys [status body]} (call ::living)]
(is (= status 400))
(is (= body "living")))
(let [{:keys [status body]} (call ::plant)]
(is (= status 400))
(is (= body "living")))
(let [{:keys [status body]} (call ::animal)]
(is (= status 400))
(is (= body "animal")))
(let [{:keys [status body]} (call ::dog)]
(is (= status 400))
(is (= body "animal")))
(let [{:keys [status body]} (call ::cat)]
(is (= status 400))
(is (= body "cat")))
(let [{:keys [status body]} (call ::garfield)]
(is (= status 400))
(is (= body "cat")))))
(deftest spec-coercion-exception-test
(let [app (ring/ring-handler
(ring/router

View file

@ -2,6 +2,7 @@
(:require [clojure.spec.alpha :as cs]
[clojure.string :as str]
[clojure.test :refer [deftest is testing]]
[malli.core :as m]
[malli.experimental.lite :as l]
[reitit.coercion :as coercion]
[reitit.coercion.malli]
@ -9,7 +10,8 @@
[reitit.coercion.spec]
[reitit.core :as r]
[schema.core :as s]
[spec-tools.data-spec :as ds])
[spec-tools.data-spec :as ds]
[malli.transform :as mt])
#?(:clj
(:import (clojure.lang ExceptionInfo))))
@ -108,6 +110,7 @@
(testing "spec-coercion (shallow)"
(testing "succeeds"
(let [m (r/match-by-path r "/spec-shallow/1/abba")]
(def MATCH m)
(is (= {:path {:keyword :abba, :number 1}, :query nil}
(coercion/coerce! m))))
(let [m (r/match-by-path r "/spec-shallow/1/abba")]

View file

@ -1,9 +1,10 @@
(ns reitit.core-test
(:require [clojure.test :refer [are deftest is testing]]
[reitit.core :as r]
[reitit.core :as r #?@(:cljs [:refer [Router]])]
[reitit.impl :as impl])
#?(:clj
(:import (clojure.lang ExceptionInfo))))
(:import (clojure.lang ExceptionInfo)
(reitit.core Router))))
(defn- var-handler [& _]
"var-handler")
@ -260,12 +261,10 @@
(is (= #'var-handler result))))))
(testing "custom router"
(let [router (r/router
["/ping"]
{:router (fn [_ _]
#_{:clj-kondo/ignore [:missing-protocol-method]}
(reify r/Router
(router-name [_] ::custom)))})]
(let [router (r/router ["/ping"] {:router (fn [_ _]
(reify Router
(r/router-name [_]
::custom)))})]
(is (= ::custom (r/router-name router)))))
(testing "bide sample"

View file

@ -4,6 +4,7 @@
[jsonista.core :as j]
[malli.core :as mc]
[matcher-combinators.test :refer [match?]]
[matcher-combinators.matchers :as matchers]
[muuntaja.core :as m]
[reitit.coercion.malli :as malli]
[reitit.coercion.schema :as schema]

View file

@ -4,18 +4,18 @@
#?@(:clj [[muuntaja.core]
[muuntaja.middleware]
[jsonista.core :as j]
[reitit.coercion.schema :as schema]
[reitit.ring.middleware.muuntaja]
[schema.core :as s]])
[reitit.ring.middleware.muuntaja]])
[malli.core :as m]
[malli.util :as mu]
[meta-merge.core :refer [meta-merge]]
[reitit.coercion.malli :as malli]
[reitit.coercion.schema :as schema]
[reitit.coercion.spec :as spec]
[reitit.core :as r]
[reitit.ring :as ring]
[reitit.ring.spec]
[reitit.ring.coercion :as rrc]
[schema.core :as s]
[clojure.spec.alpha]
[spec-tools.data-spec :as ds])
#?(:clj

View file

@ -4,8 +4,7 @@
[reitit.core :as r]
[reitit.middleware :as middleware]
[reitit.ring :as ring]
#?(:clj [reitit.trie :as trie]
:cljs [reitit.trie :as-alias trie]))
[reitit.trie :as trie])
#?(:clj
(:import (clojure.lang ExceptionInfo))))
@ -848,22 +847,23 @@
(let [body (:body (app {:request-method :get, :uri (str "/" n)}))]
(is (= body (str n))))))))))))
(def routes (atom nil))
(declare routes)
(deftest reloading-ring-handler-test
(let [r (fn [body] {:status 200, :body body})]
(reset! routes ["/" (constantly (r "1"))]) ;; initial value
(let [create-handler (fn [] (ring/ring-handler (ring/router @routes)))]
(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})))
(reset! routes ["/" (constantly (r "2"))]) ;; redefine
(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})))
(reset! routes ["/" (constantly (r "3"))]) ;; redefine again
(def routes ["/" (constantly (r "3"))]) ;; redefine again
(is (= (r "3") (app {:uri "/", :request-method :get}))))))))
(defrecord FooTest [a b])

View file

@ -41,9 +41,7 @@
"/olipa/:kerran/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"]
"/olipa/{kerran}/avaruus", ["/olipa/{kerran}/avaruus"]
"/olipa/{:kerran}/avaruus", ["/olipa/{:kerran}/avaruus"]
"/olipa/{a.b/c}/avaruus", ["/olipa/{a.b/c}/avaruus"]
"/olipa/{:a.b/c}/avaruus", ["/olipa/{:a.b/c}/avaruus"]
"/olipa/kerran/*avaruus", ["/olipa/kerran/" (trie/->CatchAll :avaruus)]
"/olipa/kerran/{*avaruus}", ["/olipa/kerran/{" (trie/->CatchAll (keyword "avaruus}"))]
"/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/{" (trie/->CatchAll (keyword "valtavan.suuri/avaruus}"))])))
@ -55,9 +53,7 @@
"/olipa/:kerran/avaruus", ["/olipa/:kerran/avaruus"]
"/olipa/{kerran}/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"]
"/olipa/{:kerran}/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"]
"/olipa/{a.b/c}/avaruus", ["/olipa/" (trie/->Wild :a.b/c) "/avaruus"]
"/olipa/{:a.b/c}/avaruus", ["/olipa/" (trie/->Wild :a.b/c) "/avaruus"]
"/olipa/kerran/*avaruus", ["/olipa/kerran/*avaruus"]
"/olipa/kerran/{*avaruus}", ["/olipa/kerran/" (trie/->CatchAll :avaruus)]
"/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/" (trie/->CatchAll :valtavan.suuri/avaruus)])))
@ -69,9 +65,7 @@
"/olipa/:kerran/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"]
"/olipa/{kerran}/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"]
"/olipa/{:kerran}/avaruus", ["/olipa/" (trie/->Wild :kerran) "/avaruus"]
"/olipa/{a.b/c}/avaruus", ["/olipa/" (trie/->Wild :a.b/c) "/avaruus"]
"/olipa/{:a.b/c}/avaruus", ["/olipa/" (trie/->Wild :a.b/c) "/avaruus"]
"/olipa/kerran/*avaruus", ["/olipa/kerran/" (trie/->CatchAll :avaruus)]
"/olipa/kerran/{*avaruus}", ["/olipa/kerran/" (trie/->CatchAll :avaruus)]
"/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/" (trie/->CatchAll :valtavan.suuri/avaruus)])))
@ -83,9 +77,7 @@
"/olipa/:kerran/avaruus", ["/olipa/:kerran/avaruus"]
"/olipa/{kerran}/avaruus", ["/olipa/{kerran}/avaruus"]
"/olipa/{:kerran}/avaruus", ["/olipa/{:kerran}/avaruus"]
"/olipa/{a.b/c}/avaruus", ["/olipa/{a.b/c}/avaruus"]
"/olipa/{:a.b/c}/avaruus", ["/olipa/{:a.b/c}/avaruus"]
"/olipa/kerran/*avaruus", ["/olipa/kerran/*avaruus"]
"/olipa/kerran/{*avaruus}", ["/olipa/kerran/{*avaruus}"]
"/olipa/kerran/{*valtavan.suuri/avaruus}", ["/olipa/kerran/{*valtavan.suuri/avaruus}"]))))