Hello, I'm trying to extend this example (https://github.com/metosin/reitit/blob/master/examples/frontend-re-frame/src/cljs/frontend_re_frame/core.cljs) to add a router to /item/:id. So, I add this to the routes:
[`"item/:id"`
{:name ::item
:view views/item-page
:parameters {:path {:id int?}
:query {(ds/opt :foo) keyword?}}}]
views/item-page:
(defn item-page [match]
(js/console.log match) ;; <--- undefined
(let [{:keys [path query]} (:parameters match)
{:keys [id]} path]
[:div
[:h2 "Selected item " id]
(if (:foo query)
[:p "Optional foo query param: " (:foo query)])]))
And the link:
[:a {:href (href ::item {:id 10})} "Link to item 10"]
But when I click on the link, the match is undefined. Do you have any tips here?
Note: I tried with https://github.com/metosin/reitit/blob/master/examples/frontend/src/frontend/core.cljs and works as expected, but cannot make the same using the re-frame example.
The parameters your view fn gets depend on your main component, are you passing in the match value there?
it is these lines in the example https://github.com/metosin/reitit/blob/master/examples/frontend/src/frontend/core.cljs#L55-L57
re-frame example just calls the view fn without parameters https://github.com/metosin/reitit/blob/master/examples/frontend-re-frame/src/cljs/frontend_re_frame/core.cljs#L131
but you can subscribe to the match in the component instead
(let [match @(re-frame/subscribe [current-route])] ...)
you can modify the code to also pass in match on the re-frame version
It works, I was really missing the match value to the view. But I will also try it with a subscribe. Thanks!
I guess I am doing something wrong, But I cannot get (s/or :success ::success :error ::error) working with a coercion.
Here are the sample specs:
(s/def ::type string?)
(s/def ::message string?)
(s/def ::error (s/keys :req-un [::type
::message]))
(s/def ::collection (s/coll-of map?))
(s/def ::success (s/keys :req-un [::collection]))
(s/def ::callback (s/or :error (s/keys :req-un [::error])
:success ::success))
And my route looks like this:
["/test"
{:post {:parameters {:body ::callback}
:responses {200 {:body map?}}
:handler identity}}]
When I do this, then they succeed:
(comment
(->> (slurp "contrib/success.json")
<-json
(s/conform ::callback))
(->> (slurp "contrib/error.json")
<-json
(s/conform ::callback)))
But when I try to do that through reitit with either success.json or error.json, then it fails.I guess I have some time to look at this right now, just a moment
I’ve created a repro repository, but the case is exactly the same as described in #494
the problem seems to be st/strip-extra-keys-transformer (which reitit.coercion.spec uses)
(is (= {:b []} (st/coerce ::subject/body {:b []} st/json-transformer))) ;;fails
(is (= {:b []} (st/coerce ::subject/body {:b []} st/strip-extra-keys-transformer))) ;;passesThat is what I was also thinking, when I was trying to debug this yesterday late evening
so this bug, probably: https://github.com/metosin/spec-tools/issues/255
a workaround seems to be to use st/spec to wrap the child schemas
ouch!
didn't get it to work yet tho
ah yes the st/spec needs to be inside the s/or
this seems to work for me:
(s/def ::a string?)
(s/def ::A (s/keys :req-un [::a]))
(s/def ::b vector?)
(s/def ::B (s/keys :req-un [::b]))
(s/def ::body (s/or :foo (st/spec ::A) :bar (st/spec ::B)))
(def app
(ring/ring-handler
(ring/router
[["/test" {:post {:coercion reitit.coercion.spec/coercion
:parameters {:body ::body}That is exactly what I am trying ATM
Yes, that seems to solve my original issue as well
that's great news, but also horrible
Oh gosh! 🤦♂️ I’ve just realized that I ran into this this January.
I even referenced this error in one of our commits: https://github.com/metosin/spec-tools/issues/212
yeah but that issue gives you the impression that the problem has been fixed
Yeah, but it isn’t
Could be a regression though
all the tests added by #219 still pass tho
But interestingly the repro case described in https://github.com/metosin/reitit/issues/494 fails today as well
what a mess of issues...
what I'm going to do next is document the current state of the issue a bit better and add a lot of crosslinks to existing issues
meanwhile, I recommend not using spec for coercion, it's not meant for that, and trying to force it to do that is just a world of pain (as we've discovered in spec-tools)
Looking at the issues, it seems to me that the root cause wasn’t fixed
yeah
Well, I am using reitit w/ clojure.spec the way it is documented
yes, I know. that was just my personal recommendation 😇
I realise it might be impossible to refactor an existing codebase
I can live with the workaround for now, but I’ll keep an eye on this error and the one that you are about to report
btw, another workaround might be to disable the strip-extra-keys-transformer by overriding the transformer that the reitit coercion uses
I was trying that yesterday
nil-ing out the transformer
But that did not help
you probably want to still have st/json-transformer in there
(def coercion
(-> reitit.coercion.spec/default-options
;; (assoc-in [:transformers :body :default] nil)
(assoc-in [:transformers :body :default] st/fail-on-extra-keys-transformer)
;; (hashmap/dissoc-in [:transformers :body :default])
reitit.coercion.spec/create))but I didn't test this end-to-end, just on the st level. see my prev message: https://clojurians.slack.com/archives/C7YF1SBT3/p1728632931301669?thread_ts=1728592880.546909&cid=C7YF1SBT3
as you can see I did multiple tries here
hmph. there might be another problem along the way then.
Yeah, that’s why I have the feeling that the root cause lies somewhere deep
IMHO, the root cause is spec-tools. It shouldn't exist 😅
Haha 😄
I've fixed some bugs in there and it just feels like whack-a-mole
Anyhow, thank you very much for your help!
Thank you very much!
added some content to https://github.com/metosin/spec-tools/issues/255
I'm afraid I won't be looking further into this right now, but I'll bump it in our open source backlog...
Oh! I hope it is not related to this bug: https://clojure.atlassian.net/browse/CLJ-2079
I ran into that here: https://clojurians.slack.com/archives/C1B1BB2Q3/p1723725302816599
funnily enough, we have a similar bug with malli, it seems! https://github.com/metosin/malli/issues/1112
Now I’m really excited to see what’s underneath it all.
Oh sweet baby jesus, the st/spec workaround messes up the Swagger doc generation
java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword
at clojure.lang.RT.seqFrom(RT.java:577)
at clojure.lang.RT.seq(RT.java:557)
at clojure.core$seq__5486.invokeStatic(core.clj:139)
at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:24)
at clojure.core.protocols$fn__8252.invokeStatic(protocols.clj:74)
at clojure.core.protocols$fn__8252.invoke(protocols.clj:74)
at clojure.core.protocols$fn__8203$G__8198__8216.invoke(protocols.clj:13)
at clojure.core$reduce.invokeStatic(core.clj:6965)
at clojure.core$reduce.invoke(core.clj:6947)
at spec_tools.impl$unlift_keys.invokeStatic(impl.cljc:166)
at spec_tools.impl$unlift_keys.invoke(impl.cljc:165)
at spec_tools.openapi.core$eval46249$fn__46250.invoke(core.cljc:34)
...I am out of luck here
I could either have a spec with st/spec for input validation and :no-doc true to fix the problem above, or the coercion is not working
aww that sucks
if you have the energy, try openapi docs instead of swagger. openapi has native support for s/or (anyOf in json schema speak), so it should be a better fit!
I believe that was failing as well, I just referred that as Swagger
But I will check this after lunch
thanks
Yeah, both /openapi.json and /swagger.json are failing
I'll try to formulate another bug against spec-tools for the openapi/swagger behaviour later today
great! thank you very much!
When I try with error.json:
{
"spec": "(spec-tools.core/spec {:spec (clojure.spec.alpha/or :error (clojure.spec.alpha/keys :req-un [:test/error]) :success :test/success), :type [:or [:map]], :leaf? true})",
"problems": [
{
"path": [
"error"
],
"pred": "(clojure.core/fn [%] (clojure.core/contains? % :error))",
"val": {},
"via": [
"test/callback"
],
"in": []
},
{
"path": [
"success"
],
"pred": "(clojure.core/fn [%] (clojure.core/contains? % :collection))",
"val": {},
"via": [
"test/callback",
"test/success"
],
"in": []
}
],
"type": "reitit.coercion/request-coercion",
"coercion": "spec",
"value": {
"error": {
"type": "HTTPException",
"message": "500: {'cause': 'Publishing error', 'info': 'Service Unavailable'}"
}
},
"in": [
"request",
"body-params"
]
}When I try with success.json:
{
"spec": "(spec-tools.core/spec {:spec (clojure.spec.alpha/or :error (clojure.spec.alpha/keys :req-un [:test/error]) :success :test/success), :type [:or [:map]], :leaf? true})",
"problems": [
{
"path": [
"error"
],
"pred": "(clojure.core/fn [%] (clojure.core/contains? % :error))",
"val": {},
"via": [
"test/callback"
],
"in": []
},
{
"path": [
"success"
],
"pred": "(clojure.core/fn [%] (clojure.core/contains? % :collection))",
"val": {},
"via": [
"test/callback",
"test/success"
],
"in": []
}
],
"type": "reitit.coercion/request-coercion",
"coercion": "spec",
"value": {
"collection": [
{}
]
},
"in": [
"request",
"body-params"
]
}I’ve found https://github.com/metosin/reitit/issues/494 but this seems to be fixed
But if I take that repro case, that still fails for me
If I flip the s/or then the ::B case succeeds and the ::A case fails from the #494 repro case
just checking: are you sure you're not accidentally using an ancient version of spec-tools? that's where the fix was
but it sounds like you have a good repro, so feel free to open a new issue!
I am using 0.10.7, that should has the fix. Technically the problem is exactly the same as #494 with the exact same repro.