http-json-get-with-timeout

Clojure
(require '[clojure.edn :as edn]
         '[clojure.string :as str])

(import '[java.net URI]
        '[java.net.http HttpClient HttpRequest HttpResponse$BodyHandlers]
        '[java.time Duration])

(def ^:private client (HttpClient/newHttpClient))

;; JSON null becomes nil; the rest of JSON is already valid EDN.
(defn json->edn [s]
  (edn/read-string (str/replace s #"(?:\"(?:\\.|[^\"\\])*\")|null" #(if (= % "null") "nil" %))))

(defn get-json [url timeout-ms]
  (let [req (-> (HttpRequest/newBuilder (URI/create url))
                (.timeout (Duration/ofMillis timeout-ms))
                (.header "Accept" "application/json") (.GET) (.build))
        res (.send client req (HttpResponse$BodyHandlers/ofString))]
    (if (< (.statusCode res) 300)
      (json->edn (.body res))
      (throw (ex-info (str "HTTP " (.statusCode res)) {:url url})))))