diff --git a/examples/just-coercion-with-ring/.gitignore b/examples/just-coercion-with-ring/.gitignore new file mode 100644 index 00000000..c53038ec --- /dev/null +++ b/examples/just-coercion-with-ring/.gitignore @@ -0,0 +1,11 @@ +/target +/classes +/checkouts +pom.xml +pom.xml.asc +*.jar +*.class +/.lein-* +/.nrepl-port +.hgignore +.hg/ diff --git a/examples/just-coercion-with-ring/README.md b/examples/just-coercion-with-ring/README.md new file mode 100644 index 00000000..f1da29e8 --- /dev/null +++ b/examples/just-coercion-with-ring/README.md @@ -0,0 +1,39 @@ +# Just Coercion With Ring + +A Sample project showing how to use the reitit coercion with pure ring. + +* `Middleware` are turned into normal ring middleware via `reitit.middleware/chain` +* Endpoint parameters are given to middleware as arguments +* Coerced parameters are available from `:parameters` + +## Usage + +```clj +> lein repl + +(require '[example.server :as server]) + +;; the manually coerced version +(require '[example.naive :as naive]) +(server/restart naive/app) + +;; schema-coercion +(require '[example.schema :as schema]) +(server/restart schema/app) + +;; spec-coercion +(require '[example.spec :as spec]) +(server/restart spec/app) + +;; data-spec-coercion +(require '[example.dspec :as dspec]) +(server/restart dspec/app) +``` + +To test the endpoint: + +http://localhost:3000/?x=1&y=20 + +## License + +Copyright © 2017 Metosin Oy diff --git a/examples/just-coercion-with-ring/project.clj b/examples/just-coercion-with-ring/project.clj new file mode 100644 index 00000000..11bbb381 --- /dev/null +++ b/examples/just-coercion-with-ring/project.clj @@ -0,0 +1,6 @@ +(defproject just-coercion-with-ring "0.1.0-SNAPSHOT" + :description "Reitit coercion with vanilla ring" + :dependencies [[org.clojure/clojure "1.9.0-RC2"] + [ring "1.6.3"] + [metosin/muuntaja "0.4.1"] + [metosin/reitit "0.1.0-SNAPSHOT"]]) diff --git a/examples/just-coercion-with-ring/src/example/dspec.clj b/examples/just-coercion-with-ring/src/example/dspec.clj new file mode 100644 index 00000000..0a52b145 --- /dev/null +++ b/examples/just-coercion-with-ring/src/example/dspec.clj @@ -0,0 +1,15 @@ +(ns example.dspec + (:require [reitit.ring.coercion :as coercion] + [reitit.ring.coercion.spec :as spec-coercion] + [example.server :as server])) + +(defn handler [{{{:keys [x y]} :query} :parameters}] + {:status 200 + :body {:result (+ x y) + :source :data-spec}}) + +(def app + (-> #'handler + (server/wrap-coercion + {:parameters {:query {:x int?, :y int?}} + :coercion spec-coercion/coercion}))) diff --git a/examples/just-coercion-with-ring/src/example/naive.clj b/examples/just-coercion-with-ring/src/example/naive.clj new file mode 100644 index 00000000..5fa8569d --- /dev/null +++ b/examples/just-coercion-with-ring/src/example/naive.clj @@ -0,0 +1,27 @@ +(ns example.naive + (:require [clojure.spec.alpha :as s] + [clojure.walk :as walk] + [example.server :as server])) + +(s/def ::x int?) +(s/def ::y int?) +(s/def ::request (s/keys :req-un [::x ::y])) + +(defn ->long [x] + (try + (Long/parseLong x) + (catch Exception _ + x))) + +(defn app [request] + (println (:query-params request)) + (let [{:keys [x y] :as params} (-> (:query-params request) + (walk/keywordize-keys) + (update :x ->long) + (update :y ->long))] + (if (s/valid? ::request params) + {:status 200 + :body {:result (+ x y) + :source :naive}} + {:status 400 + :body "invalid input"}))) diff --git a/examples/just-coercion-with-ring/src/example/schema.clj b/examples/just-coercion-with-ring/src/example/schema.clj new file mode 100644 index 00000000..198ecb87 --- /dev/null +++ b/examples/just-coercion-with-ring/src/example/schema.clj @@ -0,0 +1,15 @@ +(ns example.schema + (:require [reitit.ring.coercion :as coercion] + [reitit.ring.coercion.schema :as schema-coercion] + [example.server :as server])) + +(defn handler [{{{:keys [x y]} :query} :parameters}] + {:status 200 + :body {:result (+ x y) + :source :schema}}) + +(def app + (-> #'handler + (server/wrap-coercion + {:parameters {:query {:x Long, :y Long}} + :coercion schema-coercion/coercion}))) diff --git a/examples/just-coercion-with-ring/src/example/server.clj b/examples/just-coercion-with-ring/src/example/server.clj new file mode 100644 index 00000000..33b1e029 --- /dev/null +++ b/examples/just-coercion-with-ring/src/example/server.clj @@ -0,0 +1,28 @@ +(ns example.server + (:require [ring.adapter.jetty :as jetty] + [reitit.ring.middleware :as middleware] + [reitit.ring.coercion :as coercion])) + +(defonce ^:private server (atom nil)) + +;; unlift Middleware Record into vanilla Ring middleware +;; NOTE: to support format-based body coercion, an options map needs +;; to be set with :extract-request-format and extract-response-format +(defn wrap-coercion [handler resource] + (middleware/chain + [coercion/coerce-request-middleware + coercion/coerce-response-middleware + coercion/coerce-exceptions-middleware] + handler + resource)) + +(defn restart [handler] + (let [app (-> handler + (ring.middleware.params/wrap-params) + (muuntaja.middleware/wrap-format))] + (swap! server (fn [x] + (when x (.stop x)) + (jetty/run-jetty + handler + {:port 3000, :join? false}))) + (println "server running in port 3000"))) diff --git a/examples/just-coercion-with-ring/src/example/spec.clj b/examples/just-coercion-with-ring/src/example/spec.clj new file mode 100644 index 00000000..90f5a40c --- /dev/null +++ b/examples/just-coercion-with-ring/src/example/spec.clj @@ -0,0 +1,23 @@ +(ns example.spec + (:require [clojure.spec.alpha :as s] + [spec-tools.spec :as spec] + [reitit.ring.coercion :as coercion] + [reitit.ring.coercion.spec :as spec-coercion] + [example.server :as server])) + +;; wrap into Spec Records to enable runtime conforming +(s/def ::x spec/int?) +(s/def ::y spec/int?) +(s/def ::request (s/keys :req-un [::x ::y])) + +;; read coerced parameters under :parameters +(defn handler [{{{:keys [x y]} :query} :parameters}] + {:status 200 + :body {:result (+ x y) + :source :spec}}) + +(def app + (-> #'handler + (server/wrap-coercion + {:parameters {:query ::request} + :coercion spec-coercion/coercion})))