In previous blog posts I mention that Bidi and Silk are essentially equivalent. I don’t believe this anymore. I now prefer Silk and I can show you why with a little example. First, let’s define some routes:

(def silk-routes ( [[:home-page [[]]]
                                     [:about [["about"]]]]))

(def bidi-routes ["/" {""      :home-page
                       "about" :about-page}])

When it comes to defining routes, I find both a bit cryptic. Bidi feels a bit easier to read but I found it was harder to write in some scenarios.

Let’s parse some paths:

(bidi.bidi/match-route bidi-routes "/")
; => {:handler :home-page}

( silk-routes "/")
; => { :home-page, {:path []}, #object[ 0x7a46e3be ""],{:scheme nil, :user nil, :host nil, :port nil, :path [], :query {}, :fragment nil}}

(bidi.bidi/match-route bidi-routes "/about")
; => {:handler :about-page}

( silk-routes "/about")
; => { :about, {:path ["about"]}, #object[ 0x7a46e3be ""],{:scheme nil, :user nil, :host nil, :port nil, :path ["about"], :query {}, :fragment nil}}

So far I would consider them equivalent. Silk gives you more information about the route but is also more noisy. I personally dislike the namespaced keywords, but that’s easily solved with:

(defn sanitize-silk-keywords [matched-route]
  (rename-keys matched-route {    :name

The real difference, for me, comes when I try to parse /about?,which should be the same as /about and some lazy URL handling libraries emit the former rather than the latter. Silk first:

( silk-routes "/about?")
; => { :about, {:path ["about"]}, #object[ 0x7a46e3be ""],{:scheme nil, :user nil, :host nil, :port nil, :path ["about"], :query {}, :fragment nil}}

No surprised there. What about Bidi:

(bidi.bidi/match-route bidi-routes "/about?")
; => nil

Oops, what happened here? A bit of digging around lead me to the issue Why are query parameters not supported anymore? Essentially, Bidi’s design is that you shouldn’t route on query arguments (which I would agree in principle) and thus it relays on others to separate the two, something I don’t like at all. In a ClojureScript application it would requiring some pre-parsing of the URL, while Silk does it for you.

Silk also seems to support, if not routing, at least reporting port, host, user, scheme and even fragment. This can come in handy at some point. If you want to learn more about using Silk and Pushy, take a look at the blog post No-hashes bidirectional routing in re-frame with Silk and Pushy.

Picture by

%d bloggers like this: