This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-02-14
Channels
- # announcements (7)
- # babashka (13)
- # beginners (98)
- # biff (20)
- # calva (3)
- # clj-kondo (5)
- # clj-otel (6)
- # cljs-dev (96)
- # clojure (22)
- # clojure-austin (29)
- # clojure-conj (4)
- # clojure-europe (53)
- # clojure-nl (2)
- # clojure-norway (63)
- # clojure-uk (3)
- # clojurescript (18)
- # cursive (10)
- # data-science (11)
- # datalevin (2)
- # datomic (7)
- # deps-new (1)
- # fulcro (3)
- # graphql (1)
- # gratitude (4)
- # hyperfiddle (43)
- # kaocha (4)
- # malli (15)
- # pathom (6)
- # polylith (2)
- # reagent (3)
- # reitit (2)
- # releases (6)
- # remote-jobs (1)
- # rewrite-clj (45)
- # ring (4)
- # shadow-cljs (47)
- # sql (5)
- # xtdb (8)
I'm trying to implement a file-upload. Platypub provides an example, but it's in the context of using tinymce
, and I'd like to do something more like the htmx example (https://htmx.org/examples/file-upload/ ). Just copying that example, though, I get a 403, which I [think I] understand is due to the lack of the anti-forgery token in the headers; I'm finding it difficult to figure out how to inject that, in part, I suppose, because what client-side code I have so far is typescript with webpack configured to be picky, and htmx doesn't provide types (though there's this: https://github.com/leevigraham/typescript-htmx-types/blob/main/src/@types/htmx.org/index.d.ts). There are things I've thought to try, but I'm wondering if anyone here has already solved this problem and could help me avoid the rabbit-hole I'm slipping into.
It's currently looking like one of those days when the first thing on my todo-list, which was supposed to take 10m, eats the whole day and leaves me wanting to change careers 😛
Longshot but which version of biff are you working with?
If I'm not mistaken 0.6.0 automatically adds the anti-forgery tokens to every request
In older versions you have to do something yourself, give me a moment to confirm
:hx-headers (json/generate-string
{:x-csrf-token anti-forgery/*anti-forgery-token*})
in the versions I've used, biff/form adds it as a hidden input, and this file-upload is inside one, but I was figuring the multi-part/form-data changed things. oh, that easy?
That's assuming your issue is indeed caused by a missing anti-forgery token
If the htmx request is part of a form then you don't have to do anything, it should work out of the box (biff takes care of it), even before 0.6.0
hrmm- I guess it's something else then 😕 I've tried adding the ring-middleware for multipart uploads, but platypub doesn't use that, and I seem to be doing things essentially the same, apart from the platypub file-uploader being some javascript provided to tinymce I guess I'll try to verify the cause. any hints on how best to debug middleware stuff would be helpful
yeah, sound like the anti forgery token might not be the problem
I sometimes create a wrap-wtf
middleware that prints out the request + response, and then put it in various places in the middleware stack
I have some htmx upload code in yakread that I can share once I'm at my desk

Here's what the file input code looks like, for an image upload:
[:input {:type "file"
:accept "image/apng, image/avif, image/gif, image/jpeg, image/png, image/svg+xml, image/webp"
:name "image-file"
:class '[border-gray-300
rounded
text-black]
:hx-post "/upload-image"
:hx-target "#image-upload"
:hx-swap "outerHTML"
:hx-include "closest form"
:hx-indicator "#image-upload-indicator"
:hx-encoding "multipart/form-data"}]
Now that I'm looking at this again, I think other inputs from the containing form are only included if you do a regular form post, or if the form element is what's triggering the htmx request. In this case, the input element itself triggers the htmx request, and I think that's why I put :hx-include "closest form"
there; to make sure it included all the other params (including the csrf token)
this is the request handler by the way:
(defn upload-image [{:keys [s3/edge ad params multipart-params] :as ctx}]
(let [image-id (random-uuid)
file-info (get multipart-params "image-file")
url (str edge "/" image-id)
ctx (assoc-in ctx [:params :image] url)]
(s3/request ctx {:method "PUT"
:key image-id
:file (:tempfile file-info)
:headers {"x-amz-acl" "public-read"
"content-type" (:content-type file-info)}})
[:<>
(image-upload-input {:value url})
(preview (assoc ctx ::oob true))]))
I don't think you need to do anything with middleware
no problem!