Skip to content

Instantly share code, notes, and snippets.

@ikitommi
Last active October 23, 2017 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ikitommi/8a97080357fd7de06882ba99f0df974c to your computer and use it in GitHub Desktop.
Save ikitommi/8a97080357fd7de06882ba99f0df974c to your computer and use it in GitHub Desktop.
2-way spec coercion
(ns handler
(:require [clj-time.core :as t]
[clj-time.coerce :as t.c]
[spec-tools.conform :as conform]
[clojure.spec.alpha :as s]
[spec-tools.core :as st]
[compojure.api.sweet :refer :all]
[ring.util.http-response :refer :all]))
(def timestamp
(st/spec
{:spec #(or (pos-int? %) (string? %))
:json-schema/default "2017-10-12T05:04:57.585Z"
:type :timestamp}))
(defn json-timestamp->long [_ val]
(t.c/to-long val))
(defn timestamp->json-string [_ val]
(t.c/to-string val))
(def custom-coercion
(-> compojure.api.coercion.spec/default-options
(assoc-in
[:body :formats "application/json"]
(st/type-conforming
(merge
conform/json-type-conforming
{:timestamp json-timestamp->long}
conform/strip-extra-keys-type-conforming)))
(assoc-in
[:response :formats "application/json"]
(st/type-conforming
(merge
conform/json-type-conforming
{:timestamp timestamp->json-string}
conform/strip-extra-keys-type-conforming)))
compojure.api.coercion.spec/create-coercion))
custom-coercion
;#SpecCoercion{:name :spec,
; :options {:body {:default :compojure.api.coercion.spec/default,
; :formats {"application/json" #object[...],
; "application/msgpack" #object[...],
; "application/x-yaml" #object[...]}},
; :string {:default #object[...]},
; :response {:default :compojure.api.coercion.spec/default,
; :formats {"application/json" #object[...]}}}}
(s/def ::time timestamp)
(s/def ::body (st/spec (s/keys :req-un [::time])))
(def app
(api
{:coercion custom-coercion}
(POST "/date" []
:return ::body
:body [body ::body]
(println "I see:" body)
(ok body))))
(-> {:request-method :post
:uri "/date"
:headers {"content-type" "application/json"}
:body "{\"time\": \"2017-10-12T05:04:57.585Z\"}"}
app
:body
slurp)
; I see: {:time 1507784697585}
; => "{\"time\":\"2017-10-12T05:04:57.585Z\"}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment