15

In Clojure / Compojure, how do I convert a map to a URL query string?

{:foo 1 :bar 2 :baz 3}

to

foo=1&bar=2&baz=3

Is there any utility method to do this in compojure?

Brad Koch
  • 19,267
  • 19
  • 110
  • 137
Sathish
  • 20,660
  • 24
  • 63
  • 71
  • Possible duplicate of [Clojure building of URL from constituent parts](http://stackoverflow.com/questions/3644125/clojure-building-of-url-from-constituent-parts) – Brad Koch Feb 21 '17 at 14:27

3 Answers3

27

Yes, there is a utility for this already that doesn't involve Hiccup or rolling your own string/join/URLEncoder function:

user=> (ring.util.codec/form-encode {:foo 1 :bar 2 :baz 3})
"foo=1&bar=2&baz=3"
user=>

Compojure depends on ring/ring-core, which includes ring.util.codec, so you already have it.

Lispnik
  • 709
  • 5
  • 7
7

Something like:

(defn params->query-string [m]
     (clojure.string/join "&" (for [[k v] m] (str (name k) "=" v))))

should do it...

REPL session:

user> (defn params->query-string [m]
         (clojure.string/join "&" 
            (for [[k v] m] 
               (str (name k) "="  (java.net.URLEncoder/encode v)))))
#'user/params->query-string
user> (params->query-string {:foo 1 :bar 2 :baz 3})
"foo=1&bar=2&baz=3"
user> 
sw1nn
  • 7,278
  • 1
  • 26
  • 36
  • 4
    I might also use `java.net.URLEncoder.encode` on each value in the map, i.e. `(for [[k v] m] (str (name k) "=" (java.net.URLEncoder/encode v)))`. – user100464 Mar 17 '12 at 01:21
  • I did the same thing, but Is there a utility method to do this? – Sathish Mar 17 '12 at 05:36
  • 9
    @Sathish [Hiccup](http://weavejester.github.com/hiccup/) provides some [relevant functionality](http://weavejester.github.com/hiccup/hiccup.util.html#var-url): `(hiccup.util/url "/hello" {:a 1 :b 2}) => "/hello?a=1&b=2"`. If you don't want to add a dependency on Hiccup just for a single utility function, writing the function yourself really isn't a big deal. – Matthias Benkard Mar 17 '12 at 14:10
  • 1
    i'm sorry, but it is a big deal if the main answer doesn't do it right by omitting the encoding. people make mistakes; use a library. – andrew cooke Apr 13 '12 at 13:52
  • @andrew cooke - agree - I updated my answer with user100464 suggestion. – sw1nn Apr 13 '12 at 13:55
0
(defn to-query [inmap]
    (->> inmap
       (map (fn [[f s]] (str (name f) "=" (java.net.URLEncoder/encode (str s) "UTF-8"))))
       (clojure.string/join '&)
       ))

This code removes ':' from keywords, but will throw exception if keywords are numbers.

(to-query {:foo 1 :bar 2 :baz 3})
=> "foo=1&bar=2&baz=3"
wendyL
  • 1
  • 1