Fix Malli encoding,, #498

This commit is contained in:
Tommi Reiman 2021-08-03 08:46:51 +03:00
parent 33afa9f999
commit 20b7cabed7
2 changed files with 59 additions and 14 deletions

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

@ -207,6 +207,24 @@
(let [{:keys [status]} (app invalid-request2)] (let [{:keys [status]} (app invalid-request2)]
(is (= 500 status)))))))) (is (= 500 status))))))))
(let [app (ring/ring-handler
(ring/router
["/plus" {:get {:parameters {:query [:map [:x :int]]}
:responses {200 {:body [:map
[:total [:int {:encode/json str
:min 0}]]]}}
: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}}))]
(app {:uri "/plus"
:request-method :get
:muuntaja/request {:format "application/json"}
:muuntaja/response {:format "application/json"}
:query-params {"x" "2"}}))
(deftest malli-coercion-test (deftest malli-coercion-test
(let [create (fn [middleware] (let [create (fn [middleware]
(ring/ring-handler (ring/ring-handler
@ -449,7 +467,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