A simple routing library for ClojureScript
JavaScript Clojure Shell
Latest commit 53586fb Jan 12, 2017 @niwinz niwinz Set version to 1.4.0.

README.adoc

bide

Clojars Project

Introduction

A simple routing library for ClojureScript that uses Express-like syntax.

Egiak ez ditu bi bide

— A Basque proverb.

Install

Add the following dependency to your project.clj file:

[funcool/bide "1.4.0"]

User Guide

Just import the core namespace and start building the router:

(ns myapp.core
  (:require [bide.core :as r]))

(def router
  (r/router [["/api/auth" :myapp/auth]
             ["/api/users/:id" :myapp/user-by-id]]))

Now, you can perform basic operations such as match and resolve:

(r/match router "/api/auth")
;; => [:myapp/auth nil nil]

(r/match router "/api/users/1")
;; => [:myapp/user-by-id {:id "1"} nil]

(r/match router "/api/users/id?foobar=1")
;; => [:myapp/user-by-id {:id "1"} {:foobar "1"}]

(r/match router "/api/other")
;; => nil

(r/resolve router :myapp/auth)
;; => "/api/auth"

(r/resolve router :myapp/user-by-id {:id 2})
;; => "/api/users/2"

(r/resolve router :myapp/user-by-id {:id 2} {:foobar 1})
;; => "/api/users/2?foobar=1"

In addition, you can integrate it in your ClojureScript web application using the provided builtin helpers. It uses goog.History API under the hood:

(defn on-navigate
  "A function which will be called on each route change."
  [name params query]
  (println "Route change to: " name params query))

(r/start! router {:default :myapp/auth
                  :on-navigate on-navigate})

Finally, you can force the navigation trigger by using the navigate! helper function:

(r/navigate! router :myapp/user-by-id {:id 10})

How to Contribute?

Just open an issue or PR ;)

FAQ

Why another routing library?

Existing solutions out there are complex and generally bloated wih irrelevant documentation.

Most libraries work with native Clojure data structures for representing the routing configuration. It’s a great idea, but it does not work very well once your proyect scales. Things get out of hand pretty fast.

An example of this with bidi routing library:

(def routes
  ["/" [["auth/login" :auth/login]
        [["auth/recovery/token/" :token] :auth/recovery]
        ["workspace/" [[[:project-uuid "/" :page-uuid] :workspace/page]]]]])

The mental effort required to read and understand the configuration defined like this is considerable. Now, let’s see an example using bide:

(def routes
  [["/auth/login" :auth/login]
   ["/auth/recovery/token/:token" :auth/recovery]
   ["/workspace/:project-uuid/:page-uuid" :workspace/page]])

As you can imagine, a simple library like bide does not offer all the features provided by other solutions. New features will be added on-demand. However, we plan to stay as small and simple as possible.

How fast is bide?

Before talking about real performance comparisons and benchmarks, you should know that bide design is very simple and maybe can be considered naive. The worst case for the matching algorithm is O(N) and O(1) for resolve operation.

Considering that having thousands of entries is very unlikely to happen, the match algorithm works pretty well. This is a comparison against the same operations with bidi:

$ node out/benchmarks.js
op=resolve lib=bidi ops=10000
"Elapsed time: 90.989215 msecs"
op=resolve lib=bide ops=10000
"Elapsed time: 19.447844 msecs"
op=match lib=bidi ops=10000
"Elapsed time: 1070.330668 msecs"
op=match lib=bide ops=10000
"Elapsed time: 98.864120 msecs"

I’ve been a bidi user for quite some time, that’s why I choose this library to run the benchmarks.

License

bide is licensed under BSD (2-Clause) license.