Jorge D
Jorge D

Reputation: 43

ClojureScript: How to access (not just print) the result of an HTTP GET request

I am trying to build a simple client-server system with Clojure (server) and ClojureScript (client).

The server side is OK (everything is green on the browser's console, no CORS problems, etc.); the response is plain text ("true" or "false"). On the client side I am using basically the function included in the official cljs-http website

(defn get-request [str1 str2]
(go (let [response (<! (http/get "http://localhost:3000"
                                 {:query-params {"str1" str1
                                                 "str2" str2}}))]
  (prn response))))

Running this function on the REPL indicates that everything is fine and something map-like comes out of the async channel

cljs.user=> (b/get-request "foo" "bar")
#object[cljs.core.async.impl.channels.ManyToManyChannel]         ;; the result
cljs.user=> {:status 200, :success true, :body "false", [...]}   ;; output of `prn`

My question is: How can I actually get the response's body ouf of that ManyToManyChannel "object"?

How can I proceed?

Upvotes: 2

Views: 1276

Answers (2)

Jared Smith
Jared Smith

Reputation: 21926

It's Saturday morning and I'm feeling lazy so I didn't run this, but this should work:

(defn get-request [str1 str2]
  (go (<! (http/get "http://localhost:3000"
                    {:query-params {"str1" str1
                                    "str2" str2}}))))


(defn read-response [response-chan]
  (go (let [resp (<! response-chan)]
        (prn resp))))  ; <- the only place where you can "touch" resp!

(read-response (get-request "a" "b"))

The go block returns a channel that will receive the result you put into it in the request response (the returned form from the go block in your original).

The read function takes a channel and just reads from it, the last form just calls the second function with the result of calling the first.

Remember that channels are first-class constructs, you can pass them around, share them with multiple consumers, etc.

Upvotes: 1

Thomas Heller
Thomas Heller

Reputation: 4356

You cannot access the result of an async operation (eg. go) in a sync fashion. So the only way to get the actual response is in the async callback.

Getting the result in the REPL is a little tricky. You can store it in an atom and access it from the atom once the operation completes.

(def result-ref (atom nil))

(defn into-ref [chan]
  (go (reset! result-ref (<! chan))))

(into-ref
  (http/get "http://localhost:3000"
    {:query-params
     {"str1" str1
      "str2" str2}}))

@result-ref

Of course you can only access the result once the operation has actually completed. The REPL is a bit tricky for async operations but this trick might help.

Upvotes: 2

Related Questions