This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-16
Channels
Hi all, is it possible to have body params coerced? {:y "42"} -> {:y 42}
?
Seems like only validation is applied to body params am I missing something? I see path params will coerce from string to num but can't seem to get body to do the same. Thanks.
Hi, I have a route like this and it makes sure the string that comes in from a for is turned into an number
["/client/:client-id/cards/add"
{:name ::card/add-card
:post {:handler (...)
:coercion reitit.coercion.malli/coercion
:parameters {:form [:map
[:card-name string?]
[:card-index :int]]}}}]
Hi @U4XT72NNT, yeah it's odd, I have tried spec, malli and schema and can't get it to coerce, only validate, will keep trying
And did you add the middleware? You probably only need the request one, I just added them all to be sure.
reitit.ring.coercion/coerce-exceptions-middleware
reitit.ring.coercion/coerce-request-middleware
reitit.ring.coercion/coerce-response-middleware
All together:
(ring/router
[["/client/:client-id/cards/add"
{:name ::card/add-card
:post {:handler (...)
:coercion reitit.coercion.malli/coercion
:parameters {:form [:map
[:card-name string?]
[:card-index :int]]}}}]]
{:data
{:middleware
reitit.ring.coercion/coerce-exceptions-middleware
reitit.ring.coercion/coerce-request-middleware
reitit.ring.coercion/coerce-response-middleware}})
(comment
(require '[reitit.ring.coercion :as rrc])
(require '[reitit.coercion.schema])
(require '[reitit.ring :as ring])
(require '[schema.core :as s])
(def app
(ring/ring-handler
(ring/router
["/api"
["/plus/:z" {
:post {:coercion reitit.coercion.schema/coercion
:parameters {:query {:x s/Int}
:body {:y s/Int}
:path {:z s/Int}}
:handler (fn [{:keys [parameters]}]
(let [total (+ (-> parameters :query :x)
(-> parameters :body :y)
(-> parameters :path :z))]
{:status 200
:body {:total total}}))}}]]
{:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware]}})))
(app {:request-method :post
:uri "/api/plus/3"
:query-params {"x" "5"}
:body-params {:y 6}})
;; => {:status 200, :body {:total 14}}
(app {:request-method :post
:uri "/api/plus/3"
:query-params {"x" "1"}
:body-params {:y "6"}})
;; => {:status 400,
;; :body
;; {:schema {:y "Int"},
;; :errors {:y "(not (integer? \"6\"))"},
;; :type :reitit.coercion/request-coercion,
;; :coercion :schema,
;; :value {:y "6"},
;; :in [:request :body-params]}}
;;Keep from folding
)
I think if there is no format specified for the :body-params
, then the default-coercion-matcher
will be used (which just returns nil
constantly) see here https://github.com/metosin/reitit/blob/master/modules/reitit-schema/src/reitit/coercion/schema.cljc#L40C48-L40C55.
You can see if you change the coercion options so that the body
default option is the string-coercion-matcher
, it will work
(comment
(require '[reitit.ring.coercion :as rrc])
(require '[reitit.coercion.schema :as rcs])
(require '[reitit.ring :as ring])
(require '[schema.core :as s])
(def app
(ring/ring-handler
(ring/router
["/api"
["/plus/:z" {:post {:coercion (rcs/create (assoc-in rcs/default-options [:matchers :body :default] rcs/string-coercion-matcher))
:parameters {:query {:x s/Int}
:body {:y s/Int}
:path {:z s/Int}}
:handler (fn [{:keys [parameters]}]
(let [total (+ (-> parameters :query :x)
(-> parameters :body :y)
(-> parameters :path :z))]
{:status 200
:body {:total total}}))}}]]
{:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware]}})))
(app {:request-method :post
:uri "/api/plus/3"
:query-params {"x" "5"}
:content-type "application/json"
:body-params {:y 6}}) => {:status 200, :body {:total 14}}
(app {:request-method :post
:uri "/api/plus/3"
:query-params {"x" "1"}
:body-params {:y "6"}}) => {:status 200, :body {:total 10}}
)