malli 2025-06-02

Anyone dealt with coercion on multi malli schema where the dispatch value is supposed to be coerced into a keyword? I'm trying to keep my schema serializable (i.e. no function defintions). E.g. I'm getting a invalid dispatch value here:

(require '[malli.core :as malli]
         '[malli.transform :as malli-transform])

(malli/coerce [:multi {:dispatch :type}
               [:a [:map [:type [:enum :a]]]]
               [:b [:map [:type [:enum :b]]]]]
              {:type "a"}
              (malli-transform/transformer
               malli-transform/string-transformer))
I could explicitly update the value to keyword but that'll require an explicit middleware for my server which would probably be too explicit. Any ideas on how to circumvent this?

IIRC :decode/string from :multi schema level would be applied before multi dispatch [:multi {:decode/string (fn [s] (keyword s)) :dispatch ...} ...]

Or maybe something like [:and [:map [:type :keyword]] [:multi ...]] so Malli knows before selecting the multi schema that the type property has to be coerced

Usually :decode/string is the correct choice to apply per-property coercion where the property requires special coercion or the coercion needs to be done before Malli knows the "real" schema for the property (like with :multi)

Yeah dispatching with a fn would work but it won't be serializable anymore. I'll just use strings

The :and might work

but it is an additional dependency

And hm, https://github.com/metosin/malli?tab=readme-ov-file#serializable-functions, these example are for :fn schema functions, not sure if fns in schema properties, like :decode/string work the same

But :and version is likely the most "schema as data" approach for this

💯 1

Thanks! I'll try out the :and approach and see if that helps

(require '[malli.core :as malli]
         '[malli.transform :as malli-transform])

(malli/coerce [:and [:map [:type :keyword]] [:multi {:dispatch :type}
                                            [:a [:map [:type [:enum :a]]]]
                                            [:b [:map [:type [:enum :b]]]]]]
              {:type "a"}
              (malli-transform/transformer
               malli-transform/string-transformer))
Works

🎉 1

it’s probably not “the way” but you can hack it by making the dispatch function turn strings into keywords with (comp keyword :type).