juxt / bidi

Bidirectional URI routing

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Route Segments with spaces in them dont get matched...

twillis opened this issue · comments

Was trying out some things because I want to move an app off of secretary. This could be a misunderstanding on my part. but this is surprising that path-for can give me a url that wont match.

(ns apollo.client.routes
  (:require [bidi.bidi :as bidi]))


(def routes ["/" {"" :home-page
                 ["artists/" :artist] {"" :artist-detail
                                       ["/albums/" :album] :album-detail}
                 true :not-found}])

(def test-route "/artists/Faith No More/albums/Angel Dust")
(= test-route (bidi/path-for routes :album-detail :artist "Faith No More" :album "Angel Dust")) # true
(bidi/match-route routes test-route)  # {:handler :not-found}

If you URLEncode, it still doesn't work. :\

@twillis I found a workaround. If you use [#".+" :artist] and [#".+" :album] instead of the bare keywords it'll work. :)

@solussd thanks for the suggestion, I will give that a shot.

@solussd thanks for the workaround, I was really struggling to understand how to deal with spaces and colons.

Another workaround if you want to have this applied globally is to overwrite the protocol for matching pattern segments:

In my case I had to allow colons on dozens of endpoints and did it that way:

    (extend-protocol bidi.bidi/PatternSegment
      clojure.lang.Keyword
      (segment-regex-group [_] "[A-Za-z0-9\\-\\_\\.\\:]+")
      (param-key [this] this)
      (transform-param [_] identity)
      (unmatch-segment [this params]
        (if-let [v (this params)]
          (bidi.bidi/encode-parameter v)
          (throw (ex-info (str "Cannot form URI without a value given for "
                               this " parameter")
                          {})))))

Maybe that could mean this would be nicer to have segment-regex-group in a separate protocol to avoid the repetition of the other functions involved.

Thanks for bidi! It's lovely, we use it every day, and if it didn't exist we'd have to start by inventing it.

@twillis I found a workaround. If you use [#".+" :artist] and [#".+" :album] instead of the bare keywords it'll work. :)

This workaround gets it to match, but for me, in cljs, it's breaking the :route-params:

cljs.user=> (require '[bidi.bidi :as bidi])
nil
cljs.user=> (def routes ["/" [["a/" {[:b] :a}]]])
#'cljs.user/routes
cljs.user=> (bidi/match-route routes "/a/b")
{:route-params {:b "b"}, :handler :a}

Cool.

cljs.user=> (bidi/match-route routes "/a/b%20f")
nil

That's this issue, %20 causes it to fail to match.

cljs.user=> (def routes ["/" [["a/" {[#".+" :b] :a}]]])
#'cljs.user/routes
cljs.user=> (bidi/match-route routes "/a/b%20f")
{:route-params {:b "f"}, :handler :a}

This now matches, but I expected :route-params {:b "b f"} --- perhaps I did the regex wrong?

cljs.user=> (def routes ["/" [["a/" {[#"(.+)" :b] :a}]]])
#'cljs.user/routes
cljs.user=> (bidi/match-route routes "/a/b%20f")
{:route-params {:b "b "}, :handler :a}
cljs.user=> 

I tried to get clever with the parens, but now the route param is "b " (it dropped the last character of the string, so the 'f' was lost).

Hopefully someone here can help! Regardless, thanks to all for your time and consideration.

Wow, I just lost too much time trying to figure out why a url-encoded email in the path parms works in clojure but not clojurescript with[#".*" :email]. Thanks for the workaround @harold