example of just coercion with ring

This commit is contained in:
Tommi Reiman 2017-12-03 17:43:57 +02:00
parent e0eb1fd0a3
commit 1f2bac40db
8 changed files with 164 additions and 0 deletions

View file

@ -0,0 +1,11 @@
/target
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
.hgignore
.hg/

View file

@ -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

View file

@ -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"]])

View file

@ -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})))

View file

@ -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"})))

View file

@ -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})))

View file

@ -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")))

View file

@ -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})))