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 (domkm.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}

(domkm.silk/arrive silk-routes "/")
; => {:domkm.silk/name :home-page, :domkm.silk/pattern {:path []}, :domkm.silk/routes #object[domkm.silk.Routes 0x7a46e3be "domkm.silk.Routes@7a46e3be"], :domkm.silk/url #domkm.silk.URL{:scheme nil, :user nil, :host nil, :port nil, :path [], :query {}, :fragment nil}}

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

(domkm.silk/arrive silk-routes "/about")
; => {:domkm.silk/name :about, :domkm.silk/pattern {:path ["about"]}, :domkm.silk/routes #object[domkm.silk.Routes 0x7a46e3be "domkm.silk.Routes@7a46e3be"], :domkm.silk/url #domkm.silk.URL{: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 {:domkm.silk/name    :name
                              :domkm.silk/pattern :pattern
                              :domkm.silk/routes  :routes
                              :domkm.silk/url     :url}))

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:

(domkm.silk/arrive silk-routes "/about?")
; => {:domkm.silk/name :about, :domkm.silk/pattern {:path ["about"]}, :domkm.silk/routes #object[domkm.silk.Routes 0x7a46e3be "domkm.silk.Routes@7a46e3be"], :domkm.silk/url #domkm.silk.URL{: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 MartialArtsNomad.com

%d bloggers like this: