Data Validation in Clojure

Toni VäisänenToni Väisänen
2 min read

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.

0
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.