reitit/doc/coercion/malli_coercion.md
Juho Teperi 0ca4fce984 Add test-doc-blocks
I suspected the malli coercion custom registry example was broken, so I
wanted to get it tested and the coercion Malli options indeed had an
extra layer of map.
2026-02-09 14:18:14 +02:00

127 lines
3.9 KiB
Markdown

# Malli Coercion
[Malli](https://github.com/metosin/malli) is data-driven Schema library for Clojure/Script.
## Default Syntax
By default, [Vector Syntax](https://github.com/metosin/malli#vector-syntax) is used:
```clj
(require '[reitit.coercion.malli])
(require '[reitit.coercion :as coercion])
(require '[reitit.core :as r])
(def router
(r/router
["/:company/users/:user-id" {:name :user/user-view
:coercion reitit.coercion.malli/coercion
:parameters {:path [:map
[:company string?]
[:user-id int?]]}}]
{:compile coercion/compile-request-coercers}))
(defn match-by-path-and-coerce! [path]
(if-let [match (r/match-by-path router path)]
(assoc match :parameters (coercion/coerce! match))))
```
Successful coercion:
```clj
(-> (into {} (match-by-path-and-coerce! "/metosin/users/123"))
(dissoc :result :data))
;; => {:template "/:company/users/:user-id",
;; :path-params {:company "metosin", :user-id "123"},
;; :parameters {:path {:company "metosin", :user-id 123}}
;; :path "/metosin/users/123"}
```
Failing coercion:
```clj
(try
(match-by-path-and-coerce! "/metosin/users/ikitommi")
(catch clojure.lang.ExceptionInfo e (.getMessage e)))
;; => "Request coercion failed"
```
## Lite Syntax
Same using [Lite Syntax](https://github.com/metosin/malli#lite):
```clj
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.malli/coercion
:parameters {:path {:company string?
:user-id int?}}}]
{:compile coercion/compile-request-coercers}))
```
## Configuring coercion
Using `create` with options to create the coercion instead of `coercion`:
```clj
(require '[malli.util :as mu])
(reitit.coercion.malli/create
{:transformers {:body {:default reitit.coercion.malli/default-transformer-provider
:formats {"application/json" reitit.coercion.malli/json-transformer-provider}}
:string {:default reitit.coercion.malli/string-transformer-provider}
:response {:default reitit.coercion.malli/default-transformer-provider
:formats {"application/json" reitit.coercion.malli/json-transformer-provider}}}
;; set of keys to include in error messages
:error-keys #{:type :coercion :in #_:schema :value #_:errors :humanized #_:transformed}
;; support lite syntax?
:lite true
;; schema identity function (default: close all map schemas)
:compile mu/closed-schema
;; validate request & response
:validate true
;; top-level short-circuit to disable request & response coercion
:enabled true
;; strip-extra-keys (affects only predefined transformers)
:strip-extra-keys true
;; add/set default values
;; Can be false, true or a map of options to pass to malli.transform/default-value-transformer,
;; for example {:malli.transform/add-optional-keys true}
:default-values true
;; encode-error
:encode-error nil
;; malli options
:options nil})
```
## Configuring humanize error messages
Malli humanized error messages can be configured using `:options :errors`:
```clj
(reitit.coercion.malli/create
{:options
{:errors (assoc malli.error/default-errors
:malli.core/missing-key {:error/message {:en "MISSING"}})}})
```
See the malli docs for more info.
## Custom registry
Malli registry can be configured conveniently via `:options :registry`:
```clj
(require '[malli.core :as m])
(def coercion
(reitit.coercion.malli/create
{:options
{:registry (merge (m/default-schemas)
{:my-type :int})}}))
(def coercer (reitit.coercion/-request-coercer coercion :string [:map [:x :my-type]]))
(coercer {:x "5"} :default)
=> {:x 5}
```