ANN: bidi, a URI dispatch and formation library for Clojure

504 views
Skip to first unread message

Malcolm Sparks

unread,
Jan 1, 2014, 7:37:16 AM1/1/14
to clo...@googlegroups.com
I'd like to announce a new URI routing library called bidi.

If you're planning to write HTTP/web applications in Clojure in 2014, chances are you'll be including hyperlinks (URIs) in your pages/views/templates. After all, this is what the web is all about. But the code that includes/generates your URIs can get tightly coupled with the code that dispatches on them (Compojure routes, etc.), this can lead to broken links if you're not careful.

Having used Pedestal services in many of my systems, I'd made heavy use of the (url-for) function. But I found it difficult to extract the Pedestal routing code from the rest of the Pedestal back-end concepts. When I wanted to be able to use http-kit for another project, this prevented me from using Pedestal and I really missed the ability to form URIs - I wanted was the (url-for) function back!

Like Pedestal, bidi starts with a data description of your routes - acting as the basis for both the generation of URIs and the dispatch to your handlers. However, bidi only offers URI routing and formation - nothing else - so it can be used for 'traditional' Ring web apps, http-kit, Liberator and so on. With a little work it should work well with ClojureScript too, since it is based on protocols rather than macros.

You can find more about bidi, with code examples, here: https://github.com/juxt/bidi

While I've been thinking about writing bidi for a long time (hoping someone else more capable than me would write it!), the actual code is very new and so all the usual disclaimers apply. However, I'd be very grateful for feedback on this new library - what you like and dislike about it, initial impressions, complaints, alternatives you know about and any questions etc..

And finally I'd like to wish everyone on this list a Happy New Year and the very best for your Clojure hacking activies in 2014.


Malcolm

JUXT - https://juxt.pro


Adrian Mowat

unread,
Jan 1, 2014, 3:06:31 PM1/1/14
to clo...@googlegroups.com
Hi Malcolm,

I'm working through the examples and I am getting exceptions when I try defining multiple routes.  I noticed the 1.8.0 is mentioned in the docs but the highest version on clojars is 1.7.0.  Is clojars up to date.

Stacktraces as follows

user=> (def routes ["/" {"index.html" :index
  #_=>                         "articles/" {"index.html" :article-index
  #_=>                                      "article.html" :article}}])
#'user/routes
user=> (match-route routes "/index.html")

java.lang.IllegalArgumentException: No implementation of method: :resolve-handler of protocol: #'bidi.bidi/Matched found for class: clojure.lang.PersistentHashMap
                                           clojure.core/-cache-protocol-fn         core_deftype.clj:  541
                                                   bidi.bidi/eval3017/fn/G                 bidi.clj:   87
                                                      bidi.bidi/match-pair                 bidi.clj:   97
                                                     bidi.bidi/match-route                 bidi.clj:  193
                                                clojure.lang.RestFn.invoke              RestFn.java:  425
                                                      user$eval3329.invoke           NO_SOURCE_FILE:    1
user=>                                                 clojure.lang.Compiler.eval            Compiler.java: 6619
                                                clojure.lang.Compiler.eval            Compiler.java: 6582
                                                         clojure.core/eval                 core.clj: 2852
                                      clojure.main/repl/read-eval-print/fn                 main.clj:  259
                                         clojure.main/repl/read-eval-print                 main.clj:  259
                                                      clojure.main/repl/fn                 main.clj:  277
                                                         clojure.main/repl                 main.clj:  277
                                                clojure.lang.RestFn.invoke              RestFn.java: 1096
             clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn   interruptible_eval.clj:   56
                                            clojure.lang.AFn.applyToHelper                 AFn.java:  159
                                                  clojure.lang.AFn.applyTo                 AFn.java:  151
                                                        clojure.core/apply                 core.clj:  617
                                               clojure.core/with-bindings*                 core.clj: 1788
                                                clojure.lang.RestFn.invoke              RestFn.java:  425
                clojure.tools.nrepl.middleware.interruptible-eval/evaluate   interruptible_eval.clj:   41
clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn   interruptible_eval.clj:  171
                                                      clojure.core/comp/fn                 core.clj: 2330
             clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn   interruptible_eval.clj:  138
                                                      clojure.lang.AFn.run                 AFn.java:   24
                         java.util.concurrent.ThreadPoolExecutor.runWorker  ThreadPoolExecutor.java: 1110
                        java.util.concurrent.ThreadPoolExecutor$Worker.run  ThreadPoolExecutor.java:  603
                                                      java.lang.Thread.run              Thread.java:  722
(match-

user=> 

user=> (path-for routes :index)

java.lang.IllegalArgumentException: No implementation of method: :unresolve-handler of protocol: #'bidi.bidi/Matched found for class: clojure.lang.PersistentHashMap
                                           clojure.core/-cache-protocol-fn         core_deftype.clj:  541
                                                   bidi.bidi/eval3017/fn/G                 bidi.clj:   87
                                                    bidi.bidi/unmatch-pair                 bidi.clj:  149
                                                        bidi.bidi/path-for                 bidi.clj:  201
                                                clojure.lang.RestFn.invoke              RestFn.java:  425
                                                      user$eval3331.invoke           NO_SOURCE_FILE:    1
                                                clojure.lang.Compiler.eval            Compiler.java: 6619
                                                clojure.lang.Compiler.eval            Compiler.java: 6582
                                                         clojure.core/eval                 core.clj: 2852
                                      clojure.main/repl/read-eval-print/fn                 main.clj:  259
                                         clojure.main/repl/read-eval-print                 main.clj:  259
                                                      clojure.main/repl/fn                 main.clj:  277
                                                         clojure.main/repl                 main.clj:  277
                                                clojure.lang.RestFn.invoke              RestFn.java: 1096
             clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn   interruptible_eval.clj:   56
                                            clojure.lang.AFn.applyToHelper                 AFn.java:  159
                                                  clojure.lang.AFn.applyTo                 AFn.java:  151
                                                        clojure.core/apply                 core.clj:  617
                                               clojure.core/with-bindings*                 core.clj: 1788
user=>                                                 clojure.lang.RestFn.invoke              RestFn.java:  425
                clojure.tools.nrepl.middleware.interruptible-eval/evaluate   interruptible_eval.clj:   41
clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn   interruptible_eval.clj:  171
                                                      clojure.core/comp/fn                 core.clj: 2330
             clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn   interruptible_eval.clj:  138
                                                      clojure.lang.AFn.run                 AFn.java:   24
                         java.util.concurrent.ThreadPoolExecutor.runWorker  ThreadPoolExecutor.java: 1110
                        java.util.concurrent.ThreadPoolExecutor$Worker.run  ThreadPoolExecutor.java:  603
                                                      java.lang.Thread.run              Thread.java:  722

Malcolm Sparks

unread,
Jan 1, 2014, 3:16:50 PM1/1/14
to clo...@googlegroups.com
Hi Adrian,

Yes, it was the missing clojars deployment. 1.8.0 is up there now. 1.7.0 doesn't have the map representation, which I added to the existing vector-of-vectors syntax and moved the README examples to. Please try now.

Regards,

Malcolm


--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/Ueeh-Sbw-AI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Adrian Mowat

unread,
Jan 1, 2014, 3:40:59 PM1/1/14
to clo...@googlegroups.com
HI Malcolm

Yup, that's much better.  Thanks for the quick reply

Cheers

Adrian
Reply all
Reply to author
Forward
0 new messages