Data Validation in Clojure

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.
Subscribe to my newsletter
Read articles from Toni Väisänen directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Toni Väisänen
Toni Väisänen
Software engineer @ Metosin Ltd Need help with a project, contact: first.last@metosin.com As a 𝐜𝐨𝐧𝐬𝐮𝐥𝐭𝐚𝐧𝐭, I help clients find technical solutions to their business problems and facilitate communication between the stakeholders and the technical team. As a 𝐟𝐮𝐥𝐥-𝐬𝐭𝐚𝐜𝐤 𝐝𝐞𝐯𝐞𝐥𝐨𝐩𝐞𝐫, I build technical solutions for client's problems from user interfaces, and backend services to infrastructure-as-code solutions. As a 𝐦𝐚𝐜𝐡𝐢𝐧𝐞 𝐥𝐞𝐚𝐫𝐧𝐢𝐧𝐠 𝐞𝐧𝐠𝐢𝐧𝐞𝐞𝐫, I create, validate and deploy predictive models.