|
13 | 13 | [schema.core :as s]
|
14 | 14 | [schema.coerce :as sc]
|
15 | 15 | [schema.utils :as su]
|
16 |
| - [schema-tools.core :as st])) |
| 16 | + [schema-tools.core :as st] |
| 17 | + [linked.core :as linked] |
| 18 | + [compojure.api.impl.logging :as logging])) |
17 | 19 |
|
18 | 20 | ;;
|
19 | 21 | ;; Meta Evil
|
|
27 | 29 | "lexically bound meta-data for handlers."
|
28 | 30 | '+compojure-api-meta+)
|
29 | 31 |
|
| 32 | +(def +compojure-api-coercer+ |
| 33 | + "lexically bound (caching) coercer for handlers." |
| 34 | + '+compojure-api-coercer+) |
| 35 | + |
30 | 36 | (defmacro meta-container [meta & form]
|
31 | 37 | `(let [accumulated-meta# (get-local +compojure-api-meta+)
|
32 | 38 | ~'+compojure-api-meta+ (deep-merge accumulated-meta# ~meta)]
|
|
47 | 53 | ;; Schema
|
48 | 54 | ;;
|
49 | 55 |
|
50 |
| -(def memoized-coercer (memoize sc/coercer)) |
| 56 | +(defn memoized-coercer |
| 57 | + "Returns a memoized version of a referentially transparent coercer fn. The |
| 58 | + memoized version of the function keeps a cache of the mapping from arguments |
| 59 | + to results and, when calls with the same arguments are repeated often, has |
| 60 | + higher performance at the expense of higher memory use. FIFO with 100 entries. |
| 61 | + Cache will be filled if anonymous coercers are used (does not match the cache)" |
| 62 | + [] |
| 63 | + (let [cache (atom (linked/map)) |
| 64 | + cache-size 100] |
| 65 | + (fn [& args] |
| 66 | + (or (@cache args) |
| 67 | + (let [coercer (apply sc/coercer args)] |
| 68 | + (swap! cache (fn [mem] |
| 69 | + (let [mem (assoc mem args coercer)] |
| 70 | + (if (>= (count mem) cache-size) |
| 71 | + (dissoc mem (-> mem first first)) |
| 72 | + mem)))) |
| 73 | + coercer))))) |
51 | 74 |
|
52 | 75 | (defn strict [schema]
|
53 | 76 | (dissoc schema 'schema.core/Keyword))
|
|
57 | 80 | (fnk-impl/letk-input-schema-and-body-form
|
58 | 81 | nil (with-meta bind {:schema s/Any}) [] nil)))
|
59 | 82 |
|
60 |
| -(defn body-coercer-middleware [handler responses] |
| 83 | +(defn body-coercer-middleware [handler coercer responses] |
61 | 84 | (fn [request]
|
62 | 85 | (if-let [{:keys [status] :as response} (handler request)]
|
63 | 86 | (if-let [schema (:schema (responses status))]
|
64 | 87 | (if-let [matcher (:response (mw/get-coercion-matcher-provider request))]
|
65 |
| - (let [coerce (memoized-coercer (value-of schema) matcher) |
| 88 | + (let [coerce (coercer (value-of schema) matcher) |
66 | 89 | body (coerce (:body response))]
|
67 | 90 | (if (su/error? body)
|
68 | 91 | (throw+ (assoc body :type ::ex/response-validation))
|
|
79 | 102 | (assert (not (#{:query :json} type)) (str type " is DEPRECATED since 0.22.0. Use :body or :string instead."))
|
80 | 103 | `(let [value# (keywordize-keys (~key ~+compojure-api-request+))]
|
81 | 104 | (if-let [matcher# (~type (mw/get-coercion-matcher-provider ~+compojure-api-request+))]
|
82 |
| - (let [coerce# (memoized-coercer ~schema matcher#) |
| 105 | + (let [coerce# (~+compojure-api-coercer+ ~schema matcher#) |
83 | 106 | result# (coerce# value#)]
|
84 | 107 | (if (su/error? result#)
|
85 | 108 | (throw+ (assoc result# :type ::ex/request-validation))
|
|
116 | 139 |
|
117 | 140 | (defmulti restructure-param
|
118 | 141 | "Restructures a key value pair in smart routes. By default the key
|
119 |
| - is consumed form the :parameters map in acc. k = given key, v = value." |
| 142 | + is consumed form the :parameters map in acc. k = given key, v = value." |
120 | 143 | (fn [k v acc] k))
|
121 | 144 |
|
122 | 145 | ;;
|
|
337 | 360 | (map-of lets letks responses middlewares parameters body)
|
338 | 361 | parameters)
|
339 | 362 |
|
| 363 | + pre-lets [+compojure-api-coercer+ `(memoized-coercer)] |
| 364 | + |
340 | 365 | body `(~body-wrap ~@body)
|
341 | 366 | body (if (seq letks) `(letk ~letks ~body) body)
|
342 | 367 | body (if (seq lets) `(let ~lets ~body) body)
|
343 | 368 | body (if (seq middlewares) `(route-middlewares ~middlewares ~body ~arg) body)
|
344 | 369 | body (if (seq parameters) `(meta-container ~parameters ~body) body)
|
345 | 370 | body `(~method-symbol ~path ~arg-with-request ~body)
|
346 |
| - body (if responses `(body-coercer-middleware ~body ~responses) body)] |
| 371 | + body (if responses `(body-coercer-middleware ~body ~+compojure-api-coercer+ ~responses) body) |
| 372 | + body (if (seq pre-lets) `(let ~pre-lets ~body) body)] |
347 | 373 | body))
|
0 commit comments