-
Notifications
You must be signed in to change notification settings - Fork 150
/
Copy pathschema.clj
88 lines (74 loc) · 2.89 KB
/
schema.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
(ns compojure.api.coercion.schema
(:require [schema.coerce :as sc]
[schema.utils :as su]
[ring.swagger.coerce :as coerce]
[compojure.api.coercion.core :as cc]
[clojure.walk :as walk]
[schema.core :as s]
[compojure.api.common :as common]
;; side effects
compojure.api.coercion.register-schema)
(:import (java.io File)
(schema.core OptionalKey RequiredKey)
(schema.utils ValidationError NamedError)))
(def string-coercion-matcher coerce/query-schema-coercion-matcher)
(def json-coercion-matcher coerce/json-schema-coercion-matcher)
(defn stringify
"Stringifies Schema records recursively."
[error]
(walk/prewalk
(fn [x]
(cond
(class? x) (.getName ^Class x)
(instance? OptionalKey x) (pr-str (list 'opt (:k x)))
(instance? RequiredKey x) (pr-str (list 'req (:k x)))
(and (satisfies? s/Schema x) (record? x)) (try (pr-str (s/explain x)) (catch Exception _ x))
(instance? ValidationError x) (str (su/validation-error-explain x))
(instance? NamedError x) (str (su/named-error-explain x))
:else x))
error))
(def memoized-coercer
(common/fifo-memoize sc/coercer 1000))
;; don't use coercion for certain types
(defmulti coerce-response? identity :default ::default)
(defmethod coerce-response? ::default [_] true)
(defmethod coerce-response? File [_] false)
(defrecord SchemaCoercion [name options]
cc/Coercion
(get-name [_] name)
(get-apidocs [_ _ data] data)
(make-open [_ schema]
(if (map? schema)
(assoc schema s/Keyword s/Any)
schema))
(encode-error [_ error]
(-> error
(update :schema pr-str)
(update :errors stringify)))
(coerce-request [_ schema value type format request]
(let [type-options (options type)]
(if-let [matcher (or (get (get type-options :formats) format)
(get type-options :default))]
(let [coerce (memoized-coercer schema matcher)
coerced (coerce value)]
(if (su/error? coerced)
(let [errors (su/error-val coerced)]
(cc/map->CoercionError
{:schema schema
:errors errors}))
coerced))
value)))
(accept-response? [_ model]
(coerce-response? model))
(coerce-response [this schema value type format request]
(cc/coerce-request this schema value type format request)))
(def default-options
{:body {:default (constantly nil)
:formats {"application/json" json-coercion-matcher
"application/msgpack" json-coercion-matcher
"application/x-yaml" json-coercion-matcher}}
:string {:default string-coercion-matcher}
:response {:default (constantly nil)}})
(defn create-coercion [options]
(->SchemaCoercion :schema options))
(def default-coercion (create-coercion default-options))