This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-04-01
Channels
- # announcements (3)
- # beginners (59)
- # calva (23)
- # cider (58)
- # clojure (125)
- # clojure-dev (18)
- # clojure-dusseldorf (1)
- # clojure-europe (21)
- # clojure-germany (1)
- # clojure-hamburg (1)
- # clojure-italy (13)
- # clojure-nl (29)
- # clojure-poland (3)
- # clojure-spec (61)
- # clojure-uk (74)
- # clojurescript (12)
- # core-async (6)
- # cursive (4)
- # data-science (7)
- # datomic (14)
- # defnpodcast (1)
- # events (4)
- # fulcro (72)
- # juxt (36)
- # kaocha (3)
- # nginx (3)
- # off-topic (14)
- # pathom (5)
- # ring-swagger (68)
- # shadow-cljs (25)
- # spacemacs (8)
- # sql (42)
- # tools-deps (8)
- # vim (6)
What am I doing wrong? I'm expecting true
as the result:
(s/def ::active
(st/spec
{:spec boolean?
:decode/string (partial = "YES")}))
(st/coerce ::active "YES" st/string-transformer)
=> false
Oh, ok. Got it. When using :decode/string
it's the second parameter passed to the function which actually contains the value being coerced
Meaning this spec works correctly:
(s/def ::active
(st/spec
{:spec boolean?
:decode/string #(= "YES" %2)}))
yes, exposing spec to the transformer allows to do nice things like:
(defn strip-extra-keys [{:keys [::parse/keys]} x]
(if (and keys (map? x))
(select-keys x keys)
x))
I can't recall ever getting json-transformer
to work but I'll be damned if I'll give up this time
(s/def ::bar integer?)
(s/def ::foo (s/keys :req [::bar]))
(st/coerce ::foo {::bar "2"} st/json-transformer)
=> {::bar "2"}
End result doesn't pass validation for the very same spec, if I do the coercion "myself" by replacing "2"
with 2
it passes validations like expected.
(s/def ::bar keyword?)
(s/def ::foo (s/keys :req [::bar]))
(st/coerce ::foo {::bar "2"} st/json-transformer)
; #:user{:bar :2}
see https://github.com/metosin/spec-tools/blob/master/src/spec_tools/transform.cljc#L183-L199
I suggest adding that somewhere in the documentation in such a way that it is easy to spot. For example here https://github.com/metosin/spec-tools/blob/master/docs/01_coercion.md
https://github.com/metosin/spec-tools/commit/9e3131a054d5dffa4ae0634b6f7e1f6a9f857d15
Hey, one more question: shouldn't compojure-api use automatically :encode/json
transformers with json-transformer if one has applied :coercion :spec
into api definition?
As it is now it doesn't seem to do this so I'm just checking if I'm assuming wrong before I dig deeper
It would kinda make sense if it did not do that since otherwise generating correct api-docs would get pretty hard
So based on that, I guess I need to create a separate spec for compojure-api if I want the end result JSON to be encoded to different format
(in this case I want to handle certain data as namespaced keywords within the app, but when I expose it via JSON API I want to drop the namespaces before writing the keywords as values since clients do not know or care about Clojure keywords)
Another question which is related to the same thing, any easy way to drop the namespaces from keywords in compojure-api when doing the JSON serialization?
Right. I'm stupid. Just write your own coercion handler for compojure-api and be done with it...
Ok. This is embarassing. It seems like compojure-api isn't even calling my coercion handler. No matter what I pass there as value it doesn't care
@niklas.collin the spec coercion calls :decode/json
for incoming json. For response bodies, the default spec coercion is "just validate", not "encode to json". Idea was that you should return valid edn from the endpoint and the json encoder will format that.
One can set the response encoding on via custom coercion, but I think the default should be changed so that it's called :json
so that the custom :encode/json
things would work
I've been debugging my custom coercer and I think I found the reason why it didn't work. I'm just a bad programmer writing bugs, that's all
https://github.com/metosin/compojure-api/blob/master/src/compojure/api/coercion/spec.clj#L136-L142
My main problem initially was that I named my type-transformer into something descriptive what it was under :name
But, before I realized that I managed to typo a keyword-value pair outside the options map of type-transformer
...
Oh, the latest json & string are named :strict-string
and :strict-json
, will not work
Maybe at some point. Right now I need to get this working what I'm doing and head to home before my wife kills me 😄
Still doesn't call my encoder/decoder functions which I've declared in my type-transformer
For some reason when I pass the spec-coercion-handler
into api
under :coercion
it never calls the pass-through
function
And obviously this pass-through
stuff is there just so that I can confirm compojure-api is calling my coercion functions
pushed out [metosin/compojure-api "2.0.0-alpha30"]
with updated deps, including new spec-tools, muuntaja & ring-swagger.
@niklas.collin the response encoding needs some extra care, but don’t have extra time any time soon for that. Quick analysis: the spec-tools/coerce
should have an optional 4th arg, on which function to call, would default to st/-decode
, could be set to st/-encode
.