Malli is a data-driven schema Clojure library for defining types and validating data. It can be used for example to:
type check data when received from untrusted sources i.e. validate that HTTP request bodies before writing to the database
define domain entities as code and generate UML diagrams
generate clj-kondo types for static type checking in editors.
Malli uses hiccup-inspired vector syntax for defining types. There's also a map syntax variant but the use case for that is to be used as an internal library representation. The vector syntax looks like this.
(def Todo
[:map
[:id :int]
[:author :string]
[:created inst?]
[:status [:enum :todo :doing :done]]])
Here we have a "Todo" schema that represents a map with properties: id, author, created, and status. Each child of the map vector defines a property, meaning the property :id
is a type of :int
and :created
is a type of instant
and so on. All of these properties can be validated separately.
(malli.core/validate :int 1)
;; => true
(malli.core/validate :int "1")
;; => false
(malli.core/validate inst? (java.time.Instant/now))
;; => true
(malli.core/validate [:enum :todo :doing :done] :done)
;; => true
Or as a whole.
(malli.core/validate Todo
{:id 1
:author "Toni"
:created #inst "2023-09-30"
:status :todo})
;; => true
In the case that the data is not valid we probably want to know the details on why so. For this, we can use malli.core/explain
and malli.error/humanize
.
(def invalid-todo
{:id 1
:author "Toni"
:created "not-an-instant"
:status :todo})
(malli.core/validate Todo invalid-todo)
;; => false
(:errors (malli.core/explain Todo invalid-todo))
;; =>
({:path [:created],
:in [:created],
:schema inst?,
:value "not-an-instant"})
(malli.error/humanize
(malli.core/explain Todo invalid-todo))
;; =>
{:created ["should be an inst"]}
The error messages can be customized and internationalized to fit your needs. Malli has a lot more features to offer, so I encourage you to go through the documentation to learn more.
Thank you for reading, I hope you found this useful. Please let me know if there's some specific Malli feature that you would like to know more about.