ring-swagger & compojure-api
Empperi 2019-04-01T08:06:40.040300Z

What am I doing wrong? I'm expecting true as the result:

(s/def ::active
    {:spec boolean?
     :decode/string (partial = "YES")}))

(st/coerce ::active "YES" st/string-transformer)
=> false

Empperi 2019-04-01T08:14:58.041Z

Oh, ok. Got it. When using :decode/string it's the second parameter passed to the function which actually contains the value being coerced

Empperi 2019-04-01T08:15:24.041300Z

Meaning this spec works correctly:

(s/def ::active
    {:spec boolean?
     :decode/string #(= "YES" %2)}))

ikitommi 2019-04-01T08:20:05.042100Z

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)

Empperi 2019-04-01T08:20:05.042200Z

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

Empperi 2019-04-01T08:20:37.042600Z

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

Empperi 2019-04-01T08:22:48.043100Z

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

ikitommi 2019-04-01T08:24:14.043300Z

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

ikitommi 2019-04-01T08:24:24.043700Z

seems to work ok?

ikitommi 2019-04-01T08:24:58.044Z

If you have a failing minimal example, please share

Empperi 2019-04-01T08:26:56.044500Z

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

Empperi 2019-04-01T08:29:23.044700Z

That's as minimal as I can get it

Empperi 2019-04-01T08:30:40.045200Z

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

Empperi 2019-04-01T08:32:31.045900Z

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.

ikitommi 2019-04-01T08:33:24.046400Z

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

Empperi 2019-04-01T08:33:50.046800Z

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

ikitommi 2019-04-01T08:33:56.047100Z

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

ikitommi 2019-04-01T08:34:48.047700Z

oh, the spec keys don’t derive

ikitommi 2019-04-01T08:34:59.048Z

you need to define :decode/json for that.

ikitommi 2019-04-01T08:35:58.048700Z

documentation of this all is buried somewhere….

Empperi 2019-04-01T08:36:18.049200Z

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

Empperi 2019-04-01T08:37:02.049600Z

Not exactly obvious

Empperi 2019-04-01T08:37:24.050100Z

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

Empperi 2019-04-01T08:38:03.050500Z

But thanks, that solved my problem 👍

ikitommi 2019-04-01T08:40:46.050900Z

your welcome

Empperi 2019-04-01T10:07:38.052Z

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?

Empperi 2019-04-01T10:08:01.052400Z

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

Empperi 2019-04-01T10:09:06.052900Z

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

Empperi 2019-04-01T10:16:36.053400Z

It would kinda make sense if it did not do that since otherwise generating correct api-docs would get pretty hard

Empperi 2019-04-01T10:17:12.054100Z

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

Empperi 2019-04-01T10:18:01.055100Z

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

Empperi 2019-04-01T10:25:34.055800Z

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?

Empperi 2019-04-01T10:41:38.056200Z

Right. I'm stupid. Just write your own coercion handler for compojure-api and be done with it...

Empperi 2019-04-01T11:35:54.057Z

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

Empperi 2019-04-01T11:36:04.057200Z

I must be missing something

Empperi 2019-04-01T11:36:55.057900Z

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

Empperi 2019-04-01T11:37:03.058200Z

so it is doing something 🙂

ikitommi 2019-04-01T13:32:52.062800Z

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

ikitommi 2019-04-01T13:33:21.063800Z

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

ikitommi 2019-04-01T13:36:18.067500Z

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

Empperi 2019-04-01T13:36:34.067700Z


Empperi 2019-04-01T13:36:59.068300Z

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

Empperi 2019-04-01T13:37:51.069Z

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

Empperi 2019-04-01T13:38:16.069600Z

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

Empperi 2019-04-01T13:38:28.070Z

but that kinda screwed up finding the decoders and encoders

Empperi 2019-04-01T13:38:42.070500Z

Since they were written with :json/encode etc

Empperi 2019-04-01T13:39:12.071800Z

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

Empperi 2019-04-01T13:39:37.072900Z

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

ikitommi 2019-04-01T13:39:37.073Z

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

Empperi 2019-04-01T13:39:44.073300Z

But it just didn't work - obviously

ikitommi 2019-04-01T13:40:17.073800Z

Would you like to do a PR?

Empperi 2019-04-01T13:40:35.074400Z

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 😄

ikitommi 2019-04-01T13:41:08.075200Z

good reason :)

ikitommi 2019-04-01T13:41:47.076Z

I can fix those later today, 15min max

Empperi 2019-04-01T13:42:02.076400Z

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

Empperi 2019-04-01T13:42:10.076700Z

but it's starting to make more sense

Empperi 2019-04-01T14:09:18.076900Z

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

Empperi 2019-04-01T14:09:45.077400Z

Been debugging this for several hours now

Empperi 2019-04-01T14:10:17.078Z

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

Empperi 2019-04-01T14:10:41.078400Z

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

Empperi 2019-04-01T14:10:50.078600Z

I must be missing something

ikitommi 2019-04-01T18:37:44.080Z

pushed out [metosin/compojure-api "2.0.0-alpha30"] with updated deps, including new spec-tools, muuntaja & ring-swagger.

ikitommi 2019-04-01T18:41:30.083500Z

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

ikitommi 2019-04-01T18:42:06.084200Z

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

Empperi 2019-04-01T18:42:07.084300Z