Как я могу сделать http-вызов в clojure/ring?
Мой веб-клиент (написано в cljs
) подключается к бэкэнду (написано в clj
), который должен сделать несколько вызовов API сторонних производителей. Это должно быть сделано на сервере, а затем результат должен быть преобразован определенным образом и отправлен обратно клиенту.
Вот мой обработчик для одного из URL
(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"}))))
Вместо возвращения {:body "something"}
, он возвращает следующую ошибку:
No implementation of method: :render of protocol: #'compojure.response/Renderable found for class: org.apache.http.impl.nio.client.FutureWrapper
Что я делаю неправильно?
1 ответ
Когда вы указываете {:async? true}
, clj-http.client/get
вернет будущее, которое является FutureWrapper
в сообщении об ошибке, которое вы получили.
Так что, если вам не нужен асинхронный режим, не используйте его. Это пример синхронного обработчика звонков, который вызывает сторонний URL и возвращает ответ, который был получен.
(defn handler [request]
(response {:result (client/get "http://example.com")}))
Если вам действительно нужна асинхронность, используйте асинхронную версию обработчика кольца.
(defn handler [request respond raise]
(client/get "http://example.com"
{:async? true}
(fn [response] (respond {:body "something"}))
(fn [exception] (raise {:body "error"}))))
Не забудьте настроить адаптер веб-сервера для использования асинхронного обработчика. Например, для Jetty, установите :async?
флаг для true
вот так
(jetty/run-jetty app {:port 4000 :async? true :join? false})
Если вы хотите одновременно вызывать несколько сторонних URL-адресов и возвращаться один раз в веб-клиент, используйте обещание, чтобы помочь
(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))))))