This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-19
Channels
- # aws (2)
- # babashka (4)
- # babashka-sci-dev (7)
- # beginners (92)
- # biff (7)
- # calva (64)
- # cider (2)
- # cljsrn (14)
- # clojure (8)
- # clojure-australia (5)
- # clojure-europe (14)
- # clojure-norway (8)
- # clojure-spec (36)
- # clojurescript (19)
- # component (15)
- # cursive (1)
- # data-science (6)
- # girouette (5)
- # hyperfiddle (3)
- # juxt (5)
- # leiningen (10)
- # lsp (7)
- # malli (12)
- # nbb (90)
- # polylith (1)
- # portal (11)
- # rdf (7)
- # reagent (6)
- # reitit (40)
- # remote-jobs (1)
- # shadow-cljs (21)
- # specter (5)
- # squint (83)
- # tools-deps (17)
- # vim (7)
Right now I just have this as my frontend routes:
(def routes
[["{*path}" :delegate]])
This just delegates every path to my SPA and work very well for my needs. However, I also need to create some download links which should go directly to my backend. How can I make reitit frontend routing ignore certain routes while still matching everything else?I think I need to bypass the routing though, right? The point is that I don’t want to match specific routes.
When you click a download link in plain HTML, provided the HTTP resource identifies as downloadable file, the browser will initiate the download and keep the history state the same, i.e. the path doesn’t change to /path/to/file.ext
. When Reitit matches a route, it inserts history and assumes that I manually initiate a download via CLJS, which I do no want to do — I want the regular browser behaviour, i.e. I want to bypass Reitit’s routing.
The trouble is that I need to match every route in the frontend except for certain routes, not that I need to match certain routes in addition to every route.
I just went with a prefixed catch-all route and use a different prefix for the download routes. Works fine.
Is there a simple way to conditionally apply parameter coercion when using the ring coercion middleware? For example, say I have a route like this:
["" {:post {:parameters {:multipart ::spec/some-spec
:form ::spec/some-spec}
:handler some-handler}}]
Can I make it such that either the multipart or form params are coerced, but not require both params to be there?I suppose I can push it down into the handler but just wondering if there is something I am missing
yeah there might be a misunderstanding on my part, but I get a spec error receiving multipart requests with this basic setup. I assume the situation would be the same if I had :query
there instead of :form
. As in, I don't know if there is a way to accept a certain set of parameters either through :form
or through :query
We've been using the coercion middlewares, but I don't think there would be an issue moving to an interceptor
i'm just reading the docs right now, they are implemented via interceptors, unless i'm reading wrong
I think the specific coercers we are using are implemented as middleware here: [Pluggable Coercion — metosin/reitit 0.5.18](https://cljdoc.org/d/metosin/reitit/0.5.18/doc/ring/pluggable-coercion)
yes, provided through reitit.ring
. Sorry, probably should have been more specific at the start of my question
just looking at this, it seems like the multipart interceptor has no knowledge of other parameters
the way i have used multipart is mainly via form data (form submits, or faux form submits - ajax). and multipart is using the form coercer in that case
however, here multipart is independent of the other parameters, so in the form coercer it would have to check to see if multipart is present, and then not do it's thing.
https://github.com/metosin/reitit/blob/master/modules/reitit-core/src/reitit/coercion.cljc looking at this it seems like the coercers are independent, and the spec code https://github.com/metosin/reitit/blob/master/modules/reitit-spec/src/reitit/coercion/spec.cljc is where you would have to implement your idea of conditional coercion
(-request-coercer [this type spec]
(let [spec (coercion/-compile-model this spec nil)
{:keys [formats default]} (transformers type)]
(fn [value format]
(if-let [transformer (or (get formats format) default)]
(let [coerced (st/coerce spec value transformer)]
(if (s/valid? spec coerced)
coerced
(let [transformed (st/conform spec coerced transformer)]
(if (s/invalid? transformed)
(let [problems (st/explain-data spec coerced transformer)]
(coercion/map->CoercionError
{:spec spec
:problems problems}))
(s/unform spec transformed)))))
value))))
probably in that codecool I am looking at the same sort of thing as well. Thanks for the second set of eyes, I'll ping back if anything interesting comes of it.
i think the thing you want is very a-typical, make it so all your forms are multipart on that resource (this is my approach), and remove your :form declaration (is this possible?)
Yeah that is totally an option, but we would be more robust with a workaround. We are hooking a route up to receive messages from an email forwarding service that we don't control. The service only sends multipart if the email it is forwarding has an attachment. I think if this stymies me for much longer we will just require that anyone submitting data over email must not include attachments
It is definitely atypical and not great but these are the requirements I have 🤷
thanks again for the help!
i think you have to do something a bit hacky, and fork the spec code for a bit, maybe get your thing working, and then maybe add some feature for other people to do the same thing as you.
i never really liked the idea of splitting multipart away from the other submission stuff
also, maybe in the multipart middleware handler, you could strip off the form coercer or something...
(-> request
(multipart-params/multipart-params-request options)
(coerced-request coercers)
(handler respond raise)))))
you have access to the whole request, just try and chop it up a bit 🙂Thanks again. I slept on it over the weekend and figured out I could get what I want by just adding a middleware that moves form params (if they exist) into the :multipart-params
key. Then, I only set coercion for multipart parameters, and I get coercion for both. Kind of hacky but it meets the requirement