This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-07
Channels
- # babashka (30)
- # beginners (49)
- # calva (22)
- # cider (9)
- # clara (2)
- # clj-commons (1)
- # cljdoc (1)
- # clojars (7)
- # clojure (153)
- # clojure-australia (2)
- # clojure-europe (45)
- # clojure-italy (3)
- # clojure-losangeles (1)
- # clojure-nl (17)
- # clojure-portugal (3)
- # clojure-uk (6)
- # clojurescript (21)
- # conjure (4)
- # copenhagen-clojurians (5)
- # cryogen (3)
- # cursive (19)
- # datahike (14)
- # datascript (4)
- # datomic (9)
- # events (5)
- # fulcro (23)
- # graalvm (1)
- # gratitude (4)
- # helix (2)
- # holy-lambda (5)
- # improve-getting-started (2)
- # jobs (10)
- # kaocha (1)
- # leiningen (1)
- # liquid (8)
- # membrane (81)
- # off-topic (88)
- # polylith (29)
- # quil (1)
- # reitit (2)
- # remote-jobs (8)
- # reveal (8)
- # sci (1)
- # shadow-cljs (14)
- # specter (4)
- # sql (5)
- # tools-build (11)
- # tools-deps (5)
I'm having trouble getting file uploads to work as described in https://book.fulcrologic.com/#FileUpload. My server-side mutation does not seem to receive ::file-upload/files
, instead getting:
#p[sheluchin.mutations/import-notes:10] params => #:com.fulcrologic.fulcro.networking.file-upload
{:uploads [#:file {:content {}, :name "test.txt"}]}
I think I have my middleware setup correctly:
;; server
(defn wrap-api [handler uri]
(fn [request]
(if (= uri (:uri request))
(server/handle-api-request
(:transit-params request)
(fn [tx] (api-parser {:ring/request request} tx)))
(handler request))))
(def middleware
(-> not-found-handler
(wrap-api "/api")
(file-upload/wrap-mutation-file-uploads {})
(server/wrap-transit-params)
(server/wrap-transit-response)
(wrap-multipart-params)
(wrap-resource "public")
wrap-content-type))
;; client
(def request-middleware
(->
(http/wrap-fulcro-request)
(file-upload/wrap-file-upload)))
(defonce app
(app/fulcro-app
{:remotes
{:remote (http/fulcro-http-remote
{:url "/api"
:request-middlware request-middleware})}}))
Any tips for what I might be doing wrong? I tried to do some debugging and found that this always returns false:
#p[com.fulcrologic.fulcro.networking.file-upload/wrap-mutation-file-uploads:75] (transaction-with-uploads? req) => false
I added that one but still no luck:
(def middleware
(-> not-found-handler
(wrap-api "/api")
(file-upload/wrap-mutation-file-uploads {})
(server/wrap-transit-params)
(server/wrap-transit-response)
(wrap-keyword-params)
(wrap-multipart-params)
(wrap-resource "public")
wrap-content-type))
I'm also not sure where wrap-file-uploads
comes from, GH doesn't seem to know about it https://github.com/search?q=wrap-file-uploads&type=code
I'm sending the file by submitting to this input:
(input
{:type "file"
:accept ".txt"
:onChange (fn [evt]
(let [files (file-upload/evt->uploads evt)
params {}]
(comp/transact! app
[(m/import-notes (file-upload/attach-uploads params files))])))}))
The parser
called in wrap-api
is the pathom parser, correct? I have it defined as such:
(defn api-parser
([query] (api-parser {} query))
([env query]
(log/info "Process" query)
(pathom-parser #p env query)))
and it logs:
2021-10-07T14:38:08.946Z xps INFO [sheluchin.parser:43] - Process [(sheluchin.mutations/import-notes {:com.fulcrologic.fulcro.networking.file-upload/uploads [{:file/name "test.txt", :file/content {}}]})]
I use wrap-defaults
, with the following options:
:ring.middleware/defaults-config
{:params {:keywordize true
:multipart true
:nested true
:urlencoded true}
:cookies true
:responses {:absolute-redirects true
:content-types true
:default-charset "utf-8"
:not-modified-responses true}
:static {:resources "public"}
:session true
:security {:anti-forgery false
:hsts true
:ssl-redirect false
:frame-options :sameorigin
:xss-protection {:enable? true
:mode :block}}}
in dev at leastbut what you have is all that should be required…could be how you’re submitting the files
did you look at the low-level network request? It is a multipart form submission with the files attached as parts.
Hmm, inspecting the request gives me this error, which I don't see show up in the REPL anywhere:
[
"^ ",
"~$sheluchin.mutations/import-notes",
"class java.lang.IllegalArgumentException: Cannot open <nil> as a Reader."
]
> could be how you’re submitting the files Could you elaborate on this point? Do you mean I need to do more in the UI than just put an input with an onChange that submits the transaction? There's nothing wrapping it right now, it's right in the root component. I'm just trying to make it as simple as possible until it works. Short of me being unaware of something obvious, I guess I'm going to go through the ring docs and get a deeper understanding of what all the middleware code is doing. Can't hurt 🙂
I think your problem is that you have to properly add the file uploads TO the mutation
(comp/transact! this [(settings/save-settings (file-upload/attach-uploads params files))])
The js console in chrome, network tab (not fulcro inspect network)…you can click on the network request that contains files, and it should ahve a mime type of multipart/form-data
. If you then show the raw content, you’ll see sections separated by a random string boundary. The file(s) will be base64 encoded content in there, and the transaction will be encoded in the top part. If it does not look like that, then the client is the problem
That snippet looks exactly like what I have:
(input
{:type "file"
:accept ".txt"
; :multiple true
:onChange (fn [evt]
(let [files (file-upload/evt->uploads evt)
params {}]
(comp/transact! this
[(m/import-notes (file-upload/attach-uploads params #p files))])))})
But it is not coming across as multipart/form-data
. Request headers:
POST /api HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 174
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: ";Not A Brand";v="99", "Chromium";v="94"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36
sec-ch-ua-platform: "Linux"
Content-Type: application/transit+json
Accept: */*
Origin:
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer:
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
app setup:
(ns sheluchin.application
(:require
[com.fulcrologic.fulcro.application :as app]
[com.fulcrologic.fulcro.networking.http-remote :as http]
[com.fulcrologic.fulcro.networking.file-upload :as file-upload]
[sheluchin.specs]))
(def request-middleware
(->
(http/wrap-fulcro-request)
(file-upload/wrap-file-upload)))
(defonce app
(app/fulcro-app
{:remotes
{:remote (http/fulcro-http-remote
{:url "/api"
:request-middlware request-middleware})}}))
My God... deepest apologies for taking up your time. On the bright side, it gave me a reason to look through a good bit of Fulcro source. Many thanks for your endless patience @U0CKQ19AQ.