Malli

Malli is popular for web APIs (used by Reitit for request/response coercion), with JSON Schema/OpenAPI export, schema registries, and good performance. Alternatives: spec, Plumatic Schema.

(require '[malli.core :as m]
         '[malli.error :as me]
         '[malli.generator :as mg]
         '[malli.transform :as mt])

;; Schemas are data
(def User
  [:map
   [:id :uuid]
   [:name [:string {:min 1}]]
   [:age [:int {:min 0 :max 150}]]
   [:email {:optional true} [:re #".+@.+\..+"]]
   [:roles [:set [:enum :admin :editor :viewer]]]])

(m/validate User {:id (random-uuid) :name "Ana" :age 30 :roles #{:admin}})   ; true
(-> (m/explain User {:id 1 :name "" :age -1 :roles #{}})
    (me/humanize))
;; {:id ["should be a uuid"], :name ["should be at least 1 character"], :age ["should be at least 0"]}

;; Coercion (e.g., from JSON/HTTP strings)
(m/decode [:map [:age :int]] {:age "42"} mt/string-transformer)   ; {:age 42}

;; Generation
(mg/generate User)

;; Function schemas
(def add-schema [:=> [:cat :int :int] :int])
(m/validate add-schema +)                   ; validates function schemas via generative testing