This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-26
Channels
- # aleph (9)
- # announcements (31)
- # babashka (23)
- # beginners (35)
- # biff (2)
- # calva (5)
- # cider (10)
- # clara (11)
- # clerk (114)
- # clj-kondo (18)
- # cljdoc (37)
- # clojars (7)
- # clojure (24)
- # clojure-austin (10)
- # clojure-europe (27)
- # clojure-nl (1)
- # clojure-norway (23)
- # clojure-uk (2)
- # clojurescript (18)
- # conjure (2)
- # core-async (6)
- # cursive (21)
- # datomic (3)
- # fulcro (15)
- # introduce-yourself (7)
- # lsp (32)
- # malli (57)
- # meander (5)
- # music (1)
- # nbb (2)
- # off-topic (17)
- # pathom (6)
- # rdf (4)
- # reagent (8)
- # releases (2)
- # shadow-cljs (4)
- # slack-help (23)
- # spacemacs (6)
- # tools-build (32)
mx/defn doesn’t grab metadata off the var, just from the metadata position, unless Im missing something. It’d be nice to pass metadata into it from the name, IMO.
> mx/defn doesn’t grab metadata off the var, just from the metadata position, unless Im missing something. It’d be nice to pass metadata into it from the name, IMO. I noticed that too. But, that’s how clojure works right? but I’m onboard of making mx/defn better. auto-type-hinting would require mapping from schemas to types, right?
One I just thought of is, using catn instead of cat so
[:=> [:cat :int :int] :int]
could become
[:=> [:catn [:a int] [:c int]] :int]
I am calling mg/generate — but I think there’s a way to use -strument to do the generation
from the function schema doc:
(def pow-gen
(m/-instrument
{:schema [:function
[:=> [:cat :int] [:int {:max 6}]]
[:=> [:cat :int :int] [:int {:max 6}]]]
:gen mg/generate}))
Yeah. Does that mapping exist already? It’s mostly trivial. One question is should we it let one add a custom typehint?
no such mappings yet. I have the schema-type -> type mapping in top of the backlog, e.g. int?
is a :int
. simplifies things like JSON Schema mappings would do it with (java/js) type hints too.
Hello, please how to add a custom generator? Cannot figure out: [:fn {:generator-fn #?(:clj #(Date.) :cljs #(js/Date.))} (fn [x] (instance? #?(:clj Date :cljs js/Date) x))]
search for :gen/gen
from the README (requires a generator, not sure if plain function is valid here.
@U04M0JEU88Z here's a little example of using a custom generator:
Thank you both for you replies. I have fortunately found clojure.core.inst? fn to be a better replacement for my case. Still not sure how to fix my previous trouble, but the answer can be probably found by studing clojure.test.check.generators and than using :gen/gen .
style/usage/architecture question: we're using Malli as internal schemas (instrumentation/documentation) and then also relying on the json schema transformation for input/output validation (our system has an older custom json schema builder, lol). Combined, this means our schemas are a little unwieldy and have a lot of repetition. For example, for a single POST foo endpoint, we have
• NewFoo schema
• post-foo-payload
which is the json schema transformation of the NewFoo schema
• private post-foo-decoder
which is standalone to get speed from m/decoder
• decode-foo-params
that uses post-foo-decoder
to decode the payload
• PostFooResponse schema (which is thankfully just (mu/assoc NewFood :extra-key :uuid)
)
• private post-foo-response-encoder
which is standalone to get speed from m/encoder
• encode-post-foo-response
that uses post-foo-response-encoder
to do the final-step encoding/extra key stripping before calling (compojure/response resp)
• and finally post-foo-response
which is the json schema transformation of the PostFooResponse schema
That's a lot and some of it comes from using Malli to generate json schema schemas, I know, but there's still a fair amount of boilerplate happening. Does anyone have ideas for how to lessen the code footprint for situations like this?
if that is all for a single POST, It’s a lot. There are two good ways to organize schemas:
1. Vars
a. like plumatic, (def NewFoo (m/schema …))
b. simple, usually non-qualified keys
2. Global Registry
a. like spec, description here: https://github.com/metosin/malli#mutable-registry
b. mutable = evil, qualified keys.
for serving requests over web, the boilerplate of dealing with optimized encoders & decoders can be pushed into frameworks, e.g. reitit + malli here: https://github.com/metosin/reitit/blob/master/examples/ring-malli-swagger/src/example/server.clj#L57-L81.
btw, nowadays malli caches automatically validators, explainers and generators but NOT transformers. so this is almost as fast as manually creating a validator:
(def Foo (m/schema [:map [:x :int]]))
;; caches the validator on first invocation into schema instance
(m/validate Foo {:x 1})
> nowadays malli caches automatically validators, explainers and generators Really? That's great news. > can be pushed into frameworks that's what our json schema is meant to handle, but switching over entirely to malli is long and hard and there's no desire to move off of compojure, so right now i'm stuck carving out a small corner of sanity in the much larger code base.
> • private post-foo-decoder
which is standalone to get speed from m/decoder
> • decode-foo-params
that uses post-foo-decoder
to decode the payload
I've usually created closed over functions that internally create the decoder.
(def decode-foo-params [..] (let [decoder (..)] (fn [..] (decoder ...))
I've also created orchestration functions that deal with the repetitions of an operation (and you can more declaratively just pass in a map of {:my-schema ,, :post-decoder-fn ,,, :etc}
)
Arne also had a talk about data-driven malli which I think can serve as inspiration on how to generate more of this stuff based on some initial schemas. https://www.youtube.com/watch?v=ww9yR_rbgQs
very cool, thanks for the talk. watching it now
If you care about performance then you should consider dropping compojure, otherwise you can borrow the coercion middlewares from reitit
hah I would love to drop compojure. getting organizational buy-in is quite challenging, sadly
Hello, is there a way and example how to define Malli schema for functions with optional named arguments like this:
(defn my-named-args-fn [& {:keys [x y z]}]
(println x y z))
(my-named-args-fn :x 1 :y 2)
no simple built-in for that, but:
(defn my-named-args-fn [& {:keys [x y z]}]
(println x y z))
(malli.destructure/infer #'my-named-args-fn)
;[:=>
; [:cat
; [:altn
; [:map [:map
; [:x {:optional true} :any]
; [:y {:optional true} :any]
; [:z {:optional true} :any]]]
; [:args [:* [:alt
; [:cat [:= :x] :any]
; [:cat [:= :y] :any]
; [:cat [:= :z] :any] [:cat :any :any]]]]]]
; :any]
should that be an :or
? maybe I don't remember how that destructuring works
to add, if you use mx/defn on that shape, the destructuring schema will be inferred. ( I think ).
(require '[malli.experimental :as mx])
(mx/defn my-named-args-fn [& {:keys [x y z]}]
(println x y z))
(:schema (meta #'my-named-args-fn))
;; => [:=>
;; => [:cat
;; => [:altn
;; => [:map
;; => [:map
;; => [:x {:optional true} :any]
;; => [:y {:optional true} :any]
;; => [:z {:optional true} :any]]]
;; => [:args
;; => [:* [:alt
;; => [:cat [:= :x] :any]
;; => [:cat [:= :y] :any]
;; => [:cat [:= :z] :any] [:cat :any :any]]]]]]
;; => :any]
@UEENNMX0T :alt
& :altn
are the or for sequences. That should work ok.
btw, like with mostly everything else in malli, you can configure the dest inferring with options, “closed map with required keys”:
(md/infer #'my-named-args-fn {::md/closed-maps true, ::md/required-keys true})
;[:=>
; [:cat
; [:altn
; [:map [:map {:closed true}
; [:x :any]
; [:y :any]
; [:z :any]]]
; [:args [:* [:alt
; [:cat [:= :x] :any]
; [:cat [:= :y] :any]
; [:cat [:= :z] :any]]]]]]
; :any]
it would be easy to build a custom schema to cover the both cases (map or varargs), e.g.:
[:=>
[:cat
[:kvmap
[:x :any]
[:y :any]
[:z :any]]]
:any]
… that would work the same. haven’t needed so it’s not there yet.Thanks a lot. I will play with that and would like to create a fn to simplify the declaration.
I have some namespaces that use :malli/schema
function metadata, with (m.inst/collect!)
as the final line in each namespace. That stopped working in 0.9.0:
Syntax error (ClassNotFoundException) compiling at (me/foo.clj:180:1).
me.foo
Was this ever intended to work?@U055NJ5CC I don't see anything about this in the 0.9 changelog. Should I whip up a full repro? I'd thought there were others doing this, but maybe I'm the only one?
works here ok :thinking_face:
(ns demo)
(defn plus
"adds two numbers together"
{:malli/schema [:=> [:cat :int :int] :int]}
[z y]
(+ z y))
(require '[malli.instrument])
(malli.instrument/collect! {:ns 'demo})
;#{{:clj {demo {plus {:schema [:=> [:cat :int :int] :int]
; :ns demo, :name plus}}}}}
For what it's worth: I'm having the same problem. Did you find out what was the matter @U01R1SXCAUX?
To be clear:
• (mi/collect!)
does not work
• (mi/collect! {:ns 'demo})
does
Upon closer inspection, the 0-arity call defaults to using *ns*
as namespace. In my case its value was different from what I expected during my REPL session. Maybe the same for you Michael.
thank you!
Hi,
I'm looking for component/solution where I can transform malli
schema to clerk
to document the schema/spec in html format... This is just a start but ultimate need is to convert it to something I can publish in confluent wiki
Thank you @U055NJ5CC