mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 16:31:11 +00:00
3.3 KiB
3.3 KiB
Parameter coercion
Reitit provides pluggable parameter coercion via reitit.coercion.protocol/Coercion protocol, originally introduced in compojure-api. Reitit ships with reitit.coercion.spec/SpecCoercion providing implemenation for clojure.spec and data-specs.
NOTE: Before Clojure 1.9.0 is shipped, to use the spec-coercion, one needs to add the following dependencies manually to the project:
[org.clojure/clojure "1.9.0-alpha20"]
[org.clojure/spec.alpha "0.1.123"]
[metosin/spec-tools "0.3.3"]
Ring request and response coercion
To use Coercion with Ring, one needs to do the following:
- Define parameters and responses as data into route meta-data, in format adopted from ring-swagger:
:parametersmap, with submaps for different parameters::query,:body,:form,:headerand:path. Parameters are defined in the format understood by theCoercion.:responsesmap, with response status codes as keys (or:defaultfor "everything else") with maps with:schemaand optionally:descriptionas values.
- Define a
Coercionto route meta-data under:coercion - Mount request & response coercion middleware to the routes.
If the request coercion succeeds, the coerced parameters are injected into request under :parameters.
If either request or response coercion fails, an descriptive error is thrown.
Example with data-specs
(require '[reitit.ring :as ring])
(require '[reitit.coercion :as coercion])
(require '[reitit.coercion.spec :as spec])
(def app
(ring/ring-handler
(ring/router
["/api"
["/ping" {:parameters {:body {:x int?, :y int?}}
:responses {200 {:schema {:total pos-int?}}}
:get {:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]
{:meta {:middleware [coercion/gen-wrap-coerce-parameters
coercion/gen-wrap-coerce-response]
:coercion spec/coercion}})))
(app
{:request-method :get
:uri "/api/ping"
:body-params {:x 1, :y 2}})
; {:status 200, :body {:total 3}}
Example with specs
(require '[reitit.ring :as ring])
(require '[reitit.coercion :as coercion])
(require '[reitit.coercion.spec :as spec])
(require '[clojure.spec.alpha :as s])
(require '[spec-tools.core :as st])
(s/def ::x (st/spec int?))
(s/def ::y (st/spec int?))
(s/def ::total int?)
(s/def ::request (s/keys :req-un [::x ::y]))
(s/def ::response (s/keys :req-un [::total]))
(def app
(ring/ring-handler
(ring/router
["/api"
["/ping" {:parameters {:body ::request}
:responses {200 {:schema ::response}}
:get {:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]
{:meta {:middleware [coercion/gen-wrap-coerce-parameters
coercion/gen-wrap-coerce-response]
:coercion spec/coercion}})))
(app
{:request-method :get
:uri "/api/ping"
:body-params {:x 1, :y 2}})
; {:status 200, :body {:total 3}}