2017-12-31 09:29:51 +00:00
|
|
|
(ns reitit.ring.coercion
|
2022-02-14 14:59:20 +00:00
|
|
|
(:require [reitit.coercion :as coercion]
|
|
|
|
|
[reitit.impl :as impl]
|
|
|
|
|
[reitit.spec :as rs]))
|
2017-12-09 20:49:32 +00:00
|
|
|
|
|
|
|
|
(defn handle-coercion-exception [e respond raise]
|
|
|
|
|
(let [data (ex-data e)]
|
2018-08-17 05:41:49 +00:00
|
|
|
(if-let [status (case (:type data)
|
2017-12-09 20:49:32 +00:00
|
|
|
::coercion/request-coercion 400
|
|
|
|
|
::coercion/response-coercion 500
|
|
|
|
|
nil)]
|
|
|
|
|
(respond
|
2022-02-12 20:34:26 +00:00
|
|
|
{:status status
|
|
|
|
|
:body (coercion/encode-error data)})
|
2017-12-09 20:49:32 +00:00
|
|
|
(raise e))))
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; middleware
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
(def coerce-request-middleware
|
|
|
|
|
"Middleware for pluggable request coercion.
|
|
|
|
|
Expects a :coercion of type `reitit.coercion/Coercion`
|
|
|
|
|
and :parameters from route data, otherwise does not mount."
|
2017-12-16 08:51:32 +00:00
|
|
|
{:name ::coerce-request
|
2017-12-31 09:34:37 +00:00
|
|
|
:spec ::rs/parameters
|
2023-05-28 13:49:08 +00:00
|
|
|
:compile (fn [{:keys [coercion parameters request]} opts]
|
2019-04-20 02:39:45 +00:00
|
|
|
(cond
|
|
|
|
|
;; no coercion, skip
|
|
|
|
|
(not coercion) nil
|
|
|
|
|
;; just coercion, don't mount
|
2023-05-28 13:49:08 +00:00
|
|
|
(not (or parameters request)) {}
|
2019-04-20 02:39:45 +00:00
|
|
|
;; mount
|
|
|
|
|
:else
|
2023-05-28 13:49:08 +00:00
|
|
|
(if-let [coercers (coercion/request-coercers coercion parameters request opts)]
|
2017-12-12 20:27:00 +00:00
|
|
|
(fn [handler]
|
|
|
|
|
(fn
|
|
|
|
|
([request]
|
|
|
|
|
(let [coerced (coercion/coerce-request coercers request)]
|
|
|
|
|
(handler (impl/fast-assoc request :parameters coerced))))
|
|
|
|
|
([request respond raise]
|
|
|
|
|
(let [coerced (coercion/coerce-request coercers request)]
|
2020-05-26 05:09:35 +00:00
|
|
|
(handler (impl/fast-assoc request :parameters coerced) respond raise)))))
|
|
|
|
|
{})))})
|
2017-12-09 20:49:32 +00:00
|
|
|
|
|
|
|
|
(def coerce-response-middleware
|
|
|
|
|
"Middleware for pluggable response coercion.
|
|
|
|
|
Expects a :coercion of type `reitit.coercion/Coercion`
|
|
|
|
|
and :responses from route data, otherwise does not mount."
|
2017-12-12 20:27:00 +00:00
|
|
|
{:name ::coerce-response
|
2017-12-31 09:34:37 +00:00
|
|
|
:spec ::rs/responses
|
2017-12-12 20:27:00 +00:00
|
|
|
:compile (fn [{:keys [coercion responses]} opts]
|
2019-04-20 02:39:45 +00:00
|
|
|
(cond
|
|
|
|
|
;; no coercion, skip
|
|
|
|
|
(not coercion) nil
|
|
|
|
|
;; just coercion, don't mount
|
|
|
|
|
(not responses) {}
|
|
|
|
|
;; mount
|
|
|
|
|
:else
|
2020-05-26 05:09:35 +00:00
|
|
|
(if-let [coercers (coercion/response-coercers coercion responses opts)]
|
2017-12-12 20:27:00 +00:00
|
|
|
(fn [handler]
|
|
|
|
|
(fn
|
|
|
|
|
([request]
|
|
|
|
|
(coercion/coerce-response coercers request (handler request)))
|
|
|
|
|
([request respond raise]
|
2020-05-26 05:09:35 +00:00
|
|
|
(handler request #(respond (coercion/coerce-response coercers request %)) raise))))
|
|
|
|
|
{})))})
|
2017-12-09 20:49:32 +00:00
|
|
|
|
|
|
|
|
(def coerce-exceptions-middleware
|
|
|
|
|
"Middleware for handling coercion exceptions.
|
|
|
|
|
Expects a :coercion of type `reitit.coercion/Coercion`
|
|
|
|
|
and :parameters or :responses from route data, otherwise does not mount."
|
2017-12-12 20:27:00 +00:00
|
|
|
{:name ::coerce-exceptions
|
|
|
|
|
:compile (fn [{:keys [coercion parameters responses]} _]
|
|
|
|
|
(if (and coercion (or parameters responses))
|
|
|
|
|
(fn [handler]
|
|
|
|
|
(fn
|
|
|
|
|
([request]
|
|
|
|
|
(try
|
|
|
|
|
(handler request)
|
|
|
|
|
(catch #?(:clj Exception :cljs js/Error) e
|
|
|
|
|
(handle-coercion-exception e identity #(throw %)))))
|
|
|
|
|
([request respond raise]
|
|
|
|
|
(try
|
|
|
|
|
(handler request respond #(handle-coercion-exception % respond raise))
|
|
|
|
|
(catch #?(:clj Exception :cljs js/Error) e
|
|
|
|
|
(handle-coercion-exception e respond raise))))))))})
|