This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-26
Channels
- # announcements (6)
- # babashka (29)
- # babashka-sci-dev (2)
- # beginners (129)
- # calva (9)
- # clara (16)
- # cljdoc (49)
- # clojure (125)
- # clojure-bay-area (3)
- # clojure-europe (55)
- # clojure-france (1)
- # clojuredesign-podcast (8)
- # clojurescript (85)
- # conjure (3)
- # core-logic (2)
- # cursive (1)
- # events (1)
- # honeysql (61)
- # jobs-discuss (23)
- # lsp (69)
- # malli (14)
- # nrepl (3)
- # off-topic (16)
- # portal (11)
- # re-frame (8)
- # releases (1)
- # ring (2)
- # shadow-cljs (12)
- # vim (42)
- # xtdb (18)
I'm using the :http-xhrio effect handler in an attempt to call a REST API:
(rf/reg-event-fx
:translation-request
(fn [{:keys [_db]} [_ rule]]
(let [body (edn->json rule)]
(println ":in translation-request - body" body)
{:http-xhrio {:method :post
:uri ""
:headers {"Content-Type" "application/json"
"Accept" "*/*"}
:body body
:timeout 9000
:format (ajax/json-request-format)
:response-format (ajax/text-response-format)
:on-success [:got-translation]
:on-failure [:got-translation-error]}})))
My server wraps the handler in wrap-json-body and wrap-json-response middleware and should be converting the input stream for the body into a :body attribute with the body's json value inside.
When I call the API call using Postman, everything is working fine. But when I make the call using the http-xhrio handler, the stream in the server is not converted and the API returns a null result. Does anyone see if I'm doing something wrong with the handling of the :translation-request event using the http-xhrio handler?Don't see anything obviously wrong, however:
• You shouldn't need :headers
at all (`content-type` should be set by :format
and accept
should be set by :response-format
, IIRC)
• You can see what's actually being sent in the Network tab of your browser's DevTools, and then compare it to what Postman sends
I took out the :headers attribute (leaving this in the code):
(rf/reg-event-fx
:translation-request
(fn [{:keys [_db]} [_ rule]]
(let [body (edn->json rule)]
(println ":in translation-request - body" body)
{:http-xhrio {:method :post
:uri ""
:body body
:timeout 9000
:format (ajax/json-request-format)
:response-format (ajax/text-response-format)
:on-success [:got-translation]
:on-failure [:got-translation-error]}})))
Postman sends a request with a Content-Type header of application/json, while the xhrio request is using a Content-Type header of application/x-www-form-urlencoded. I'm not sure why this is happening, as I tell the system that the type of the request is json in the :format attribute.Based on a search of the documentation and code for cljs-ajax (which the http-xhrio handler is based on), I found the following:
:format - specifies the format for the body of the request (Transit, JSON, etc.). Also sets the appropriate Content-Type header. Defaults to :transit if not provided.
So, it can be a keyword, even though the code documentation says you can pass it the request-format object, as well. So I set my request to:
(rf/reg-event-fx
:translation-request
(fn [{:keys [_db]} [_ rule]]
(let [body (edn->json rule)]
(println ":in translation-request - body" body)
{:http-xhrio {:method :post
:uri ""
:body body
:timeout 9000
:format :json
:response-format (ajax/text-response-format)
:on-success [:got-translation]
:on-failure [:got-translation-error]}})))
thinking that this might work. It didn't. The content type header seems to really be stuck on application/x-www-form-urlencoded, and I can't figure out how to produce a request having an application/json content type.Ah, try replacing :body
with :params
and remove the edn->json
call (unless it creates a CLJS object and not a string - then leave it as is).
From cljs-ajax
documentation:
> • :body
the exact data to send with in the request. If specified, both :params
and :request-format
are ignored. Note that you can submit js/FormData and other "raw" javascript types through this.
>
> • :params
- the parameters that will be sent with the request, format dependent: :transit
and :edn
can send anything, :json
, :text
and :raw
need to be given a map. GET
will add params onto the query string, POST
will put the params in the body
>
I got it working... On the way there, I started getting CORS messages that were finally alleviated by adding ring.cors.middleware to my handlers in my server:
(def allowed-origins [#".*"])
(def allowed-methods [:get :post :put])
(def allowed-headers #{:accept :content-type})
(defn wrap [handler]
(-> handler
(wrap-json-body {:keywords? true})
wrap-json-response
(wrap-cors :access-control-allow-origin allowed-origins
:access-control-allow-methods allowed-methods
:access-control-allow-headers allowed-headers)))
I also had to modify the code in the client to add the application/json content type:
(rf/reg-event-fx
:translation-request
(fn [{:keys [_db]} [_ rule]]
(let [body (edn->json rule)]
(println ":in translation-request - body" body)
{:http-xhrio {:method :post
:uri ""
:headers {"Content-Type" "application/json"
"Accept" "*/*"}
:body body
:timeout 9000
:response-format (ajax/text-response-format)
:on-success [:got-translation]
:on-failure [:got-translation-error]}})))
As usual, thanks for your help.