ring-swagger 2019-04-01

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

Now if only json-transformer would do anything...

Any quick tips why it returns the given data structure as-is back?

I can't recall ever getting json-transformer to work but I'll be damned if I'll give up this time

(st/coerce keyword? "kikka" st/json-transformer)
; :kikka

seems to work ok?

If you have a failing minimal example, please share

(s/def ::bar integer?)
(s/def ::foo (s/keys :req [::bar]))
(st/coerce ::foo {::bar "2"} st/json-transformer)
=> {::bar "2"}

That's as minimal as I can get it

Most likely I'm doing something wrong but that's how I've understood it should work

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.

JSON can represent ints, so there is no string->int conversion.

Right. Well, same thing happens when explicitly defining :decode/string

(s/def ::bar keyword?)
(s/def ::foo (s/keys :req [::bar]))
(st/coerce ::foo {::bar "2"} st/json-transformer)
; #:user{:bar :2}

oh, the spec keys don’t derive

you need to define :decode/json for that.

documentation of this all is buried somewhere….

And boom, my problem disappeared by replacing :decode/string to :decode/json

Not exactly obvious

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

But thanks, that solved my problem 👍

your welcome

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?

Assuming that the Content-Type is application/json of course

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

I must be missing something

If I pass just something like :coercion "what" then it gives me a very clear error

so it is doing something 🙂

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

I think it's a bad design as the :encode/json doesn't work with it.

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

Yeah, I've read through the source codes several times by now 😄

My main problem initially was that I named my type-transformer into something descriptive what it was under :name

but that kinda screwed up finding the decoders and encoders

Since they were written with :json/encode etc

But, before I realized that I managed to typo a keyword-value pair outside the options map of type-transformer...

It compiled happily since it's parameter definition is [& options-or-transformers]

Oh, the latest json & string are named :strict-string and :strict-json, will not work

But it just didn't work - obviously

Would you like to do a PR?

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 😄

good reason :)

I can fix those later today, 15min max

Still doesn't call my encoder/decoder functions which I've declared in my type-transformer

but it's starting to make more sense

For some reason when I pass the spec-coercion-handler into api under :coercion it never calls the pass-through function

Been debugging this for several hours now

And obviously this pass-through stuff is there just so that I can confirm compojure-api is calling my coercion functions

(and yeah, I've tried without that when block too)

I must be missing something

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.

now, it just calls -decode on response body, which is kinda nonsense.