Fork me on GitHub
#malli
<
2022-02-11
>
jeroenvandijk08:02:32

Looks useful! - a small step for people acquinted with Plumatic Schema to try Malli - offers potentially a soft migration path from Schema to Malli. Assuming enough/all Schema predicates will be covered - extend existing Schema code bases with the power of Malli (I believe :multi will have better error reporting than schema.core/either for instance). This again assumes that the translation of Schema will be near to perfect

πŸ‘ 2
ikitommi08:02:06

(require '[malli.experimental.lite :as l])

(def Schema
  (l/schema
   {:map1 {:x int?
           :y [:maybe string?]
           :z (l/maybe keyword?)}
    :map2 {:min-max [:int {:min 0 :max 10}]
           :tuples (l/vector (l/tuple int? string?))
           :optional (l/optional (l/maybe :boolean))
           :set-of-maps (l/set {:e int?
                                :f string?})
           :map-of-int (l/map-of int? {:s string?})}}))
;[:map
; [:map1
;  [:map
;   [:x int?]
;   [:y [:maybe string?]]
;   [:z [:maybe keyword?]]]]
; [:map2
;  [:map
;   [:min-max [:int {:min 0, :max 10}]]
;   [:tuples [:vector [:tuple int? string?]]]
;   [:optional {:optional true} [:maybe :boolean]]

ikitommi08:02:55

18 lines of optional sugar, for simple cases like defining route parameters with reitit.

πŸ‘ 2
jeroenvandijk08:02:53

I can imagine this dsl would not cover complex cases of Malli, but sure looks useful to remove some boilerplate. Maybe it becomes confusing if these way of schema writing get mixed, not sure

ikitommi08:02:54

yes, I would. not use this for anything β€œnormal”, but for specific / inline cases, good: default reitit+malli:

:parameters {:query [:map 
                     [:x int?]
                     [:y {:optional true} string?]]}
adding reitit+malli support for lite too:
:parameters {:query {:x int?, :y (l/optional string?)}}

jeroenvandijk09:02:42

I wanted to say maybe instead of supporting lite directly, asking the user to use to dsl themselves might lead to less confusion. But I see malli can go into malli-lite and malli-lite can go into malli :)

:parameters {:query {:x int?, :y (l/optional [:map-of string? string?]]}
Generates a valid malli schema, and also the other way around:
:parameters {:query [:map 
                     [:x int?]
                     [:y {:optional true} (map-of string? string?]]}
Nice πŸ’ͺ

jeroenvandijk09:02:58

So that actually means complex cases are also covered, because normal malli can be used where necessary?

ikitommi09:02:45

yes.

πŸ‘Œ 1
ikitommi14:02:23

malli.experimental.lite now merged in master.

ikitommi17:02:53

not sure how this relates to malli, but πŸ‘

Ben Sless17:02:24

mostly, thinking about a good way to bring this together with malli, hopefully finding a lossless translation between the two. AsyncAPI looks like a very interesting way to solve the "schema problem" at an organizational level + all the metadata I would have had to reinvent the wheel to specify, which could go beyond interfacing with malli, but further code generation. You could derive reitit routes from it, and more

Brett Rowberry15:02:24

Today, when humanizing a value against a map schema, the error message "invalid type" isn't super useful. I know I can add a custom error message. How could it be more descriptive?

(malli.error/humanize (malli.core/explain [:map] "string"))
;; => ["invalid type"]

Brett Rowberry22:02:31

Right, I know I can do that for a given schema, but wondered if maybe all maps could say something more specific.

ikitommi11:02:30

You can override the default error for invalid type, using options to me/humanize.

ikitommi11:02:13

there should be an example behind the link..

dvingo12:02:44

oh woops sorry @U021RHDFFHN overlooked that you said that. I learned something, just tried this out and it works:

(malli.error/humanize
    (malli.core/explain [:map] "string")
    {:errors (-> default-errors
               (assoc ::m/invalid-type
                      {:error/fn (fn [{:keys [value schema] :as in} _]
                                   (str "The value you provided: '" value "' is not the correct type for the schema: '" (m/form schema) "'"))}))})
=> ["The value you provided: \"string\" is not the correct type for the schema: ':map'"]

πŸ‘ 1
ikitommi17:02:55

the (m/form schema) could be (m/type schema), just report on type, not whole form. otherwise, πŸ’―

πŸ‘ 1
Brett Rowberry18:02:59

Thanks! This works best for my use case:

(malli.error/humanize (malli.core/explain [:map] nil))
;; => ["invalid type"]

(malli.error/humanize
 (malli.core/explain [:map [:hi string?]] nil)
 {:errors (-> malli.error/default-errors
              (assoc ::m/invalid-type
                     {:error/fn (fn [{:keys [_value schema]} _]
                                  (str "The value provided does not conform to schema: '" (m/form #_m/type schema) "'"))}))})
;; => ["The value provided does not conform to schema: '[:map [:hi string?]]'"]