Skip to content

Instantly share code, notes, and snippets.

@souenzzo

souenzzo/java_http.clj

Last active Mar 22, 2020
Embed
What would you like to do?
(ns com.wsscode.pathom.diplomat.http.java-http
(:require [com.wsscode.pathom.diplomat.http :as http]
[clojure.spec.alpha :as s]
[clojure.core.async :as async]
[clojure.string :as string]
[clojure.data.json :as json])
(:import (java.net.http HttpResponse$BodyHandlers HttpRequest HttpClient HttpResponse HttpHeaders HttpRequest$BodyPublishers)
(java.net URI)
(java.util.function Function BiPredicate)
(java.util Optional)))
(set! *warn-on-reflection* true)
(defn build-request
[{::http/keys [url content-type accept as body headers form-params method]
:or {headers {}}
:as env}]
(let [uri (URI/create url)
method (string/upper-case (http/request-method env))
version (Optional/empty)
timeout (Optional/empty)
headers (HttpHeaders/of (cond-> headers
content-type (assoc "content-type" [(http/encode-type->header content-type)]))
(reify BiPredicate
(test [this a b]
true)))
expect-continue false
body-publisher (if form-params
(Optional/of
(HttpRequest$BodyPublishers/ofString
(json/write-str form-params)))
(Optional/empty))]
(proxy [HttpRequest] []
(uri [] uri)
(method [] method)
(version [] version)
(timeout [] timeout)
(headers [] headers)
(expectContinue [] expect-continue)
(bodyPublisher [] body-publisher))))
(defn build-response-map
[{::http/keys [as]} ^HttpResponse response]
(let [headers (into {}
(comp
(map (fn [[k v]]
[k (first v)])))
(.map (.headers response)))]
{::http/status (.statusCode response)
::http/body (if (and (= as ::http/json)
(string/starts-with? (string/lower-case (get headers "content-type"))
"application/json"))
(json/read-str (.body response)
:key-fn keyword)
(.body response))
::http/headers headers}))
(defn request
[]
(let [client (HttpClient/newHttpClient)]
(fn [env]
(s/assert ::http/request env)
(let [request (build-request env)]
(build-response-map env (.send client request (HttpResponse$BodyHandlers/ofString)))))))
(defn request-async
[]
(let [client (HttpClient/newHttpClient)]
(fn [env]
(s/assert ::http/request env)
(let [request (build-request env)
chan (async/promise-chan (map (partial build-response-map env)))]
(doto (.sendAsync client request (HttpResponse$BodyHandlers/ofString))
(.thenApply (reify Function
(apply [this response]
(async/put! chan response)))))
chan))))
(comment
(http/request {::http/driver (request)
::http/url (str "https://api.github.com/graphql?access_token=" (System/getenv "GITHUB_TOKEN"))
::http/as ::http/json
::http/content-type ::http/json
::http/form-params {:query "query { __schema { queryType { name } } }"}})
=> {::http/status 200,
::http/headers {"server" "GitHub.com",,,}
::http/body {:data {:__schema {:queryType {:name "Query"}}}}})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.