Fork me on GitHub


馃帀 9

Fantastic! Going to try these out now!



what a brilliant/horrible idea: add optional :object schema, which allows maps to be described using clojure maps. Kinda like data-specs but for malli:

 {"name" [:required :string]
  "age" [:required :number :positive :integer]
  "email" [:string :email]
  "website" [:string :url]
  "createdOn" [[:date {:default "2020-18-10"}]]
  "address" [:object
             {"street" [[:string {:min 1}]]
              "zip" [:int]}]}]



 {"name" [:and :required :string]
  "age" [:and :required :number :positive :integer]
  "email" [:and :string :email]
  "website" [:and :string :url]
  "createdOn" [:date {:default "2020-18-10"}]
  "address" {:street [:string {:min 1}]
             :zip :int}}]


a bit like Schema, but more EDN-like


鈽濓笍. simple formats like Schema and data-spec are kinda easy, but not simple: the core utilties (`select-keys`, assoc etc.) almost work, unless you have a wrapper for keys like ds/opt or s/optional-key in case they don鈥檛. Also, value wrappers are needed to add visible properties/meta-data to schemas. And there is no order for keys. But, super nice for many things like defining inlined route parameters:

 {:get {:summary "plus with spec query parameters"
        :parameters {:query {:x int?, :y int?}}
        :responses {200 {:body {:total int?}}}
        :handler handle-plus}]


if there was a litemalli coercion in reitit, one could swap the data-spec apps almost 1:1 to it.


I prefer #1 to #2; the latter is making nested map notation implicit and special for :object and I don't know if it's worth it.


That reitit example could just as easily be solved by a utility function that takes the concise nested map notation and converts it to a tree of :object

馃憤 3

someone should write malli-tools ;)




Does :object offer different semantics or tradeoffs than :map? Or would it deref/merge down to a :map schema? Or would we have two things that are the same but different? :]


To be clear, I prefer writing the map notation and was always confused why :map used vectors; but that ship has sailed... or has it?


we're in a dynlang, we can do everything we want ;)


I'm thinking :object could be just a nice alternative syntax that would "compile down" to a :map. But maybe I'm just missing the point. :)


why it is called object though?


like JavaScript object?


I was thinking like: wow, is this a schema to describe Java objects like bean-stuff?


anyone not working on front-ends might think the same

鈽濓笍 3

vector syntax for :map allows simple way to define properties for it and retains the order of keys. But yes, we can add more schemas to build things in different ways. Could have also optional :`json-schema` that allows any JSON Schema in it etc.


the name could be anything, just flushing stuff from my brain (after a vacation).


IMO, it would be confusing to see both :map and :object somewhere in my system output and they were semantically the same thing (a representation of known key-value mapping); so the way I see it: 1. if we want an alternative writing notation, why not just make it a utility function? (instead of introducing a new kind of schema) 2. if we want an alternative notation that is a data-literal (utility functions need runtime support), then we could introduce an alternative name (like :object ); but it could just as easily be :kv or :map2 ; or even why not extend existing :map to support both kinds of notations (vectors or maps) 3. if this is something similar to :map but offers possibly different semantics, than currently those semantics aren't clear to me; otherwise it'd be great if we didn't have two things that represent essentially the same thing (this would make merging, etc. more complicated to deal with later on)


(This is also why I like having :map and :map-of , because they represent different semantics; even though they are using the same internal datastructure)


Related to 2, I think they should be kept separate (if implemented). If :map supported both syntax, there would be ambiguity issues:

 {:id :int
  :title :string}]
is that empty map with props? or map with no props but with keys?


If I would implement that today, it would be a separate ns, malli.object etc, with a Schema impl, a helper and a extra registry snipplet so one can merge the schemas into a registry easily:

(require '[malli.core :as m])
(require '[malli.object :as mo])

(def registry (merge (m/default-schemas) (mo/schemas)))

   {:id int?
    :address [:object {:street string?}]}]
  {:registry registry})