This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-28
Channels
- # announcements (1)
- # beginners (43)
- # calva (7)
- # clojure (48)
- # clojure-europe (19)
- # clojure-nl (1)
- # clojure-norway (24)
- # clojure-uk (4)
- # clojuredesign-podcast (4)
- # clojurescript (11)
- # conjure (15)
- # core-async (1)
- # cursive (1)
- # datomic (33)
- # events (1)
- # fulcro (2)
- # humbleui (21)
- # hyperfiddle (34)
- # introduce-yourself (1)
- # joyride (24)
- # lambdaisland (8)
- # lsp (3)
- # malli (30)
- # meander (2)
- # observability (5)
- # off-topic (2)
- # pathom (3)
- # polylith (26)
- # portal (5)
- # re-frame (28)
- # shadow-cljs (7)
- # spacemacs (2)
- # xtdb (6)
Hello what would be your general tips to making schemas with malli? I've successfully made a few map schemas but i'm struggling to use them effectively as I get a "invalid-type" validation errors with large schema files and large values inserted to those. Making it difficult and slow to actually track down what went wrong. Adding a custom error to these only drops the entire schema and entire value into the error, nothing mory. Do you have any specific tips on how to structure the schema to get as accurate error messages as possible? My current schema is a map contain vectors, containing maps up to 5 levels. It's all defined as a single entity with the vector syntax alone, no registry.
FWIW it's not just you, this is an area for growth for malli. Some ideas with that in mind:
You might want to https://github.com/metosin/malli/blob/875caae5ecbeecbe32d40af53c0732bec717f70a/src/malli/error.cljc#L29 the default invalid-type
error message to be more specific.
e.g., https://github.com/fluree/db/commit/4ff41ae12fe5588b0e64da93ff45ea14d72499cc#diff-5b7e602fc7bc937648bce72499d1c9c24ead635bf2e72468c224769b43f9263aR212-R219
::m/invalid-type
{:error/fn (fn [{:keys [schema value]} _]
(if-let [expected-type (-> schema m/type)]
(str "should be a " (case expected-type
(:map-of :map) "map"
(:cat :catn :sequential) "sequence"
:else (name type)))
(str "type of " (pr-str value) " does not match expected type")))}
Use :multi
instead of :or
.agree, the default error is bad, should be easy to make better as Ambrose pointed out 🙂
I just wanted to make sure I'm not doing something stupid. Is there a simpler way to require that fields are set, but only if one specific field is set to true?
[:multi {:dispatch :x}
[true [:map [:x :boolean]
[:y :int]]]
[::m/default [:map [:x {:optional true} [:maybe :boolean]]
[:y {:optional true} [:maybe :int]]]]]
the alternative would be something like [:or big-map another-big-map]
and a lot of time would be spent figuring out which schema to use.
Using :or gave worse results for the errors with explain (and reitit's coercer). It would generate errors for both branches, which in the case of the coercer merged into a single set of humanized errors without the full path identifying the branch.
declarative key/value relations are not simple, here is one try: https://github.com/bsless/malli-keys-relations
> (malli.generator/generate [:map [:success? {:gen/return true} boolean?]])
{:success? false}
Looks like :gen/return
isn't doing what I want to here - suggestions?Hey there 👋 I had tried this variation as well, inspired by the readme
> (malli.generator/generate [:map [:success? [:and {:gen/return true} boolean?]]])
{:success? false}
Unrelated, lately I've been really wanting a Schema
-style zero-cost defprotocol
for Malli. Maybe one day I'll find the time.
Yes, I think I told you that I was working on a common library extracting out the implementation details of s/defprotocol
.
I got stuck, just made it public, maybe you'll find it inspiring? https://github.com/frenchy64/instrument-defprotocol
Pretty rough, unreleased, but it at least separates out the main ideas of what's needed to instrument protocols visually. I think if you read https://github.com/frenchy64/instrument-defprotocol/blob/main/src/com/ambrosebs/instrument_defprotocol/clj.clj file you should get a good idea of what's involved. IIRC I found it difficult to decide how leaky I wanted to make the abstraction, because there were performance benefits for being more flexible but also potentially it made it easier to shoot yourself in the foot.
Did the Schema impl play out nicely long term? Perhaps I'd be better off with a non-generic solution
Works on the latest Clojure master based on the cron CI. Not sure if I test the latest CLJS though.
Thanks! Hope I can hack something with it this year. Should be pretty low-risk as one can always replace custom/defprotocol
with defprotocol
- nothing else should be adapted
@U45T93RA6 hm, which version of malli were you using with :gen/return
?