From f26dc1ab19e1356861b8bdcfd243e2eb412bca20 Mon Sep 17 00:00:00 2001 From: Joel Kaasinen Date: Fri, 10 Oct 2025 08:48:40 +0300 Subject: [PATCH] feat: :default-values-for-optional-keys for malli coercion --- doc/coercion/malli_coercion.md | 9 ++++++-- .../src/reitit/coercion/malli.cljc | 9 ++++---- test/cljc/reitit/coercion_test.cljc | 21 +++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/doc/coercion/malli_coercion.md b/doc/coercion/malli_coercion.md index c7ecc34d..eb25b27c 100644 --- a/doc/coercion/malli_coercion.md +++ b/doc/coercion/malli_coercion.md @@ -73,9 +73,10 @@ Using `create` with options to create the coercion instead of `coercion`: {:transformers {:body {:default reitit.coercion.malli/default-transformer-provider :formats {"application/json" reitit.coercion.malli/json-transformer-provider}} :string {:default reitit.coercion.malli/string-transformer-provider} - :response {:default reitit.coercion.malli/default-transformer-provider}} + :response {:default reitit.coercion.malli/default-transformer-provider + :formats {"application/json" reitit.coercion.malli/json-transformer-provider}}} ;; 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} ;; support lite syntax? :lite true ;; schema identity function (default: close all map schemas) @@ -88,6 +89,10 @@ Using `create` with options to create the coercion instead of `coercion`: :strip-extra-keys true ;; add/set default values :default-values true + ;; add/set defaults also for optional keys. Corresponds to :malli.transform/add-optional-keys + :default-values-for-optional-keys false + ;; encode-error + :encode-error nil ;; malli options :options nil}) ``` diff --git a/modules/reitit-malli/src/reitit/coercion/malli.cljc b/modules/reitit-malli/src/reitit/coercion/malli.cljc index 813bbc20..568f605d 100644 --- a/modules/reitit-malli/src/reitit/coercion/malli.cljc +++ b/modules/reitit-malli/src/reitit/coercion/malli.cljc @@ -9,8 +9,7 @@ [malli.swagger :as swagger] [malli.transform :as mt] [malli.util :as mu] - [reitit.coercion :as coercion] - [clojure.string :as string])) + [reitit.coercion :as coercion])) ;; ;; coercion @@ -27,11 +26,11 @@ (defn- -provider [transformer] (reify TransformationProvider - (-transformer [_ {:keys [strip-extra-keys default-values]}] + (-transformer [_ {:keys [strip-extra-keys default-values default-values-for-optional-keys]}] (mt/transformer (if strip-extra-keys (mt/strip-extra-keys-transformer)) transformer - (if default-values (mt/default-value-transformer)))))) + (if default-values (mt/default-value-transformer {:malli.transform/add-optional-keys default-values-for-optional-keys})))))) (def string-transformer-provider (-provider (mt/string-transformer))) (def json-transformer-provider (-provider (mt/json-transformer))) @@ -118,6 +117,8 @@ :strip-extra-keys true ;; add/set default values :default-values true + ;; add/set defaults also for optional keys. Corresponds to :malli.transform/add-optional-keys + :default-values-for-optional-keys false ;; encode-error :encode-error nil ;; malli options diff --git a/test/cljc/reitit/coercion_test.cljc b/test/cljc/reitit/coercion_test.cljc index 0fcfd125..e1f0cd20 100644 --- a/test/cljc/reitit/coercion_test.cljc +++ b/test/cljc/reitit/coercion_test.cljc @@ -140,6 +140,27 @@ (let [m (r/match-by-path r "/none/kikka/abba")] (is (= nil (coercion/coerce! m)))))))) +(deftest malli-query-parameter-coercion-test + (let [router (fn [coercion] + (r/router ["/test" + {:coercion coercion + :parameters {:query [:map + [:a [:string {:default "a"}]] + [:x {:optional true} [:keyword {:default :a}]]]}}] + {:compile coercion/compile-request-coercers}))] + (testing "default values for :optional query keys do not get added" + (is (= {:query {:a "a"}} + (-> (r/match-by-path (router reitit.coercion.malli/coercion) "/test") + (assoc :query-params {}) + (coercion/coerce!))))) + (testing "default values for :optional query keys get added when :default-values-for-optional-keys is set" + (is (= {:query {:a "a" :x :a}} + (-> (r/match-by-path (router (reitit.coercion.malli/create + (assoc reitit.coercion.malli/default-options + :default-values-for-optional-keys true))) "/test") + (assoc :query-params {}) + (coercion/coerce!))))))) + (defn match-by-path-and-coerce! [router path] (if-let [match (r/match-by-path router path)] (assoc match :parameters (coercion/coerce! match))))