diff --git a/CHANGELOG.md b/CHANGELOG.md index 329199c4..60289cb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,25 @@ We use [Break Versioning][breakver]. The version numbers follow a `.` is present, `:responses :default` is not used, even if `:responses ` defines no schema. + * Should not break normal use, but might cause surprises related to defaults applying/not applying +* **NOTE** This release depends on malli 0.18.0, which changes the format of OpenAPI & Swagger named schemas from `foo.bar/quux` to `foo.bar.quux` ## 0.8.0 (2025-03-28) diff --git a/README.md b/README.md index 9906134d..3ee8d384 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# reitit +# reitit [![Build Status](https://github.com/metosin/reitit/actions/workflows/testsuite.yml/badge.svg)](https://github.com/metosin/reitit/actions) [![cljdoc badge](https://cljdoc.org/badge/metosin/reitit)](https://cljdoc.org/d/metosin/reitit/) @@ -54,7 +54,7 @@ There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians * `metosin/reitit-sieppari` support for [Sieppari](https://github.com/metosin/sieppari) * `metosin/reitit-dev` - development utilities -... * This is not a typo; the new `reitit-openapi` was released under the new, verified `fi.metosin` group. Existing +... * This is not a typo; the new `reitit-openapi` was released under the new, verified `fi.metosin` group. Existing modules will continue to be released under `metosin` for compatibility purposes. ## Extra modules @@ -66,7 +66,7 @@ modules will continue to be released under `metosin` for compatibility purposes. All main modules bundled: ```clj -[metosin/reitit "0.8.0"] +[metosin/reitit "0.9.1"] ``` Optionally, the parts can be required separately. @@ -109,6 +109,7 @@ A Ring routing app with input & output coercion using [data-specs](https://githu (require '[reitit.ring :as ring]) (require '[reitit.coercion.spec]) (require '[reitit.ring.coercion :as rrc]) +(require '[reitit.ring.middleware.exception :as exception]) (require '[reitit.ring.middleware.muuntaja :as muuntaja]) (require '[reitit.ring.middleware.parameters :as parameters]) @@ -124,39 +125,45 @@ A Ring routing app with input & output coercion using [data-specs](https://githu ;; router data affecting all routes {:data {:coercion reitit.coercion.spec/coercion :muuntaja m/instance - :middleware [parameters/parameters-middleware + :middleware [parameters/parameters-middleware ; decoding query & form params + muuntaja/format-middleware ; content negotiation + exception/exception-middleware ; converting exceptions to HTTP responses rrc/coerce-request-middleware - muuntaja/format-response-middleware rrc/coerce-response-middleware]}}))) ``` Valid request: ```clj -(app {:request-method :get - :uri "/api/math" - :query-params {:x "1", :y "2"}}) +(-> (app {:request-method :get + :uri "/api/math" + :query-params {:x "1", :y "2"}}) + (update :body slurp)) ; {:status 200 -; :body {:total 3}} +; :body "{\"total\":3}" +; :headers {"Content-Type" "application/json; charset=utf-8"}} ``` Invalid request: ```clj -(app {:request-method :get - :uri "/api/math" - :query-params {:x "1", :y "a"}}) -;{:status 400, -; :body {:type :reitit.coercion/request-coercion, -; :coercion :spec, -; :spec "(spec-tools.core/spec {:spec (clojure.spec.alpha/keys :req-un [:$spec20745/x :$spec20745/y]), :type :map, :keys #{:y :x}, :keys/req #{:y :x}})", -; :problems [{:path [:y], -; :pred "clojure.core/int?", -; :val "a", -; :via [:$spec20745/y], -; :in [:y]}], -; :value {:x "1", :y "a"}, -; :in [:request :query-params]}} +(-> (app {:request-method :get + :uri "/api/math" + :query-params {:x "1", :y "a"}}) + (update :body jsonista.core/read-value)) +; {:status 400 +; :headers {"Content-Type" "application/json; charset=utf-8"} +; :body {"spec" "(spec-tools.core/spec {:spec (clojure.spec.alpha/keys :req-un [:spec$8974/x :spec$8974/y]), :type :map, :leaf? false})" +; "value" {"x" "1" +; "y" "a"} +; "problems" [{"via" ["spec$8974/y"] +; "path" ["y"] +; "pred" "clojure.core/int?" +; "in" ["y"] +; "val" "a"}] +; "type" "reitit.coercion/request-coercion" +; "coercion" "spec" +; "in" ["request" "query-params"]}} ``` ## More examples diff --git a/doc/README.md b/doc/README.md index 2b5411dc..2623fe9b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -41,7 +41,7 @@ There is [#reitit](https://clojurians.slack.com/messages/reitit/) in [Clojurians All bundled: ```clj -[metosin/reitit "0.8.0"] +[metosin/reitit "0.9.1"] ``` Optionally, the parts can be required separately. diff --git a/doc/basics/error_messages.md b/doc/basics/error_messages.md index eab5737c..fcef1cd4 100644 --- a/doc/basics/error_messages.md +++ b/doc/basics/error_messages.md @@ -22,7 +22,7 @@ The default exception formatting uses `reitit.exception/exception`. It produces ## Pretty Errors ```clj -[metosin/reitit-dev "0.8.0"] +[metosin/reitit-dev "0.9.1"] ``` 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. diff --git a/doc/development.md b/doc/development.md index 1f418649..dbfd028f 100644 --- a/doc/development.md +++ b/doc/development.md @@ -32,10 +32,6 @@ We use [Break Versioning][breakver]. Remember our promise: patch-level bumps nev [breakver]: https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md ```bash -# Check that you're using Java 8! Making the release with a newer Java version -# means that it is broken when used with Java 8. -java -version - # new version ./scripts/set-version "1.0.0" diff --git a/doc/http/default_interceptors.md b/doc/http/default_interceptors.md index 5977912d..dc8fcb25 100644 --- a/doc/http/default_interceptors.md +++ b/doc/http/default_interceptors.md @@ -1,7 +1,7 @@ # Default Interceptors ```clj -[metosin/reitit-interceptors "0.8.0"] +[metosin/reitit-interceptors "0.9.1"] ``` Just like the [ring default middleware](../ring/default_middleware.md), but for interceptors. diff --git a/doc/http/interceptors.md b/doc/http/interceptors.md index 02075251..d06fe7c4 100644 --- a/doc/http/interceptors.md +++ b/doc/http/interceptors.md @@ -5,7 +5,7 @@ Reitit has also support for [interceptors](http://pedestal.io/reference/intercep ## Reitit-http ```clj -[metosin/reitit-http "0.8.0"] +[metosin/reitit-http "0.9.1"] ``` 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. diff --git a/doc/http/pedestal.md b/doc/http/pedestal.md index 967594b3..4334ca38 100644 --- a/doc/http/pedestal.md +++ b/doc/http/pedestal.md @@ -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.8.0"] +[metosin/reitit-pedestal "0.9.1"] ``` 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.8.0"] -; [metosin/reitit "0.8.0"] +; [metosin/reitit-pedestal "0.9.1"] +; [metosin/reitit "0.9.1"] (require '[io.pedestal.http :as server]) (require '[reitit.pedestal :as pedestal]) diff --git a/doc/http/sieppari.md b/doc/http/sieppari.md index 590abf3d..929f75f2 100644 --- a/doc/http/sieppari.md +++ b/doc/http/sieppari.md @@ -1,7 +1,7 @@ # Sieppari ```clj -[metosin/reitit-sieppari "0.8.0"] +[metosin/reitit-sieppari "0.9.1"] ``` [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). diff --git a/doc/http/transforming_interceptor_chain.md b/doc/http/transforming_interceptor_chain.md index 6043170d..895e8aca 100644 --- a/doc/http/transforming_interceptor_chain.md +++ b/doc/http/transforming_interceptor_chain.md @@ -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.8.0"] +[metosin/reitit-interceptors "0.9.1"] ``` 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: diff --git a/doc/ring/data_driven_middleware.md b/doc/ring/data_driven_middleware.md index 2d310ff4..b86a23d9 100644 --- a/doc/ring/data_driven_middleware.md +++ b/doc/ring/data_driven_middleware.md @@ -2,6 +2,8 @@ Ring [defines middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware) as a function of type `handler & args => request => response`. It is relatively easy to understand and allows for good performance. A downside is that the middleware chain is just a opaque function, making things like debugging and composition hard. It is too easy to apply the middlewares in wrong order. +For the basics of reitit middleware, [read this first](ring.md#middleware). + Reitit defines middleware as data: 1. A middleware can be defined as first-class data entries diff --git a/doc/ring/default_middleware.md b/doc/ring/default_middleware.md index c311d8e7..bacc9f90 100644 --- a/doc/ring/default_middleware.md +++ b/doc/ring/default_middleware.md @@ -1,7 +1,7 @@ # Default Middleware ```clj -[metosin/reitit-middleware "0.8.0"] +[metosin/reitit-middleware "0.9.1"] ``` 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. @@ -17,8 +17,6 @@ Any Ring middleware can be used with `reitit-ring`, but using data-driven middle `reitit.ring.middleware.parameters/parameters-middleware` to capture query- and form-params. Wraps `ring.middleware.params/wrap-params`. -**NOTE**: This middleware will be factored into two parts: a query-parameters middleware and a Muuntaja format responsible for the the `application/x-www-form-urlencoded` body format. cf. https://github.com/metosin/reitit/issues/134 - ## Exception Handling See [Exception Handling with Ring](exceptions.md). diff --git a/doc/ring/exceptions.md b/doc/ring/exceptions.md index 0c22290e..e3b4d305 100644 --- a/doc/ring/exceptions.md +++ b/doc/ring/exceptions.md @@ -1,7 +1,7 @@ # Exception Handling with Ring ```clj -[metosin/reitit-middleware "0.8.0"] +[metosin/reitit-middleware "0.9.1"] ``` 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. diff --git a/doc/ring/ring.md b/doc/ring/ring.md index 553af17c..e9a3a175 100644 --- a/doc/ring/ring.md +++ b/doc/ring/ring.md @@ -5,7 +5,7 @@ Read more about the [Ring Concepts](https://github.com/ring-clojure/ring/wiki/Concepts). ```clj -[metosin/reitit-ring "0.8.0"] +[metosin/reitit-ring "0.9.1"] ``` ## `reitit.ring/router` @@ -141,7 +141,7 @@ Name-based reverse routing: # Middleware -Middleware can be mounted using a `:middleware` key - either to top-level or under request method submap. Its value should be a vector of `reitit.middleware/IntoMiddleware` values. These include: +Middleware can be mounted using a `:middleware` key in [Route Data](../basics/route_data.md) - either to top-level or under request method submap. Its value should be a vector of `reitit.middleware/IntoMiddleware` values. These include: 1. normal ring middleware function `handler -> request -> response` 2. vector of middleware function `[handler args*] -> request -> response` and it's arguments @@ -194,11 +194,56 @@ Top-level middleware, applied before any routing is done: (def app (ring/ring-handler (ring/router - ["/api" {:middleware [[mw :api]]} + ["/api" {:middleware [[wrap :api]]} ["/get" {:get handler}]]) nil - {:middleware [[mw :top]]})) + {:middleware [[wrap :top]]})) (app {:request-method :get, :uri "/api/get"}) ; {:status 200, :body [:top :api :ok]} ``` + +Same middleware for all routes, using [top-level route data](route_data.md#top-level-route-data): + +```clj +(def app + (ring/ring-handler + (ring/router + ["/api" + ["/get" {:get handler + :middleware [[wrap :specific]]}]] + {:data {:middleware [[wrap :generic]]}}))) + +(app {:request-method :get, :uri "/api/get"}) +; {:status 200, :body [:generic :specific :handler]} +``` + +## Execution order + +Here's a full example that shows the execution order of the middleware +using all of the above techniques: + + +```clj +(def app + (ring/ring-handler + (ring/router + ["/api" {:middleware [[wrap :3-parent]]} + ["/get" {:get handler + :middleware [[wrap :4-route]]}]] + {:data {:middleware [[wrap :2-top-level-route-data]]}}) + nil + {:middleware [[wrap :1-top]]})) + +(app {:request-method :get, :uri "/api/get"}) +; {:status 200, :body [:1-top :2-top-level-route-data :3-parent :4-route :handler]} +``` + +## Which method should I use for defining middleware? + +- If you have middleware that you want to apply to the default handler (second argument of `ring/ring-handler`), use _top-level middleware_ +- If you have a generic middleware, that doesn't depend on the route, use _top-level middleware_ or _top-level route data_ + - If you are using top-level route data anyway for some other reasons, it might be clearest to have all the middleware there. This is what most of the reitit examples do. +- If you want to apply a middleware to only a couple of routes, use _nested middleware_ (ie. _route data_) +- If you want a middleware to apply to all routes, but use route-specific data, you need _top-level route data_ combined with [Compiling Middleware](compiling_middleware.md) + - This is what many reitit features like [Ring Coercion](coercion.md) do. Check the examples & docs for the reitit features you want to use! diff --git a/doc/ring/swagger.md b/doc/ring/swagger.md index b4271692..965c6a4b 100644 --- a/doc/ring/swagger.md +++ b/doc/ring/swagger.md @@ -1,7 +1,7 @@ # Swagger Support ``` -[metosin/reitit-swagger "0.8.0"] +[metosin/reitit-swagger "0.9.1"] ``` 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.8.0"] +[metosin/reitit-swagger-ui "0.9.1"] ``` `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: diff --git a/doc/ring/transforming_middleware_chain.md b/doc/ring/transforming_middleware_chain.md index c6f7ea73..9a61c0e2 100644 --- a/doc/ring/transforming_middleware_chain.md +++ b/doc/ring/transforming_middleware_chain.md @@ -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.8.0"] +[metosin/reitit-middleware "0.9.1"] ``` 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: diff --git a/examples/buddy-auth/project.clj b/examples/buddy-auth/project.clj index 6c8a69c8..04395a66 100644 --- a/examples/buddy-auth/project.clj +++ b/examples/buddy-auth/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [buddy "2.0.0"]] :repl-options {:init-ns example.server}) diff --git a/examples/frontend-auth/project.clj b/examples/frontend-auth/project.clj index 1c4e5994..a655f52d 100644 --- a/examples/frontend-auth/project.clj +++ b/examples/frontend-auth/project.clj @@ -10,9 +10,9 @@ [ring "1.12.1"] [hiccup "1.0.5"] [org.clojure/clojurescript "1.11.132"] - [metosin/reitit "0.8.0"] - [metosin/reitit-schema "0.8.0"] - [metosin/reitit-frontend "0.8.0"] + [metosin/reitit "0.9.1"] + [metosin/reitit-schema "0.9.1"] + [metosin/reitit-frontend "0.9.1"] [cljsjs/react "17.0.2-0"] [cljsjs/react-dom "17.0.2-0"] ;; Just for pretty printting the match diff --git a/examples/frontend-controllers/project.clj b/examples/frontend-controllers/project.clj index 34ad198d..6f37c56d 100644 --- a/examples/frontend-controllers/project.clj +++ b/examples/frontend-controllers/project.clj @@ -10,9 +10,9 @@ [ring "1.12.1"] [hiccup "1.0.5"] [org.clojure/clojurescript "1.11.132"] - [metosin/reitit "0.8.0"] - [metosin/reitit-schema "0.8.0"] - [metosin/reitit-frontend "0.8.0"] + [metosin/reitit "0.9.1"] + [metosin/reitit-schema "0.9.1"] + [metosin/reitit-frontend "0.9.1"] [cljsjs/react "17.0.2-0"] [cljsjs/react-dom "17.0.2-0"] ;; Just for pretty printting the match diff --git a/examples/frontend-links/project.clj b/examples/frontend-links/project.clj index ae2ff62a..b0872b3e 100644 --- a/examples/frontend-links/project.clj +++ b/examples/frontend-links/project.clj @@ -10,9 +10,9 @@ [ring "1.12.1"] [hiccup "1.0.5"] [org.clojure/clojurescript "1.10.520"] - [metosin/reitit "0.8.0"] - [metosin/reitit-spec "0.8.0"] - [metosin/reitit-frontend "0.8.0"] + [metosin/reitit "0.9.1"] + [metosin/reitit-spec "0.9.1"] + [metosin/reitit-frontend "0.9.1"] [cljsjs/react "17.0.2-0"] [cljsjs/react-dom "17.0.2-0"] ;; Just for pretty printting the match diff --git a/examples/frontend-malli/project.clj b/examples/frontend-malli/project.clj index d455f211..0718dedb 100644 --- a/examples/frontend-malli/project.clj +++ b/examples/frontend-malli/project.clj @@ -10,9 +10,9 @@ [ring "1.12.1"] [hiccup "1.0.5"] [org.clojure/clojurescript "1.11.132"] - [metosin/reitit "0.8.0"] - [metosin/reitit-malli "0.8.0"] - [metosin/reitit-frontend "0.8.0"] + [metosin/reitit "0.9.1"] + [metosin/reitit-malli "0.9.1"] + [metosin/reitit-frontend "0.9.1"] [cljsjs/react "17.0.2-0"] [cljsjs/react-dom "17.0.2-0"] ;; Just for pretty printting the match diff --git a/examples/frontend-prompt/project.clj b/examples/frontend-prompt/project.clj index 3253e288..6ddd3f3f 100644 --- a/examples/frontend-prompt/project.clj +++ b/examples/frontend-prompt/project.clj @@ -10,9 +10,9 @@ [ring "1.12.1"] [hiccup "1.0.5"] [org.clojure/clojurescript "1.11.132"] - [metosin/reitit "0.8.0"] - [metosin/reitit-spec "0.8.0"] - [metosin/reitit-frontend "0.8.0"] + [metosin/reitit "0.9.1"] + [metosin/reitit-spec "0.9.1"] + [metosin/reitit-frontend "0.9.1"] [cljsjs/react "17.0.2-0"] [cljsjs/react-dom "17.0.2-0"] ;; Just for pretty printting the match diff --git a/examples/frontend-re-frame/project.clj b/examples/frontend-re-frame/project.clj index 46060d54..d935c2ed 100644 --- a/examples/frontend-re-frame/project.clj +++ b/examples/frontend-re-frame/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [reagent "1.2.0"] [re-frame "0.10.6"] [cljsjs/react "17.0.2-0"] diff --git a/examples/frontend/project.clj b/examples/frontend/project.clj index 67e86126..9351fc29 100644 --- a/examples/frontend/project.clj +++ b/examples/frontend/project.clj @@ -10,9 +10,9 @@ [ring "1.12.1"] [hiccup "1.0.5"] [org.clojure/clojurescript "1.11.132"] - [metosin/reitit "0.8.0"] - [metosin/reitit-spec "0.8.0"] - [metosin/reitit-frontend "0.8.0"] + [metosin/reitit "0.9.1"] + [metosin/reitit-spec "0.9.1"] + [metosin/reitit-frontend "0.9.1"] [cljsjs/react "17.0.2-0"] [cljsjs/react-dom "17.0.2-0"] ;; Just for pretty printting the match diff --git a/examples/http-swagger/project.clj b/examples/http-swagger/project.clj index 3192b595..a55f7234 100644 --- a/examples/http-swagger/project.clj +++ b/examples/http-swagger/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [metosin/ring-swagger-ui "5.9.0"]] :repl-options {:init-ns example.server}) diff --git a/examples/http/project.clj b/examples/http/project.clj index a355907f..5c00013b 100644 --- a/examples/http/project.clj +++ b/examples/http/project.clj @@ -5,5 +5,5 @@ [funcool/promesa "11.0.678"] [manifold "0.4.2"] [ring/ring-jetty-adapter "1.12.1"] - [metosin/reitit "0.8.0"]] + [metosin/reitit "0.9.1"]] :repl-options {:init-ns example.server}) diff --git a/examples/just-coercion-with-ring/project.clj b/examples/just-coercion-with-ring/project.clj index a07c2ba5..b505c209 100644 --- a/examples/just-coercion-with-ring/project.clj +++ b/examples/just-coercion-with-ring/project.clj @@ -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.8.0"]]) + [metosin/reitit "0.9.1"]]) diff --git a/examples/openapi/project.clj b/examples/openapi/project.clj index 083feaf7..fdae4232 100644 --- a/examples/openapi/project.clj +++ b/examples/openapi/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [metosin/ring-swagger-ui "5.9.0"]] :repl-options {:init-ns example.server} :profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}}) diff --git a/examples/openapi/src/example/server.clj b/examples/openapi/src/example/server.clj index 618a469a..b2419cf0 100644 --- a/examples/openapi/src/example/server.clj +++ b/examples/openapi/src/example/server.clj @@ -137,6 +137,32 @@ {:from "0003" :amount -6.5}]}})}}] + ["/complex" + {:post {:summary "Complex schema with :multi, :enum, :tuple etc." + :request {:content + {:default + {:schema [:map + [:vector-of-tuples [:vector [:tuple :string :int]]] + [:regex [:re "[0-9]+"]] + [:enum [:enum 1 3 5 42]] + [:multi [:multi {:dispatch :type} + [:literal [:map + [:type [:= :literal]] + [:value [:or :int :string]]]] + [:reference [:map + [:type [:= :reference]] + [:description :string] + [:ref :uuid]]]]]] + :example {:vector-of-tuples [["a" 1] ["b" 2]] + :regex "01234" + :enum 5 + :multi {:type :literal + :value "x"}}}}} + :responses {200 {:content {:default {:schema [:map]}}}} + :handler (fn [request] + {:status 200 + :body (:body request)})}}] + ["/secure" {:tags #{"secure"} :openapi {:security [{"auth" []}]}} diff --git a/examples/pedestal-malli-swagger/project.clj b/examples/pedestal-malli-swagger/project.clj index c71b15db..c2ffe897 100644 --- a/examples/pedestal-malli-swagger/project.clj +++ b/examples/pedestal-malli-swagger/project.clj @@ -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.8.0"] - [metosin/reitit-pedestal "0.8.0"] - [metosin/reitit "0.8.0"]] + [metosin/reitit-malli "0.9.1"] + [metosin/reitit-pedestal "0.9.1"] + [metosin/reitit "0.9.1"]] :repl-options {:init-ns server}) diff --git a/examples/pedestal-swagger/project.clj b/examples/pedestal-swagger/project.clj index 2c2556d4..b70b1391 100644 --- a/examples/pedestal-swagger/project.clj +++ b/examples/pedestal-swagger/project.clj @@ -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.8.0"] - [metosin/reitit "0.8.0"]] + [metosin/reitit-pedestal "0.9.1"] + [metosin/reitit "0.9.1"]] :repl-options {:init-ns example.server}) diff --git a/examples/pedestal/project.clj b/examples/pedestal/project.clj index f1f1e194..e0bc7314 100644 --- a/examples/pedestal/project.clj +++ b/examples/pedestal/project.clj @@ -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.8.0"] - [metosin/reitit "0.8.0"]] + [metosin/reitit-pedestal "0.9.1"] + [metosin/reitit "0.9.1"]] :repl-options {:init-ns example.server}) diff --git a/examples/ring-example/project.clj b/examples/ring-example/project.clj index 239080e7..8db86735 100644 --- a/examples/ring-example/project.clj +++ b/examples/ring-example/project.clj @@ -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.8.0"]] + [metosin/reitit "0.9.1"]] :repl-options {:init-ns example.server}) diff --git a/examples/ring-integrant/project.clj b/examples/ring-integrant/project.clj index aaefbda6..aab61c20 100644 --- a/examples/ring-integrant/project.clj +++ b/examples/ring-integrant/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [integrant "0.8.1"]] :main example.server :repl-options {:init-ns user} diff --git a/examples/ring-malli-lite-swagger/project.clj b/examples/ring-malli-lite-swagger/project.clj index 94038052..a0f8355c 100644 --- a/examples/ring-malli-lite-swagger/project.clj +++ b/examples/ring-malli-lite-swagger/project.clj @@ -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.8.0"]] + [metosin/reitit "0.9.1"]] :repl-options {:init-ns example.server} :profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}}) diff --git a/examples/ring-malli-swagger/project.clj b/examples/ring-malli-swagger/project.clj index 33f74cd1..7a4f2231 100644 --- a/examples/ring-malli-swagger/project.clj +++ b/examples/ring-malli-swagger/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [metosin/ring-swagger-ui "5.9.0"]] :repl-options {:init-ns example.server} :profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}}) diff --git a/examples/ring-spec-swagger/project.clj b/examples/ring-spec-swagger/project.clj index ffd29f2e..f59de541 100644 --- a/examples/ring-spec-swagger/project.clj +++ b/examples/ring-spec-swagger/project.clj @@ -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.8.0"] + [metosin/reitit "0.9.1"] [metosin/ring-swagger-ui "5.9.0"]] :repl-options {:init-ns example.server} :profiles {:dev {:dependencies [[ring/ring-mock "0.4.0"]]}}) diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index 4aed99a1..c6f2629a 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-core "0.8.0" +(defproject metosin/reitit-core "0.9.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 7a3d4458..147b652c 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -178,8 +178,9 @@ (let [format->coercer (or (status->format->coercer (:status response)) (status->format->coercer :default)) format (extract-response-format request response) - coercer (or (format->coercer format) - (format->coercer :default))] + coercer (when format->coercer + (or (format->coercer format) + (format->coercer :default)))] (if-not coercer response (let [value (:body response) diff --git a/modules/reitit-core/src/reitit/spec.cljc b/modules/reitit-core/src/reitit/spec.cljc index b2608514..6c51759c 100644 --- a/modules/reitit-core/src/reitit/spec.cljc +++ b/modules/reitit-core/src/reitit/spec.cljc @@ -37,8 +37,11 @@ ;; Default data ;; +(defn -multi? [x] + (instance? #?(:clj clojure.lang.MultiFn :cljs cljs.core.MultiFn) x)) + (s/def ::name keyword?) -(s/def ::handler (s/or :fn fn? :var var?)) +(s/def ::handler (s/or :fn fn? :var var? :multi -multi?)) (s/def ::no-doc boolean?) (s/def ::conflicting boolean?) (s/def ::default-data diff --git a/modules/reitit-dev/project.clj b/modules/reitit-dev/project.clj index e190124d..1c451211 100644 --- a/modules/reitit-dev/project.clj +++ b/modules/reitit-dev/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-dev "0.8.0" +(defproject metosin/reitit-dev "0.9.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-frontend/project.clj b/modules/reitit-frontend/project.clj index e8096309..2ec7de9b 100644 --- a/modules/reitit-frontend/project.clj +++ b/modules/reitit-frontend/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-frontend "0.8.0" +(defproject metosin/reitit-frontend "0.9.1" :description "Reitit: Clojurescript frontend routing core" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-http/project.clj b/modules/reitit-http/project.clj index 79ab8e2a..4d1294d8 100644 --- a/modules/reitit-http/project.clj +++ b/modules/reitit-http/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-http "0.8.0" +(defproject metosin/reitit-http "0.9.1" :description "Reitit: HTTP routing with interceptors" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-interceptors/project.clj b/modules/reitit-interceptors/project.clj index 42db1275..01e3085e 100644 --- a/modules/reitit-interceptors/project.clj +++ b/modules/reitit-interceptors/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-interceptors "0.8.0" +(defproject metosin/reitit-interceptors "0.9.1" :description "Reitit, common interceptors bundled" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-malli/project.clj b/modules/reitit-malli/project.clj index 5c749843..f31938a7 100644 --- a/modules/reitit-malli/project.clj +++ b/modules/reitit-malli/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-malli "0.8.0" +(defproject metosin/reitit-malli "0.9.1" :description "Reitit: Malli coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-middleware/project.clj b/modules/reitit-middleware/project.clj index 69f6f7a7..8c0bbcf0 100644 --- a/modules/reitit-middleware/project.clj +++ b/modules/reitit-middleware/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-middleware "0.8.0" +(defproject metosin/reitit-middleware "0.9.1" :description "Reitit, common middleware bundled" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-openapi/project.clj b/modules/reitit-openapi/project.clj index c130fbf8..17521d7a 100644 --- a/modules/reitit-openapi/project.clj +++ b/modules/reitit-openapi/project.clj @@ -1,4 +1,4 @@ -(defproject fi.metosin/reitit-openapi "0.8.0" +(defproject fi.metosin/reitit-openapi "0.9.1" :description "Reitit: OpenAPI-support" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-openapi/src/reitit/openapi.clj b/modules/reitit-openapi/src/reitit/openapi.clj index aade0b60..5a4ac9d8 100644 --- a/modules/reitit-openapi/src/reitit/openapi.clj +++ b/modules/reitit-openapi/src/reitit/openapi.clj @@ -206,20 +206,23 @@ accept-route (fn [route] (-> route second :openapi :id (or ::default) (trie/into-set) (set/intersection ids) seq)) definitions (volatile! {}) - transform-endpoint (fn [[method {{:keys [coercion no-doc openapi] :as data} :data - middleware :middleware - interceptors :interceptors}]] - (if (and data (not no-doc)) - [method - (meta-merge - (apply meta-merge (keep (comp :openapi :data) middleware)) - (apply meta-merge (keep (comp :openapi :data) interceptors)) - (if coercion - (-get-apidocs-openapi coercion data definitions)) - (select-keys data [:tags :summary :description]) - (strip-top-level-keys openapi))])) + transform-endpoint (fn [path [method {{:keys [coercion no-doc openapi] :as data} :data + middleware :middleware + interceptors :interceptors}]] + (try + (if (and data (not no-doc)) + [method + (meta-merge + (apply meta-merge (keep (comp :openapi :data) middleware)) + (apply meta-merge (keep (comp :openapi :data) interceptors)) + (if coercion + (-get-apidocs-openapi coercion data definitions)) + (select-keys data [:tags :summary :description]) + (strip-top-level-keys openapi))]) + (catch Throwable t + (throw (ex-info "While building openapi docs" {:path path :method method} t))))) transform-path (fn [[p _ c]] - (if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))] + (if-let [endpoint (some->> c (keep (partial transform-endpoint p)) (seq) (into {}))] [(openapi-path p (r/options router)) endpoint])) map-in-order #(->> % (apply concat) (apply array-map)) paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) map-in-order)] diff --git a/modules/reitit-pedestal/project.clj b/modules/reitit-pedestal/project.clj index f6b9bf27..7d5b3abc 100644 --- a/modules/reitit-pedestal/project.clj +++ b/modules/reitit-pedestal/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-pedestal "0.8.0" +(defproject metosin/reitit-pedestal "0.9.1" :description "Reitit + Pedestal Integration" :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 29e28279..0cc9d24b 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-ring "0.8.0" +(defproject metosin/reitit-ring "0.9.1" :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 abe88a88..90b1370d 100644 --- a/modules/reitit-schema/project.clj +++ b/modules/reitit-schema/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-schema "0.8.0" +(defproject metosin/reitit-schema "0.9.1" :description "Reitit: Plumatic Schema coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-sieppari/project.clj b/modules/reitit-sieppari/project.clj index e90ccc30..1cb1f02a 100644 --- a/modules/reitit-sieppari/project.clj +++ b/modules/reitit-sieppari/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-sieppari "0.8.0" +(defproject metosin/reitit-sieppari "0.9.1" :description "Reitit: Sieppari Interceptors" :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 6fac837a..a1c2bde9 100644 --- a/modules/reitit-spec/project.clj +++ b/modules/reitit-spec/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-spec "0.8.0" +(defproject metosin/reitit-spec "0.9.1" :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 785945b2..058f542f 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.8.0" +(defproject metosin/reitit-swagger-ui "0.9.1" :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 bc0c9d68..25362782 100644 --- a/modules/reitit-swagger/project.clj +++ b/modules/reitit-swagger/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-swagger "0.8.0" +(defproject metosin/reitit-swagger "0.9.1" :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 c5245813..0f4a89dd 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit "0.8.0" +(defproject metosin/reitit "0.9.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/package-lock.json b/package-lock.json index c1d46edd..86c75ec1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "shadow-cljs": "^2.28.22" }, "devDependencies": { - "@seriousme/openapi-schema-validator": "^2.3.1", + "@seriousme/openapi-schema-validator": "^2.4.0", "karma": "^6.4.4", "karma-chrome-launcher": "^3.2.0", "karma-cli": "^2.0.0", @@ -27,11 +27,10 @@ } }, "node_modules/@seriousme/openapi-schema-validator": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@seriousme/openapi-schema-validator/-/openapi-schema-validator-2.3.1.tgz", - "integrity": "sha512-szUXBZJUhq+Yw+vUro2QeltSIoZvMDQi3MLqJhIKcRcRYyFt9B6dyjMD1RVf3nFvNAHkWqa48NJA46ti2P8smA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@seriousme/openapi-schema-validator/-/openapi-schema-validator-2.4.0.tgz", + "integrity": "sha512-2PWq2QbDMu+CANpBLZ2Uch9PgTIiftLpiLH4lcaykjV463f4Vt9eD61EeaVI++D0HII4JKnptX46391pII1XZA==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", diff --git a/package.json b/package.json index 099a051d..a87d623d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "reitit", "private": true, "devDependencies": { - "@seriousme/openapi-schema-validator": "^2.3.1", + "@seriousme/openapi-schema-validator": "^2.4.0", "karma": "^6.4.4", "karma-chrome-launcher": "^3.2.0", "karma-cli": "^2.0.0", diff --git a/project.clj b/project.clj index dbe9796c..b6016bfc 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-parent "0.8.0" +(defproject metosin/reitit-parent "0.9.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" @@ -18,29 +18,29 @@ ;; TODO: need to verify that the code actually worked with Java1.8, see #242 ;; 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.8.0"] - [metosin/reitit-core "0.8.0"] - [metosin/reitit-dev "0.8.0"] - [metosin/reitit-spec "0.8.0"] - [metosin/reitit-malli "0.8.0"] - [metosin/reitit-schema "0.8.0"] - [metosin/reitit-ring "0.8.0"] - [metosin/reitit-middleware "0.8.0"] - [metosin/reitit-http "0.8.0"] - [metosin/reitit-interceptors "0.8.0"] - [metosin/reitit-swagger "0.8.0"] - [fi.metosin/reitit-openapi "0.8.0"] - [metosin/reitit-swagger-ui "0.8.0"] - [metosin/reitit-frontend "0.8.0"] - [metosin/reitit-sieppari "0.8.0"] - [metosin/reitit-pedestal "0.8.0"] + :managed-dependencies [[metosin/reitit "0.9.1"] + [metosin/reitit-core "0.9.1"] + [metosin/reitit-dev "0.9.1"] + [metosin/reitit-spec "0.9.1"] + [metosin/reitit-malli "0.9.1"] + [metosin/reitit-schema "0.9.1"] + [metosin/reitit-ring "0.9.1"] + [metosin/reitit-middleware "0.9.1"] + [metosin/reitit-http "0.9.1"] + [metosin/reitit-interceptors "0.9.1"] + [metosin/reitit-swagger "0.9.1"] + [fi.metosin/reitit-openapi "0.9.1"] + [metosin/reitit-swagger-ui "0.9.1"] + [metosin/reitit-frontend "0.9.1"] + [metosin/reitit-sieppari "0.9.1"] + [metosin/reitit-pedestal "0.9.1"] [metosin/ring-swagger-ui "5.20.0"] [metosin/spec-tools "0.10.7"] [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.17.0"] + [metosin/malli "0.18.0"] ;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111 [com.fasterxml.jackson.core/jackson-core "2.18.2"] @@ -99,7 +99,7 @@ [metosin/muuntaja "0.6.11"] [metosin/sieppari "0.0.0-alpha13"] [metosin/jsonista "0.3.13"] - [metosin/malli "0.17.0"] + [metosin/malli "0.18.0"] [lambdaisland/deep-diff "0.0-47"] [meta-merge "1.0.0"] [com.bhauman/spell-spec "0.1.2"] diff --git a/test/cljc/reitit/openapi_test.clj b/test/cljc/reitit/openapi_test.clj index 11d3fd85..ca545008 100644 --- a/test/cljc/reitit/openapi_test.clj +++ b/test/cljc/reitit/openapi_test.clj @@ -1009,7 +1009,7 @@ {:content {"application/json" {:schema - {:$ref "#/components/schemas/reitit.openapi-test~1Plus"}}}}}} + {:$ref "#/components/schemas/reitit.openapi-test.Plus"}}}}}} "/get" {:get {:parameters @@ -1019,19 +1019,15 @@ {:in "query" :name :y :required true - :schema {:$ref "#/components/schemas/reitit.openapi-test~1Y"}}]}}} + :schema {:$ref "#/components/schemas/reitit.openapi-test.Y"}}]}}} :components {:schemas - {"reitit.openapi-test/Plus" + {"reitit.openapi-test.Plus" {:type "object" :properties {:x {:type "integer"} - :y {:$ref "#/components/schemas/reitit.openapi-test~1Y"}} + :y {:$ref "#/components/schemas/reitit.openapi-test.Y"}} :required [:x :y]} - "reitit.openapi-test/Y" {:type "integer"}}}} + "reitit.openapi-test.Y" {:type "integer"}}}} spec)) - ;; TODO: the OAS 3.1 json schema disallows "/" in :components :schemas keys, - ;; even though the text of the spec allows it. See: - ;; https://github.com/seriousme/openapi-schema-validator/blob/772375bf4895f0e641d103c27140cdd1d2afc34e/schemas/v3.1/schema.json#L282 - #_ (is (nil? (validate spec)))))) diff --git a/test/cljc/reitit/ring_coercion_test.cljc b/test/cljc/reitit/ring_coercion_test.cljc index cf8364a8..aae8d69a 100644 --- a/test/cljc/reitit/ring_coercion_test.cljc +++ b/test/cljc/reitit/ring_coercion_test.cljc @@ -695,15 +695,22 @@ (testing (str coercion) (let [app (ring/ring-handler (ring/router - ["/foo" {:post {:responses {200 {:content {:default {:schema schema-200}}} - 201 {:content {"application/edn" {:schema schema-200}}} - 202 {:description "status code and content-type explicitly mentioned, but no :schema" - :content {"application/edn" {} - "application/json" {}}} - :default {:content {"application/json" {:schema schema-default}}}} - :handler (fn [req] - {:status (-> req :body-params :status) - :body (-> req :body-params :response)})}}] + [["/foo" {:post {:responses {200 {:content {:default {:schema schema-200}}} + 201 {:content {"application/edn" {:schema schema-200}}} + 202 {:description "status code and content-type explicitly mentioned, but no :schema" + :content {"application/edn" {} + "application/json" {}}} + :default {:content {"application/json" {:schema schema-default}}}} + :handler (fn [req] + {:status (-> req :body-params :status) + :body (-> req :body-params :response)})}}] + ["/bar" {:post {:responses {200 {:content {:default {:schema schema-200}}}} + :handler (fn [req] + {:status (-> req :body-params :status) + :body (-> req :body-params :response)})}}] + ["/quux" {:post {:handler (fn [req] + {:status (-> req :body-params :status) + :body (-> req :body-params :response)})}}]] {:validate reitit.ring.spec/validate :data {:middleware [rrc/coerce-request-middleware rrc/coerce-response-middleware] @@ -713,40 +720,52 @@ (app request) (catch ExceptionInfo e (select-keys (ex-data e) [:type :in])))) - request (fn [body] + request (fn [uri body] {:request-method :post - :uri "/foo" + :uri uri :muuntaja/request {:format "application/json"} :muuntaja/response {:format (:format body "application/json")} :body-params body})] (testing "explicit response schema" (is (= {:status 200 :body {:a 1}} - (call (request {:status 200 :response {:a 1}}))) + (call (request "/foo" {:status 200 :response {:a 1}}))) "valid response") (is (= {:type :reitit.coercion/response-coercion, :in [:response :body]} - (call (request {:status 200 :response {:b 1}}))) + (call (request "/foo" {:status 200 :response {:b 1}}))) "invalid response") (is (= {:type :reitit.coercion/response-coercion, :in [:response :body]} - (call (request {:status 200 :response {:b 1} :format "application/edn"}))) + (call (request "/foo" {:status 200 :response {:b 1} :format "application/edn"}))) "invalid response, different content-type")) (testing "explicit response schema, but for the wrong content-type" (is (= {:status 201 :body "anything goes!"} - (call (request {:status 201 :response "anything goes!"}))) + (call (request "/foo" {:status 201 :response "anything goes!"}))) "no coercion applied")) (testing "response config without :schema" (is (= {:status 202 :body "anything goes!"} - (call (request {:status 202 :response "anything goes!"}))) + (call (request "/foo" {:status 202 :response "anything goes!"}))) "no coercion applied")) (testing "default response schema" (is (= {:status 300 :body {:b 2}} - (call (request {:status 300 :response {:b 2}}))) + (call (request "/foo" {:status 300 :response {:b 2}}))) "valid response") (is (= {:type :reitit.coercion/response-coercion, :in [:response :body]} - (call (request {:status 300 :response {:a 2}}))) + (call (request "/foo" {:status 300 :response {:a 2}}))) "invalid response") (is (= {:status 300 :body "anything goes!"} - (call (request {:status 300 :response "anything goes!" :format "application/edn"}))) - "no coercion applied due to content-type"))))))) + (call (request "/foo" {:status 300 :response "anything goes!" :format "application/edn"}))) + "no coercion applied due to content-type")) + (testing "no default" + (is (= {:status 200 :body {:a 1}} + (call (request "/bar" {:status 200 :response {:a 1}}))) + "valid response") + (testing "unlisted response code" + (is (= {:status 202 :body "anything goes!"} + (call (request "/bar" {:status 202 :response "anything goes!"}))) + "no coercion applied"))) + (testing "no response coercion" + (is (= {:status 200 :body "anything goes!"} + (call (request "/quux" {:status 200 :response "anything goes!"}))) + "no coercion applied"))))))) #?(:clj (deftest muuntaja-test diff --git a/test/cljc/reitit/ring_spec_test.cljc b/test/cljc/reitit/ring_spec_test.cljc index 2e1b1648..e63fc319 100644 --- a/test/cljc/reitit/ring_spec_test.cljc +++ b/test/cljc/reitit/ring_spec_test.cljc @@ -12,6 +12,9 @@ (s/def ::role #{:admin :user}) (s/def ::roles (s/and (s/coll-of ::role :into #{}) set?)) +(defmulti my-multi (constantly :default)) +(defmethod my-multi :default [x] x) + (deftest route-data-validation-test (testing "validation is turned off by default" (is (r/router? @@ -85,6 +88,12 @@ (ring/router ["/api" {:handler identity :middleware '()}] + {:validate rrs/validate})))) + + (testing "handler can be a multimethod" + (is (r/router? + (ring/router + ["/api" {:get {:handler my-multi}}] {:validate rrs/validate}))))) (deftest coercion-spec-test diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 593a1287..9fcbd10a 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -161,14 +161,14 @@ expected {:x-id #{::math} :swagger "2.0" :info {:title "my-api"} - :definitions {"reitit.swagger-test/req-key" {:type "string" + :definitions {"reitit.swagger-test.req-key" {:type "string" :x-anyOf [{:type "string"} {:type "string"}]} - "reitit.swagger-test/req-val" {:type "object" + "reitit.swagger-test.req-val" {:type "object" :x-anyOf [{:type "object"} {:type "string"}]} - "reitit.swagger-test/resp-map" {:type "object"}, - "reitit.swagger-test/resp-string" {:type "string" + "reitit.swagger-test.resp-map" {:type "object"}, + "reitit.swagger-test.resp-string" {:type "string" :minLength 1}} :paths {"/api/spec/plus/{z}" {:patch {:parameters [] :summary "patch" @@ -287,12 +287,12 @@ :schema {:type "object" :additionalProperties - {:$ref "#/definitions/reitit.swagger-test~1req-val"}}}] + {:$ref "#/definitions/reitit.swagger-test.req-val"}}}] :responses {200 {:schema - {:$ref "#/definitions/reitit.swagger-test~1resp-map" - :x-anyOf [{:$ref "#/definitions/reitit.swagger-test~1resp-map"} - {:$ref "#/definitions/reitit.swagger-test~1resp-string"}]} + {:$ref "#/definitions/reitit.swagger-test.resp-map" + :x-anyOf [{:$ref "#/definitions/reitit.swagger-test.resp-map"} + {:$ref "#/definitions/reitit.swagger-test.resp-string"}]} :description ""} 500 {:description "fail"}} :summary "plus put with definitions"}} @@ -532,24 +532,24 @@ {:get {:no-doc true :handler (swagger/create-swagger-handler)}}]])) spec (:body (app {:request-method :get, :uri "/swagger.json"}))] - (is (= {:definitions {"reitit.swagger-test/Plus" {:properties {:x {:$ref "#/definitions/reitit.swagger-test~1X"}, - :y {:$ref "#/definitions/reitit.swagger-test~1Y"}}, + (is (= {:definitions {"reitit.swagger-test.Plus" {:properties {:x {:$ref "#/definitions/reitit.swagger-test.X"}, + :y {:$ref "#/definitions/reitit.swagger-test.Y"}}, :required [:x :y], :type "object"}, - "reitit.swagger-test/X" {:format "int64", + "reitit.swagger-test.X" {:format "int64", :type "integer"}, - "reitit.swagger-test/Y" {:format "int64", + "reitit.swagger-test.Y" {:format "int64", :type "integer"}, - "reitit.swagger-test/Result" {:type "object", + "reitit.swagger-test.Result" {:type "object", :properties {:result {:type "integer", :format "int64"}}, :required [:result]}}, :paths {"/post" {:post {:parameters [{:description "", :in "body", :name "body", :required true, - :schema {:$ref "#/definitions/reitit.swagger-test~1Plus"}}] + :schema {:$ref "#/definitions/reitit.swagger-test.Plus"}}] :responses {200 {:description "" - :schema {:$ref "#/definitions/reitit.swagger-test~1Result"}}}}} + :schema {:$ref "#/definitions/reitit.swagger-test.Result"}}}}} "/get" {:get {:parameters [{:in "query" :name :x :description "" @@ -563,7 +563,7 @@ :required true :format "int64"}] :responses {200 {:description "" - :schema {:$ref "#/definitions/reitit.swagger-test~1Result"}}}}}} + :schema {:$ref "#/definitions/reitit.swagger-test.Result"}}}}}} :swagger "2.0", :x-id #{:reitit.swagger/default}} spec))))