Merge branch 'master' into fix-resource-handler-url-decoding

This commit is contained in:
Tommi Reiman 2021-08-03 13:33:39 +03:00 committed by GitHub
commit 38f2bd4812
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 156 additions and 86 deletions

View file

@ -14,10 +14,27 @@ We use [Break Versioning][breakver]. The version numbers follow a `<major>.<mino
## UNRELEASED ## UNRELEASED
* updated deps:
```clj
[metosin/ring-swagger-ui "3.46.0"] is available but we use "3.36.0"
[metosin/jsonista "0.3.3"] is available but we use "0.3.1"
[metosin/malli "0.5.1"] is available but we use "0.3.0"
[com.fasterxml.jackson.core/jackson-core "2.12.4"] is available but we use "2.12.1"
[com.fasterxml.jackson.core/jackson-databind "2.12.4"] is available but we use "2.12.1"
[fipp "0.6.24"] is available but we use "0.6.23"
[ring/ring-core "1.9.4"] is available but we use "1.9.1"
[io.pedestal/pedestal.service "0.5.9"] is available but we use "0.5.8"
```
### `reitit-ring` ### `reitit-ring`
* Fixes `reitit.ring/create-resource-handler` and `reitit.ring/create-file-handler` to support URL-escaped characters. [#484](https://github.com/metosin/reitit/issues/484). PR [#489](https://github.com/metosin/reitit/pull/489). * Fixes `reitit.ring/create-resource-handler` and `reitit.ring/create-file-handler` to support URL-escaped characters. [#484](https://github.com/metosin/reitit/issues/484). PR [#489](https://github.com/metosin/reitit/pull/489).
### `reitit-malli`
* FIX: Malli response coercision seems to do nothing at all [#498](https://github.com/metosin/reitit/pull/501)
## 0.5.13 (2021-04-23) ## 0.5.13 (2021-04-23)
* updated deps: * updated deps:

View file

@ -157,6 +157,7 @@ All examples are in https://github.com/metosin/reitit/tree/master/examples
* https://www.learnreitit.com/ * https://www.learnreitit.com/
* Lipas, liikuntapalvelut: https://github.com/lipas-liikuntapaikat/lipas * Lipas, liikuntapalvelut: https://github.com/lipas-liikuntapaikat/lipas
* Implementation of the Todo-Backend API spec, using Clojure, Ring/Reitit and next-jdbc: https://github.com/PrestanceDesign/todo-backend-clojure-reitit * Implementation of the Todo-Backend API spec, using Clojure, Ring/Reitit and next-jdbc: https://github.com/PrestanceDesign/todo-backend-clojure-reitit
* Ping CRM, a single page app written in Clojure Ring, Reitit, Integrant and next.jdbc: https://github.com/prestancedesign/clojure-inertia-pingcrm-demo
## More info ## More info

View file

@ -39,7 +39,7 @@ Responses are defined in route data under `:responses` key. It's value should be
Below is an example with [Plumatic Schema](https://github.com/plumatic/schema). It defines schemas for `:query`, `:body` and `:path` parameters and for http 200 response `:body`. Below is an example with [Plumatic Schema](https://github.com/plumatic/schema). It defines schemas for `:query`, `:body` and `:path` parameters and for http 200 response `:body`.
Handler can access the coerced parameters can be read under `:parameters` key in the request. Handlers can access the coerced parameters via the `:parameters` key in the request.
```clj ```clj
(require '[reitit.coercion.schema]) (require '[reitit.coercion.schema])
@ -71,7 +71,7 @@ Defining a coercion for a route data doesn't do anything, as it's just data. We
### Full example ### Full example
Here's an full example for applying coercion with Reitit, Ring and Schema: Here is a full example for applying coercion with Reitit, Ring and Schema:
```clj ```clj
(require '[reitit.ring.coercion :as rrc]) (require '[reitit.ring.coercion :as rrc])
@ -150,7 +150,7 @@ Invalid response:
## Pretty printing spec errors ## Pretty printing spec errors
Spec problems are exposed as-is into request & response coercion errors, enabling pretty-printers like [expound](https://github.com/bhb/expound) to be used: Spec problems are exposed as is in request & response coercion errors. Pretty-printers like [expound](https://github.com/bhb/expound) can be enabled like this:
```clj ```clj
(require '[reitit.ring :as ring]) (require '[reitit.ring :as ring])
@ -216,7 +216,7 @@ Spec problems are exposed as-is into request & response coercion errors, enablin
### Optimizations ### Optimizations
The coercion middleware are [compiled against a route](compiling_middleware.md). In the middleware compilation step the actual coercer implementations are constructed for the defined models. Also, the middleware doesn't mount itself if a route doesn't have `:coercion` and `:parameters` or `:responses` defined. The coercion middlewares are [compiled against a route](compiling_middleware.md). In the middleware compilation step the actual coercer implementations are constructed for the defined models. Also, the middleware doesn't mount itself if a route doesn't have `:coercion` and `:parameters` or `:responses` defined.
We can query the compiled middleware chain for the routes: We can query the compiled middleware chain for the routes:

View file

@ -1,12 +1,12 @@
# Compiling Middleware # Compiling Middleware
The [dynamic extensions](dynamic_extensions.md) is a easy way to extend the system. To enable fast lookups into route data, we can compile them into any shape (records, functions etc.) we want, enabling fast access at request-time. The [dynamic extensions](dynamic_extensions.md) are an easy way to extend the system. To enable fast lookup of route data, we can compile them into any shape (records, functions etc.), enabling fast access at request-time.
But, we can do much better. As we know the exact route that middleware/interceptor is linked to, we can pass the (compiled) route information into the middleware at creation-time. It can do local reasoning: extract and transform relevant data just for it and pass the optimized data into the actual request-handler via a closure - yielding much faster runtime processing. Middleware can also decide not to mount itself by returning `nil`. Why mount a `wrap-enforce-roles` middleware for a route if there are no roles required for it? But, we can do much better. As we know the exact route that a middleware/interceptor is linked to, we can pass the (compiled) route information into the middleware at creation-time. It can do local reasoning: Extract and transform relevant data just for it and pass the optimized data into the actual request-handler via a closure - yielding much faster runtime processing. A middleware can also decide not to mount itself by returning `nil`. (E.g. Why mount a `wrap-enforce-roles` middleware for a route if there are no roles required for it?)
To enable this we use [middleware records](data_driven_middleware.md) `:compile` key instead of the normal `:wrap`. `:compile` expects a function of `route-data router-opts => ?IntoMiddleware`. To enable this we use [middleware records](data_driven_middleware.md) `:compile` key instead of the normal `:wrap`. `:compile` expects a function of `route-data router-opts => ?IntoMiddleware`.
To demonstrate the two approaches, below are response coercion middleware written as normal ring middleware function and as middleware record with `:compile`. To demonstrate the two approaches, below is the response coercion middleware written as normal ring middleware function and as middleware record with `:compile`.
## Normal Middleware ## Normal Middleware

View file

@ -1,8 +1,8 @@
# Content Negotiation # Content Negotiation
Wrapper for [Muuntaja](https://github.com/metosin/muuntaja) middleware for content-negotiation, request decoding and response encoding. Takes explicit configuration via `:muuntaja` key in route data. Emit's [swagger](swagger.md) `:produces` and `:consumes` definitions automatically based on the Muuntaja configuration. Wrapper for [Muuntaja](https://github.com/metosin/muuntaja) middleware for content negotiation, request decoding and response encoding. Takes explicit configuration via `:muuntaja` key in route data. Emits [swagger](swagger.md) `:produces` and `:consumes` definitions automatically based on the Muuntaja configuration.
Negotiates a request body based on `Content-Type` header and response body based on `Accept`, `Accept-Charset` headers. Publishes the negotiation results as `:muuntaja/request` and `:muuntaja/response` keys into the request. Negotiates a request body based on `Content-Type` header and response body based on `Accept` and `Accept-Charset` headers. Publishes the negotiation results as `:muuntaja/request` and `:muuntaja/response` keys into the request.
Decodes the request body into `:body-params` using the `:muuntaja/request` key in request if the `:body-params` doesn't already exist. Decodes the request body into `:body-params` using the `:muuntaja/request` key in request if the `:body-params` doesn't already exist.
@ -87,7 +87,7 @@ Server: Jetty(9.2.21.v20170120)
## Changing default parameters ## Changing default parameters
The current JSON formatter used by `reitit` already have the option to parse keys as `keyword` which is a sane default in Clojure. However, if you would like to parse all the `double` as `bigdecimal` you'd need to change an option of the [JSON formatter](https://github.com/metosin/jsonista) The current JSON formatter used by `reitit` already has the option to parse keys as `keyword` which is a sane default in Clojure. However, if you would like to parse all the `double` as `bigdecimal` you'd need to change an option of the [JSON formatter](https://github.com/metosin/jsonista)
```clj ```clj
@ -102,7 +102,7 @@ The current JSON formatter used by `reitit` already have the option to parse key
Now you should change the `m/instance` installed in the router with the `new-muuntaja-instance`. Now you should change the `m/instance` installed in the router with the `new-muuntaja-instance`.
You can find more options for [JSON](https://cljdoc.org/d/metosin/jsonista/0.2.5/api/jsonista.core#object-mapper) and [EDN]. Here you can find more options for [JSON](https://cljdoc.org/d/metosin/jsonista/0.2.5/api/jsonista.core#object-mapper) and EDN.
## Adding custom encoder ## Adding custom encoder
@ -125,9 +125,9 @@ The example below is from `muuntaja` explaining how to add a custom encoder to p
``` ```
## Adding all together ## Putting it all together
If you inspect `m/default-options` it's only a map, therefore you can compose your new muuntaja instance with as many options as you need it. If you inspect `m/default-options` you'll find it's only a map. This means you can compose your new muuntaja instance with as many options as you need.
```clj ```clj
(def new-muuntaja (def new-muuntaja

View file

@ -1,19 +1,19 @@
# Data-driven Middleware # Data-driven Middleware
Ring [defines middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware) as a function of type `handler & args => request => response`. It's relatively easy to understand and enables good performance. Downside is that the middleware-chain is just a opaque function, making things like debugging and composition hard. It's too easy to apply the middleware in wrong order. 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.
Reitit defines middleware as data: Reitit defines middleware as data:
1. Middleware can be defined as first-class data entries 1. A middleware can be defined as first-class data entries
2. Middleware can be mounted as a [duct-style](https://github.com/duct-framework/duct/wiki/Configuration) vector (of middleware) 2. A middleware can be mounted as a [duct-style](https://github.com/duct-framework/duct/wiki/Configuration) vector (of middlewares)
4. Middleware can be optimized & [compiled](compiling_middleware.md) against an endpoint 4. A middleware can be optimized & [compiled](compiling_middleware.md) against an endpoint
3. Middleware chain can be transformed by the router 3. A middleware chain can be transformed by the router
## Middleware as data ## Middleware as data
All values in the `:middleware` vector in the route data are expanded into `reitit.middleware/Middleware` Records with using the `reitit.middleware/IntoMiddleware` Protocol. By default, functions, maps and `Middleware` records are allowed. All values in the `:middleware` vector of route data are expanded into `reitit.middleware/Middleware` Records by using the `reitit.middleware/IntoMiddleware` Protocol. By default, functions, maps and `Middleware` records are allowed.
Records can have arbitrary keys, but the following keys have a special purpose: Records can have arbitrary keys, but the following keys have special purpose:
| key | description | | key | description |
| ---------------|-------------| | ---------------|-------------|
@ -22,13 +22,13 @@ Records can have arbitrary keys, but the following keys have a special purpose:
| `:wrap` | The actual middleware function of `handler & args => request => response` | `:wrap` | The actual middleware function of `handler & args => request => response`
| `:compile` | Middleware compilation function, see [compiling middleware](compiling_middleware.md). | `:compile` | Middleware compilation function, see [compiling middleware](compiling_middleware.md).
Middleware Records are accessible in their raw form in the compiled route results, thus available for inventories, creating api-docs etc. Middleware Records are accessible in their raw form in the compiled route results, and thus are available for inventories, creating api-docs, etc.
For the actual request processing, the Records are unwrapped into normal functions and composed into a middleware function chain, yielding zero runtime penalty. For the actual request processing, the Records are unwrapped into normal functions and composed into a middleware function chain, yielding zero runtime penalty.
### Creating Middleware ### Creating Middleware
The following produce identical middleware runtime function. The following examples produce identical middleware runtime functions.
### Function ### Function
@ -77,7 +77,7 @@ The following produce identical middleware runtime function.
:handler handler}}]]))) :handler handler}}]])))
``` ```
All the middleware are applied correctly: All the middlewares are applied correctly:
```clj ```clj
(app {:request-method :get, :uri "/api/ping"}) (app {:request-method :get, :uri "/api/ping"})
@ -86,7 +86,7 @@ All the middleware are applied correctly:
## Compiling middleware ## Compiling middleware
Middleware can be optimized against an endpoint using [middleware compilation](compiling_middleware.md). Middlewares can be optimized against an endpoint using [middleware compilation](compiling_middleware.md).
## Ideas for the future ## Ideas for the future

View file

@ -1,6 +1,6 @@
# Default handler # Default handler
By default, if no routes match, `nil` is returned, which is not valid response in Ring: By default, if no routes match, `nil` is returned, which is not a valid response in Ring:
```clj ```clj
(require '[reitit.ring :as ring]) (require '[reitit.ring :as ring])

View file

@ -4,7 +4,7 @@
[metosin/reitit-middleware "0.5.13"] [metosin/reitit-middleware "0.5.13"]
``` ```
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. 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.
* [Parameter Handling](#parameters-handling) * [Parameter Handling](#parameters-handling)
* [Exception Handling](#exception-handling) * [Exception Handling](#exception-handling)

View file

@ -1,8 +1,8 @@
# Dynamic Extensions # Dynamic Extensions
`ring-handler` injects the `Match` into a request and it can be extracted at runtime with `reitit.ring/get-match`. This can be used to build ad-hoc extensions to the system. `ring-handler` injects the `Match` into a request and it can be extracted at runtime with `reitit.ring/get-match`. This can be used to build ad hoc extensions to the system.
Example middleware to guard routes based on user roles: This example shows a middleware to guard routes based on user roles:
```clj ```clj
(require '[reitit.ring :as ring]) (require '[reitit.ring :as ring])

View file

@ -4,7 +4,7 @@
[metosin/reitit-middleware "0.5.13"] [metosin/reitit-middleware "0.5.13"]
``` ```
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 practise is a have an top-level exception handler to log and format the errors for clients. 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.
```clj ```clj
(require '[reitit.ring.middleware.exception :as exception]) (require '[reitit.ring.middleware.exception :as exception])
@ -36,7 +36,7 @@ A preconfigured middleware using `exception/default-handlers`. Catches:
### `exception/create-exception-middleware` ### `exception/create-exception-middleware`
Creates the exception-middleware with custom options. Takes a map of `identifier => exception request => response` that is used to select the exception handler for the thrown/raised exception identifier. Exception identifier is either a `Keyword` or a Exception Class. Creates the exception-middleware with custom options. Takes a map of `identifier => exception request => response` that is used to select the exception handler for the thrown/raised exception identifier. Exception identifier is either a `Keyword` or an Exception Class.
The following handlers are available by default: The following handlers are available by default:
@ -55,7 +55,7 @@ The handler is selected from the options map by exception identifier in the foll
2) Class of exception 2) Class of exception
3) `:type` ancestors of exception ex-data 3) `:type` ancestors of exception ex-data
4) Super Classes of exception 4) Super Classes of exception
5) The ::default handler 5) The `::default` handler
```clj ```clj
;; type hierarchy ;; type hierarchy
@ -94,7 +94,7 @@ The handler is selected from the options map by exception identifier in the foll
(def app (def app
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/fail" (fn [_] (throw (ex-info "fail" {:type ::failue})))] ["/fail" (fn [_] (throw (ex-info "fail" {:type ::failure})))]
{:data {:middleware [exception-middleware]}}))) {:data {:middleware [exception-middleware]}})))
(app {:request-method :get, :uri "/fail"}) (app {:request-method :get, :uri "/fail"})
@ -102,6 +102,6 @@ The handler is selected from the options map by exception identifier in the foll
; => {:status 500, ; => {:status 500,
; :body {:message "default" ; :body {:message "default"
; :exception clojure.lang.ExceptionInfo ; :exception clojure.lang.ExceptionInfo
; :data {:type :user/failue} ; :data {:type :user/failure}
; :uri "/fail"}} ; :uri "/fail"}}
``` ```

View file

@ -12,7 +12,7 @@ Read more about the [Ring Concepts](https://github.com/ring-clojure/ring/wiki/Co
`ring-router` is a higher order router, which adds support for `:request-method` based routing, [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers) and [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware). `ring-router` is a higher order router, which adds support for `:request-method` based routing, [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers) and [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware).
It accepts the following options: It accepts the following options:
| key | description | | key | description |
| ----------------------------------------|-------------| | ----------------------------------------|-------------|
@ -53,7 +53,7 @@ Given a `ring-router`, optional default-handler & options, `ring-handler` functi
| key | description | | key | description |
| ------------------|-------------| | ------------------|-------------|
| `:middleware` | Optional sequence of middleware that wrap the ring-handler" | `:middleware` | Optional sequence of middlewares that wrap the ring-handler
| `:inject-match?` | Boolean to inject `match` into request under `:reitit.core/match` key (default true) | `:inject-match?` | Boolean to inject `match` into request under `:reitit.core/match` key (default true)
| `:inject-router?` | Boolean to inject `router` into request under `:reitit.core/router` key (default true) | `:inject-router?` | Boolean to inject `router` into request under `:reitit.core/router` key (default true)

View file

@ -89,7 +89,8 @@
default-interceptors (->> interceptors default-interceptors (->> interceptors
(map #(interceptor/into-interceptor % nil (r/options router)))) (map #(interceptor/into-interceptor % nil (r/options router))))
default-queue (interceptor/queue executor default-interceptors) default-queue (interceptor/queue executor default-interceptors)
enrich-request (ring/create-enrich-request inject-match? inject-router?)] enrich-request (ring/create-enrich-request inject-match? inject-router?)
enrich-default-request (ring/create-enrich-default-request inject-router?)]
{:name ::router {:name ::router
:enter (fn [{:keys [request] :as context}] :enter (fn [{:keys [request] :as context}]
(if-let [match (r/match-by-path router (:uri request))] (if-let [match (r/match-by-path router (:uri request))]
@ -101,7 +102,9 @@
context (assoc context :request request) context (assoc context :request request)
queue (interceptor/queue executor (concat default-interceptors interceptors))] queue (interceptor/queue executor (concat default-interceptors interceptors))]
(interceptor/enqueue executor context queue)) (interceptor/enqueue executor context queue))
(interceptor/enqueue executor context default-queue))) (let [request (enrich-default-request request router)
context (assoc context :request request)]
(interceptor/enqueue executor context default-queue))))
:leave (fn [context] :leave (fn [context]
(if-not (:response context) (if-not (:response context)
(assoc context :response (default-handler (:request context))) (assoc context :response (default-handler (:request context)))

View file

@ -34,7 +34,7 @@
(def json-transformer-provider (-provider (mt/json-transformer))) (def json-transformer-provider (-provider (mt/json-transformer)))
(def default-transformer-provider (-provider nil)) (def default-transformer-provider (-provider nil))
(defn- -coercer [schema type transformers f encoder {:keys [validate enabled options]}] (defn- -coercer [schema type transformers f {:keys [validate enabled options]}]
(if schema (if schema
(let [->coercer (fn [t] (let [->coercer (fn [t]
(let [decoder (if t (m/decoder schema options t) identity) (let [decoder (if t (m/decoder schema options t) identity)
@ -48,7 +48,6 @@
(-explain [_ value] (explainer value))))) (-explain [_ value] (explainer value)))))
{:keys [formats default]} (transformers type) {:keys [formats default]} (transformers type)
default-coercer (->coercer default) default-coercer (->coercer default)
encode (or encoder (fn [value _format] value))
format-coercers (some->> (for [[f t] formats] [f (->coercer t)]) (filter second) (seq) (into {})) format-coercers (some->> (for [[f t] formats] [f (->coercer t)]) (filter second) (seq) (into {}))
get-coercer (cond format-coercers (fn [format] (or (get format-coercers format) default-coercer)) get-coercer (cond format-coercers (fn [format] (or (get format-coercers format) default-coercer))
default-coercer (constantly default-coercer))] default-coercer (constantly default-coercer))]
@ -66,14 +65,14 @@
value)) value))
;; encode: decode -> validate -> encode ;; encode: decode -> validate -> encode
(fn [value format] (fn [value format]
(let [transformed (-decode default-coercer value)]
(if-let [coercer (get-coercer format)] (if-let [coercer (get-coercer format)]
(let [transformed (-decode coercer value)]
(if (-validate coercer transformed) (if (-validate coercer transformed)
(encode transformed format) (-encode coercer transformed)
(let [error (-explain coercer transformed)] (let [error (-explain coercer transformed)]
(coercion/map->CoercionError (coercion/map->CoercionError
(assoc error :transformed transformed))))) (assoc error :transformed transformed))))
value))))))) value))))))))
;; ;;
;; swagger ;; swagger
@ -106,11 +105,13 @@
;; public api ;; public api
;; ;;
;; TODO: this is much too compöex
(def default-options (def default-options
{:transformers {:body {:default default-transformer-provider {:transformers {:body {:default default-transformer-provider
:formats {"application/json" json-transformer-provider}} :formats {"application/json" json-transformer-provider}}
:string {:default string-transformer-provider} :string {:default string-transformer-provider}
:response {:default default-transformer-provider}} :response {:default default-transformer-provider
:formats {"application/json" json-transformer-provider}}}
;; set of keys to include in error messages ;; set of keys to include in error messages
:error-keys #{:type :coercion :in :schema :value :errors :humanized #_:transformed} :error-keys #{:type :coercion :in :schema :value :errors :humanized #_:transformed}
;; schema identity function (default: close all map schemas) ;; schema identity function (default: close all map schemas)
@ -176,10 +177,8 @@
(seq error-keys) (select-keys error-keys) (seq error-keys) (select-keys error-keys)
encode-error (encode-error))) encode-error (encode-error)))
(-request-coercer [_ type schema] (-request-coercer [_ type schema]
(-coercer (compile schema options) type transformers :decode nil opts)) (-coercer (compile schema options) type transformers :decode opts))
(-response-coercer [_ schema] (-response-coercer [_ schema]
(let [schema (compile schema options) (-coercer (compile schema options) :response transformers :encode opts))))))
encoder (-coercer schema :body transformers :encode nil opts)]
(-coercer schema :response transformers :encode encoder opts)))))))
(def coercion (create default-options)) (def coercion (create default-options))

View file

@ -27,28 +27,28 @@
[metosin/reitit-frontend "0.5.13"] [metosin/reitit-frontend "0.5.13"]
[metosin/reitit-sieppari "0.5.13"] [metosin/reitit-sieppari "0.5.13"]
[metosin/reitit-pedestal "0.5.13"] [metosin/reitit-pedestal "0.5.13"]
[metosin/ring-swagger-ui "3.36.0"] [metosin/ring-swagger-ui "3.46.0"]
[metosin/spec-tools "0.10.5"] [metosin/spec-tools "0.10.5"]
[metosin/schema-tools "0.12.3"] [metosin/schema-tools "0.12.3"]
[metosin/muuntaja "0.6.8"] [metosin/muuntaja "0.6.8"]
[metosin/jsonista "0.3.1"] [metosin/jsonista "0.3.3"]
[metosin/sieppari "0.0.0-alpha13"] [metosin/sieppari "0.0.0-alpha13"]
[metosin/malli "0.3.0"] [metosin/malli "0.5.1"]
;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111 ;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111
[com.fasterxml.jackson.core/jackson-core "2.12.1"] [com.fasterxml.jackson.core/jackson-core "2.12.4"]
[com.fasterxml.jackson.core/jackson-databind "2.12.1"] [com.fasterxml.jackson.core/jackson-databind "2.12.4"]
[meta-merge "1.0.0"] [meta-merge "1.0.0"]
[fipp "0.6.23" :exclusions [org.clojure/core.rrb-vector]] [fipp "0.6.24" :exclusions [org.clojure/core.rrb-vector]]
[expound "0.8.9"] [expound "0.8.9"]
[lambdaisland/deep-diff "0.0-47"] [lambdaisland/deep-diff "0.0-47"]
[com.bhauman/spell-spec "0.1.2"] [com.bhauman/spell-spec "0.1.2"]
[ring/ring-core "1.9.1"] [ring/ring-core "1.9.4"]
[io.pedestal/pedestal.service "0.5.8"]] [io.pedestal/pedestal.service "0.5.9"]]
:plugins [[jonase/eastwood "0.3.14"] :plugins [[jonase/eastwood "0.9.6"]
;[lein-virgil "0.1.7"] ;[lein-virgil "0.1.7"]
[lein-doo "0.1.11"] [lein-doo "0.1.11"]
[lein-cljsbuild "1.1.8"] [lein-cljsbuild "1.1.8"]
@ -85,33 +85,33 @@
[metosin/spec-tools "0.10.5"] [metosin/spec-tools "0.10.5"]
[metosin/muuntaja "0.6.8"] [metosin/muuntaja "0.6.8"]
[metosin/sieppari "0.0.0-alpha13"] [metosin/sieppari "0.0.0-alpha13"]
[metosin/jsonista "0.3.1"] [metosin/jsonista "0.3.3"]
[metosin/malli "0.2.1"] [metosin/malli "0.5.1"]
[lambdaisland/deep-diff "0.0-47"] [lambdaisland/deep-diff "0.0-47"]
[meta-merge "1.0.0"] [meta-merge "1.0.0"]
[com.bhauman/spell-spec "0.1.2"] [com.bhauman/spell-spec "0.1.2"]
[expound "0.8.9"] [expound "0.8.9"]
[fipp "0.6.23"] [fipp "0.6.24"]
[orchestra "2021.01.01-1"] [orchestra "2021.01.01-1"]
[ring "1.9.1"] [ring "1.9.4"]
[ikitommi/immutant-web "3.0.0-alpha1"] [ikitommi/immutant-web "3.0.0-alpha1"]
[metosin/ring-http-response "0.9.2"] [metosin/ring-http-response "0.9.2"]
[metosin/ring-swagger-ui "3.36.0"] [metosin/ring-swagger-ui "3.46.0"]
[criterium "0.4.6"] [criterium "0.4.6"]
[org.clojure/test.check "1.1.0"] [org.clojure/test.check "1.1.0"]
[org.clojure/tools.namespace "1.1.0"] [org.clojure/tools.namespace "1.1.0"]
[com.gfredericks/test.chuck "0.2.10"] [com.gfredericks/test.chuck "0.2.11"]
[io.pedestal/pedestal.service "0.5.8"] [io.pedestal/pedestal.service "0.5.9"]
[org.clojure/core.async "1.3.610"] [org.clojure/core.async "1.3.618"]
[manifold "0.1.8"] [manifold "0.1.8"]
[funcool/promesa "6.0.0"] [funcool/promesa "6.0.2"]
[com.clojure-goes-fast/clj-async-profiler "0.5.0"] [com.clojure-goes-fast/clj-async-profiler "0.5.1"]
[ring-cors "0.1.13"] [ring-cors "0.1.13"]
[com.bhauman/rebel-readline "0.1.4"]]} [com.bhauman/rebel-readline "0.1.4"]]}
@ -121,18 +121,18 @@
"-Dclojure.compiler.direct-linking=true"] "-Dclojure.compiler.direct-linking=true"]
:test-paths ["perf-test/clj"] :test-paths ["perf-test/clj"]
:dependencies [[compojure "1.6.2"] :dependencies [[compojure "1.6.2"]
[ring/ring-defaults "0.3.2"] [ring/ring-defaults "0.3.3"]
[ikitommi/immutant-web "3.0.0-alpha1"] [ikitommi/immutant-web "3.0.0-alpha1"]
[io.pedestal/pedestal.service "0.5.8"] [io.pedestal/pedestal.service "0.5.9"]
[io.pedestal/pedestal.jetty "0.5.8"] [io.pedestal/pedestal.jetty "0.5.9"]
[calfpath "0.8.1"] [calfpath "0.8.1"]
[org.clojure/core.async "1.3.610"] [org.clojure/core.async "1.3.618"]
[manifold "0.1.8"] [manifold "0.1.8"]
[funcool/promesa "6.0.0"] [funcool/promesa "6.0.2"]
[metosin/sieppari] [metosin/sieppari]
[yada "1.2.16"] [yada "1.2.16"]
[aleph "0.4.6"] [aleph "0.4.6"]
[ring/ring-defaults "0.3.2"] [ring/ring-defaults "0.3.3"]
[ataraxy "0.4.2"] [ataraxy "0.4.2"]
[bidi "2.1.6"] [bidi "2.1.6"]
[janus "1.3.2"]]} [janus "1.3.2"]]}

View file

@ -41,3 +41,25 @@
(:io.pedestal.http/service-fn))] (:io.pedestal.http/service-fn))]
(is (= "ok" (:body (io.pedestal.test/response-for service :get "/ok")))) (is (= "ok" (:body (io.pedestal.test/response-for service :get "/ok"))))
(is (= 500 (:status (io.pedestal.test/response-for service :get "/fail")))))) (is (= 500 (:status (io.pedestal.test/response-for service :get "/fail"))))))
(deftest pedestal-inject-router-test
(let [check-router (fn [r] (when-not (:reitit.core/router r)
(throw (ex-info "Missing :reitit.core/router!" {}))))
interceptor {:name ::needs-router
:enter (fn [{:as context :keys [request]}]
(check-router request)
context)}
router (pedestal/routing-interceptor
(http/router
[""
["/ok" (fn [r] (check-router r) {:status 200, :body "ok"})]])
nil
{:interceptors [interceptor]})
service (-> {:io.pedestal.http/request-logger nil
:io.pedestal.http/routes []}
(io.pedestal.http/default-interceptors)
(pedestal/replace-last-interceptor router)
(io.pedestal.http/create-servlet)
(:io.pedestal.http/service-fn))]
(is (= "ok" (:body (io.pedestal.test/response-for service :get "/ok"))))
(is (= "Not Found" (:body (io.pedestal.test/response-for service :get "/not-existing"))))))

View file

@ -449,7 +449,35 @@
(testing "failed response" (testing "failed response"
(let [{:keys [status body]} (app (->request [{:message "kosh"}]))] (let [{:keys [status body]} (app (->request [{:message "kosh"}]))]
(is (= 500 status)) (is (= 500 status))
(is (= :reitit.coercion/response-coercion (:type body)))))))))) (is (= :reitit.coercion/response-coercion (:type body))))))))
(testing "encoding responses"
(let [->app (fn [total-schema]
(ring/ring-handler
(ring/router
["/total" {:get {:parameters {:query [:map [:x :int]]}
:responses {200 {:body [:map [:total total-schema]]}}
:handler (fn [{{{:keys [x]} :query} :parameters}]
{:status 200
:body {:total (* x x)}})}}]
{:data {:middleware [rrc/coerce-request-middleware
rrc/coerce-response-middleware]
:coercion malli/coercion}})))
call (fn [accept total-schema]
((->app total-schema) {:uri "/total"
:request-method :get
:muuntaja/request {:format "application/json"}
:muuntaja/response {:format accept}
:query-params {"x" "2"}}))]
(testing "no encoding"
(is (= {:status 200, :body {:total +4}} (call "application/json" :int))))
(testing "json encoding"
(is (= {:status 200, :body {:total -4}} (call "application/json" [:int {:encode/json -}]))))
(testing "edn encoding (nada)"
(is (= {:status 200, :body {:total +4}} (call "application/edn" [:int {:encode/json -}]))))))))
#?(:clj #?(:clj
(deftest muuntaja-test (deftest muuntaja-test