Compojure re-expression to match trailing slash

Maybe I'm just an idiot, but I can't set up a match for an extra slash in Clojure.

lein repl REPL started; server listening on localhost port 47383 user=> (use 'ring.mock.request 'clout.core) nil user=> (route-matches "/article/" (request :get "/article/")) {} user=> (route-matches "/article/?" (request :get "/article")) nil user=> (route-matches "/article/?" (request :get "/article/")) nil user=> (route-matches #"/article/?" (request :get "/article/")) java.lang.IllegalArgumentException: No implementation of method: :route-matches of protocol: #'clout.core/Route found for class: java.util.regex.Pattern (NO_SOURCE_FILE:0) 

What regular expression can I use to match an extra slash in Compojure?

+7
source share
3 answers

The path string expected by clout as the first argument to route-matches is not a regular expression, but a string that can contain keywords and a wildcard character * .

I believe clout does not support defining routes that ignore trailing slashes. You can solve the problem with a middleware function that removes trailing slashes. The following functions were taken from the old version of the compojure source code (before the big refactoring), I could not find out if they moved to a new place. Here is the original commit that introduced these features.

 (defn with-uri-rewrite "Rewrites a request uri with the result of calling f with the request original uri. If f returns nil the handler is not called." [handler f] (fn [request] (let [uri (:uri request) rewrite (f uri)] (if rewrite (handler (assoc request :uri rewrite)) nil)))) (defn- uri-snip-slash "Removes a trailing slash from all uris except \"/\"." [uri] (if (and (not (= "/" uri)) (.endsWith uri "/")) (chop uri) uri)) (defn ignore-trailing-slash "Makes routes match regardless of whether or not a uri ends in a slash." [handler] (with-uri-rewrite handler uri-snip-slash)) 
+5
source

Here is the condensed version of the dependency-free middleware:

 (defn with-ignore-trailing-slash [handler] (fn [request] (let [uri (request :uri) clean-uri (if (and (not= "/" uri) (.endsWith uri "/")) (subs uri 0 (- (count uri) 1)) uri)] (handler (assoc request :uri clean-uri))))) 

Bug fixes fixed.

+1
source

For those who are looking for an even more concise solution :)

 (defn- with-ignore-trailing-slash [handler] (fn [request] (let [uri (request :uri) clean-uri (str/replace uri #"^(.+?)/+$" "$1")] (handler (assoc request :uri clean-uri))))) 
0
source

All Articles