My web client (written in cljs
) connects to backend (written in clj
) which needs to make a few third party API calls. It has to be done on the server and then the result should be transformed in a specific way and sent back to the client.
Here's my handler for one of the urls
(defn get-orders [req]
(let [{:keys [sig uri]} (api-signature :get-orders)]
(client/get uri
{:async? true}
(fn [response] {:body "something"})
(fn [exception] {:body "error"}))))
Instead of returning {:body "something"}
, it is returning the following error:
No implementation of method: :render of protocol: #'compojure.response/Renderable found for class: org.apache.http.impl.nio.client.FutureWrapper
What am I doing wrong?
When you specify {:async? true}
, clj-http.client/get
will return a future which is a FutureWrapper
in the error message you got.
So if you don't need async, don't use it. This is an example of a synchronous ring handler which calls a third-party url and returns the response that got back.
(defn handler [request]
(response {:result (client/get "http://example.com")}))
If you really need async, use async version of ring handler.
(defn handler [request respond raise]
(client/get "http://example.com"
{:async? true}
(fn [response] (respond {:body "something"}))
(fn [exception] (raise {:body "error"}))))
Don't forget to config webserver adapter to use the async handler. For example, for Jetty, set :async?
flag to true
like so
(jetty/run-jetty app {:port 4000 :async? true :join? false})
If you want to concurrently call to multiple third-party urls and return once to web client, use promise to help
(defn handler [request]
(let [result1 (promise)
result2 (promise)]
(client/get "http://example.com/"
{:async? true}
(fn [response] (deliver result1 {:success true :body "something"}))
(fn [exception] (deliver result1 {:success false :body "error"})))
(client/get "http://example.com/"
{:async? true}
(fn [response] (deliver result2 {:success true :body "something"}))
(fn [exception] (deliver result2 {:success false :body "error"})))
(cond
(and (:success @result1)
(:success @result2))
(response {:result1 (:body @result1)
:result2 (:body @result2)})
(not (:success @result1))
(throw (ex-info "fail1" (:body @result1)))
(not (:success @result2))
(throw (ex-info "fail2" (:body @result2))))))