url-query-string-round-trip
Clojure
(require '[clojure.string :as str])
(import '[java.net URLDecoder URLEncoder]
'[java.nio.charset StandardCharsets])
(defn- encode [s] (URLEncoder/encode (str s) StandardCharsets/UTF_8))
(defn- decode [s] (URLDecoder/decode (str s) StandardCharsets/UTF_8))
(defn query-string
"Builds a=1&b=two from a map, skipping nil values; keys may be keywords."
[params]
(->> params (remove (comp nil? val))
(map (fn [[k v]] (str (encode (name k)) "=" (encode v))))
(str/join "&")))
(defn parse-query
"Parses a query string into {key [values]}, URL-decoding both sides."
[qs]
(reduce (fn [m pair]
(let [[k v] (str/split pair #"=" 2)]
(update m (decode (or k "")) (fnil conj []) (decode (or v "")))))
{} (remove str/blank? (str/split (or qs "") #"&"))))