reitit

meya wudafu 2024-10-10T12:29:26.031569Z

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.

juhoteperi 2024-10-10T13:34:07.608229Z

The parameters your view fn gets depend on your main component, are you passing in the match value there?

juhoteperi 2024-10-10T13:34:33.731889Z

it is these lines in the example https://github.com/metosin/reitit/blob/master/examples/frontend/src/frontend/core.cljs#L55-L57

juhoteperi 2024-10-10T13:34:59.887159Z

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

juhoteperi 2024-10-10T13:35:19.901859Z

but you can subscribe to the match in the component instead

juhoteperi 2024-10-10T13:35:41.029589Z

(let [match @(re-frame/subscribe [current-route])] ...)

juhoteperi 2024-10-10T13:36:03.806919Z

you can modify the code to also pass in match on the re-frame version

meya wudafu 2024-10-10T13:43:57.164989Z

It works, I was really missing the match value to the view. But I will also try it with a subscribe. Thanks!

István Karaszi 2024-10-10T20:41:20.546909Z

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.

opqdonut 2024-10-11T07:32:56.466009Z

I guess I have some time to look at this right now, just a moment

🙏 1
István Karaszi 2024-10-11T07:33:35.708369Z

I’ve created a repro repository, but the case is exactly the same as described in #494

István Karaszi 2024-10-11T07:34:25.627209Z

https://github.com/raszi/reitit-spec-or

opqdonut 2024-10-11T07:48:35.075249Z

the problem seems to be st/strip-extra-keys-transformer (which reitit.coercion.spec uses)

opqdonut 2024-10-11T07:48:51.301669Z

(is (= {:b []} (st/coerce ::subject/body {:b []} st/json-transformer))) ;;fails
  (is (= {:b []} (st/coerce ::subject/body {:b []} st/strip-extra-keys-transformer))) ;;passes

István Karaszi 2024-10-11T07:50:00.728549Z

That is what I was also thinking, when I was trying to debug this yesterday late evening

opqdonut 2024-10-11T07:50:06.076019Z

so this bug, probably: https://github.com/metosin/spec-tools/issues/255

opqdonut 2024-10-11T07:50:34.880609Z

a workaround seems to be to use st/spec to wrap the child schemas

István Karaszi 2024-10-11T07:50:50.376539Z

ouch!

opqdonut 2024-10-11T07:53:18.094709Z

didn't get it to work yet tho

opqdonut 2024-10-11T07:53:46.210109Z

ah yes the st/spec needs to be inside the s/or

opqdonut 2024-10-11T07:54:07.597629Z

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}

István Karaszi 2024-10-11T07:54:40.654129Z

That is exactly what I am trying ATM

István Karaszi 2024-10-11T07:55:21.269209Z

Yes, that seems to solve my original issue as well

opqdonut 2024-10-11T07:56:19.938799Z

that's great news, but also horrible

👆 1
István Karaszi 2024-10-11T07:56:25.563749Z

Oh gosh! 🤦‍♂️ I’ve just realized that I ran into this this January.

István Karaszi 2024-10-11T07:56:43.686959Z

I even referenced this error in one of our commits: https://github.com/metosin/spec-tools/issues/212

opqdonut 2024-10-11T07:57:20.759819Z

yeah but that issue gives you the impression that the problem has been fixed

István Karaszi 2024-10-11T07:57:31.273879Z

Yeah, but it isn’t

István Karaszi 2024-10-11T07:57:55.884339Z

Could be a regression though

opqdonut 2024-10-11T07:58:32.735519Z

all the tests added by #219 still pass tho

István Karaszi 2024-10-11T07:59:12.907709Z

But interestingly the repro case described in https://github.com/metosin/reitit/issues/494 fails today as well

opqdonut 2024-10-11T08:00:15.315939Z

what a mess of issues...

😅 1
opqdonut 2024-10-11T08:01:34.555129Z

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

opqdonut 2024-10-11T08:01:57.924009Z

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)

István Karaszi 2024-10-11T08:02:06.484789Z

Looking at the issues, it seems to me that the root cause wasn’t fixed

opqdonut 2024-10-11T08:02:14.334819Z

yeah

István Karaszi 2024-10-11T08:02:53.546189Z

Well, I am using reitit w/ clojure.spec the way it is documented

opqdonut 2024-10-11T08:03:18.214409Z

yes, I know. that was just my personal recommendation 😇

opqdonut 2024-10-11T08:03:44.543299Z

I realise it might be impossible to refactor an existing codebase

István Karaszi 2024-10-11T08:04:46.767509Z

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

opqdonut 2024-10-11T08:05:01.116699Z

btw, another workaround might be to disable the strip-extra-keys-transformer by overriding the transformer that the reitit coercion uses

István Karaszi 2024-10-11T08:05:12.513029Z

I was trying that yesterday

István Karaszi 2024-10-11T08:05:19.106939Z

nil-ing out the transformer

István Karaszi 2024-10-11T08:05:26.296979Z

But that did not help

opqdonut 2024-10-11T08:05:35.850369Z

you probably want to still have st/json-transformer in there

István Karaszi 2024-10-11T08:05:58.897419Z

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

opqdonut 2024-10-11T08:06:09.389999Z

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&amp;cid=C7YF1SBT3

István Karaszi 2024-10-11T08:06:14.322329Z

as you can see I did multiple tries here

opqdonut 2024-10-11T08:06:47.785829Z

hmph. there might be another problem along the way then.

István Karaszi 2024-10-11T08:07:12.712009Z

Yeah, that’s why I have the feeling that the root cause lies somewhere deep

opqdonut 2024-10-11T08:07:51.228429Z

IMHO, the root cause is spec-tools. It shouldn't exist 😅

István Karaszi 2024-10-11T08:07:59.559939Z

Haha 😄

opqdonut 2024-10-11T08:08:03.520249Z

I've fixed some bugs in there and it just feels like whack-a-mole

🫣 1
István Karaszi 2024-10-11T08:14:27.283319Z

Anyhow, thank you very much for your help!

opqdonut 2024-10-11T08:21:04.953619Z

reopened https://github.com/metosin/reitit/issues/494

István Karaszi 2024-10-11T08:21:32.858979Z

Thank you very much!

opqdonut 2024-10-11T08:26:04.425649Z

added some content to https://github.com/metosin/spec-tools/issues/255

opqdonut 2024-10-11T08:26:27.956879Z

I'm afraid I won't be looking further into this right now, but I'll bump it in our open source backlog...

🙏 1
István Karaszi 2024-10-11T08:30:57.603449Z

Oh! I hope it is not related to this bug: https://clojure.atlassian.net/browse/CLJ-2079

István Karaszi 2024-10-11T08:31:16.926799Z

I ran into that here: https://clojurians.slack.com/archives/C1B1BB2Q3/p1723725302816599

opqdonut 2024-10-11T08:50:55.140909Z

funnily enough, we have a similar bug with malli, it seems! https://github.com/metosin/malli/issues/1112

István Karaszi 2024-10-11T09:00:07.817769Z

Now I’m really excited to see what’s underneath it all.

István Karaszi 2024-10-11T09:24:55.799419Z

Oh sweet baby jesus, the st/spec workaround messes up the Swagger doc generation

István Karaszi 2024-10-11T09:26:15.757189Z

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

István Karaszi 2024-10-11T09:31:53.777089Z

I am out of luck here

István Karaszi 2024-10-11T09:37:28.192919Z

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

opqdonut 2024-10-11T10:32:04.529179Z

aww that sucks

opqdonut 2024-10-11T10:33:17.443229Z

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!

István Karaszi 2024-10-11T10:34:55.564519Z

I believe that was failing as well, I just referred that as Swagger

István Karaszi 2024-10-11T10:35:13.601259Z

But I will check this after lunch

opqdonut 2024-10-11T10:35:40.006799Z

thanks

István Karaszi 2024-10-11T10:58:02.849389Z

Yeah, both /openapi.json and /swagger.json are failing

opqdonut 2024-10-11T11:02:09.247589Z

I'll try to formulate another bug against spec-tools for the openapi/swagger behaviour later today

🙏 1
opqdonut 2024-10-11T14:44:40.184999Z

https://github.com/metosin/spec-tools/issues/291

👍 1
István Karaszi 2024-10-11T15:16:07.379089Z

great! thank you very much!

István Karaszi 2024-10-10T20:41:36.954869Z

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"
  ]
}

István Karaszi 2024-10-10T20:42:19.614589Z

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"
  ]
}

István Karaszi 2024-10-10T20:53:36.492149Z

I’ve found https://github.com/metosin/reitit/issues/494 but this seems to be fixed

István Karaszi 2024-10-10T20:55:03.244859Z

But if I take that repro case, that still fails for me

István Karaszi 2024-10-10T20:56:22.467359Z

If I flip the s/or then the ::B case succeeds and the ::A case fails from the #494 repro case

opqdonut 2024-10-11T05:15:31.114359Z

just checking: are you sure you're not accidentally using an ancient version of spec-tools? that's where the fix was

opqdonut 2024-10-11T05:15:58.962149Z

but it sounds like you have a good repro, so feel free to open a new issue!

István Karaszi 2024-10-11T06:54:28.255599Z

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.