Re: (newbie) redirect server/contextRoot to servet/contextRoot/ (or help with relative urls)

251 views
Skip to first unread message

James Reeves

unread,
Jan 16, 2013, 8:51:01 AM1/16/13
to Compojure
If you're using Hiccup, have you tried using the wrap-base-url middleware?

- James


On 16 January 2013 13:41, Colin Yates <colin...@gmail.com> wrote:
Hi,

tl;dr I am serving a hiccup template with relative links (i.e. "lib/extjs...js") from my "/" route.  It works if I visit myserver/contextRoot/ but not myserver/contextRoot - how can I force contextRoot to be contextRoot/ ?

[longer version]
I am having a world of joy :) getting my app to work properly when run by "lein run server" without a context root and when served from tomcat with a context root.  I have solved most of the problem by using relative URLs, as expected.  It all works beautifully if I visit /index.html (because everything is relative to the directory index.html is in).  

This is a single page ExtJS application without any friendly bookmarks so the URL is pretty redundant.  

The next step was to replace index.html with "/" so somebody can simply visit server/ or server/contextRoot.  The problem is that relative links served by "/contextRoot" will be relative to "/", not "/contextRoot/".  If "contextRoot" serves a HTML page which contains a link to "lib/myfile" then /contextRoot will actually serve "/lib/myfile" which doesn't exist - I want it to serve "/contextRoot/lib/myfile".  As exected /contextRoot/ will resolve to "/contextRoot/lib/myfile" which works.

Forcing people to visit index.html (with a redirect from "/") is perfectly acceptable, but before giving in I wanted to ask for help.  So help :)

Thanks in advance.

Col

--
You received this message because you are subscribed to the Google Groups "Compojure" group.
To view this discussion on the web visit https://groups.google.com/d/msg/compojure/-/e3AATzWr7hoJ.
To post to this group, send email to comp...@googlegroups.com.
To unsubscribe from this group, send email to compojure+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/compojure?hl=en.

Colin Yates

unread,
Jan 16, 2013, 9:08:41 AM1/16/13
to comp...@googlegroups.com
Thanks for that pointer (http://weavejester.github.com/hiccup/hiccup.middleware.html).  Unfortunately it isn't just in hiccup templates I need to do this, it is also within my JS as well (which is served as static files).

On 16 January 2013 13:51, James Reeves <ja...@booleanknot.com> wrote:
wrap-base-url


Sean Bowman

unread,
Apr 10, 2013, 7:07:55 PM4/10/13
to comp...@googlegroups.com
You're working too hard.  Don't worry about excess slashes.  They don't matter.

The context is taking precedence, and within the context the "/" is the root match, so your result of "3" makes sense to me.  I don't think (GET "") matches anything, and the context takes precedence over (GET "/a"), since it comes first and matches (GET "/") underneath.

That said, I think you're worrying about the wrong things.  Is there some reason you expect the added slash on some routes?  Even if you do, the browser is typically fine with the extra slash; they all just ignore it.  So http://localhost:8080//a//b// is the same as http://localhost:8080/a/b to Chrome, FF, IE, etc.  

I don't know if relative URLs will work with multiple slashes, but I wouldn't recommend relative URLs for anything.  In the past 10 or 12 years I've never used relative paths.  Any time I've ever seen someone do that, it winds up a mess, and you spend all your time figuring out paths instead of writing your web app.  Use absolute paths, and keep your paths simple.  You'll be much happier.

On Apr 10, 2013, at 3:56 PM, Philip Aston <philip...@gmail.com> wrote:


I have the same problem.

With the following:

 (routes
        (context "/a" []
          (GET "" [] "2")
          (GET "/" [] "3")
          (GET "/b" [] "4")
          (GET "c" [] "5")
          (GET "*" [] "5"))
        (GET "/a" [] "1")
)

both "/a"  and "/a/" result in "3". For "/a", I was expecting "2" or "1".

I want to say something like (GET "/a" [] (redirect "/a/")), so that my browser uses the correct base for relative urls. But how?

Thanks,

- Phil 

Nick Bauman

unread,
Apr 10, 2013, 7:18:18 PM4/10/13
to comp...@googlegroups.com
"I want to say something like (GET "/a" [] (redirect "/a/")), so that my browser uses the correct base for relative urls. But how?"

Excess slashes can matter. For example, Google doesn't like it when you serve the same content from two different URLs so you should redirect from "/a" to "/a/" whenever possible.

You can do this by adding a little middleware to your routes like so:

(defn redirect-to-slash
  [app]
  (fn[request]
    (let [resp (app request)]
      (if (and (not (= \/ (last (:uri request)))) (= 404 (:status resp)))
       (redirect (str (:uri request) \/))
       resp))))

Adding middleware like so:

(def my-app
  (-> routes ; defined elsewhere
    redirect-to-slash))
 
(defn start-server []
  (future (jetty/run-jetty (var my-app) {:port 8081})))



On Wed, Apr 10, 2013 at 4:56 PM, Philip Aston <philip...@gmail.com> wrote:

I have the same problem.

With the following:

 (routes
        (context "/a" []
          (GET "" [] "2")
          (GET "/" [] "3")
          (GET "/b" [] "4")
          (GET "c" [] "5")
          (GET "*" [] "5"))
        (GET "/a" [] "1")
)

both "/a"  and "/a/" result in "3". For "/a", I was expecting "2" or "1".

I want to say something like (GET "/a" [] (redirect "/a/")), so that my browser uses the correct base for relative urls. But how?

Thanks,

- Phil

On Wednesday, 16 January 2013 13:41:29 UTC, Colin Yates wrote:
Hi,

tl;dr I am serving a hiccup template with relative links (i.e. "lib/extjs...js") from my "/" route.  It works if I visit myserver/contextRoot/ but not myserver/contextRoot - how can I force contextRoot to be contextRoot/ ?

[longer version]
I am having a world of joy :) getting my app to work properly when run by "lein run server" without a context root and when served from tomcat with a context root.  I have solved most of the problem by using relative URLs, as expected.  It all works beautifully if I visit /index.html (because everything is relative to the directory index.html is in).  

This is a single page ExtJS application without any friendly bookmarks so the URL is pretty redundant.  

The next step was to replace index.html with "/" so somebody can simply visit server/ or server/contextRoot.  The problem is that relative links served by "/contextRoot" will be relative to "/", not "/contextRoot/".  If "contextRoot" serves a HTML page which contains a link to "lib/myfile" then /contextRoot will actually serve "/lib/myfile" which doesn't exist - I want it to serve "/contextRoot/lib/myfile".  As exected /contextRoot/ will resolve to "/contextRoot/lib/myfile" which works.

Forcing people to visit index.html (with a redirect from "/") is perfectly acceptable, but before giving in I wanted to ask for help.  So help :)

Thanks in advance.

Col

--
You received this message because you are subscribed to the Google Groups "Compojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compojure+...@googlegroups.com.

To post to this group, send email to comp...@googlegroups.com.

Philip Aston

unread,
Apr 11, 2013, 4:13:23 AM4/11/13
to comp...@googlegroups.com
Thanks Sean.

I don't want to work hard, I want Compojure to do The Right Thing for me :-)


> "So http://localhost:8080//a//b// is the same as http://localhost:8080/a/b to Chrome, FF, IE, etc."

This isn't true with respect to non-root relative URLs. Why do I care? I don't want my modular app to care about the root context (I want that specified elsewhere, in a different module). I guess I could use the hiccup wrap-base-url, and calculate root relative URLs, but that also feels like work.

- Phil

Philip Aston

unread,
Apr 11, 2013, 4:14:15 AM4/11/13
to comp...@googlegroups.com
Thanks Nick. Yes, that sounds like a good way to fix it once.

- Phil

Nick Bauman

unread,
Apr 11, 2013, 11:12:25 PM4/11/13
to comp...@googlegroups.com
I'm looking at that code I typed up there and I believe the "(and (not" might be backwards and you want "(not (and" but I think you get the idea.

More information on the slash versus no-slash thing and why it's important to consider carefully:



Sean Bowman

unread,
Apr 12, 2013, 1:37:04 AM4/12/13
to comp...@googlegroups.com
It's not important to consider carefully.  When the article's conclusion is basically that you'll get a warm and fuzzy if you deal with this specific issue, I can't really take it very seriously.

Just don't use slashes at the end in any of your URLs and have Apache, Nginx, or whatever proxy you're using 303 redirect URLs with slashes at the end.  There, done.  Heck, you'll even be ahead of Google.

Try this.


You get a 302 redirect. (easier to see with curl)


You get a 503 error (Service Unavailable).  (wow, not a 404, but a 503; was not expecting that)


You get the same content without any redirects or errors.

It's not hard to find examples; these were three of the five URLs I tried.  My guess is Google could basically care less, and that you're doing a lot of worrying over nothing.

Philip Aston

unread,
Apr 12, 2013, 5:56:14 AM4/12/13
to comp...@googlegroups.com

I got so far with the redirect middleware, but gave up. When I changed
(context "/ui") to (context "/ui/") so "/ui" generates a 404, my
context-scoped routes broke because they have to start with "/", hence
they became mapped to"/ui//blah".

IMHO, the Compojure context macro does not handle trailing slashes in
paths in a useful manner. It clashes with Clout routes which I
understand have to start with a leading "/" (where's the spec for
routes?). Consequently:

  - "" is not a valid route. With (context "/a"), "/a" is handled by a
    route of "/".

  - You can't define (context "/a/"), then (GET "b" [] ..). Context
    paths ending in "/" are not that useful

I guess I could take a different approach and have middleware that
redirects specific request paths before Compojure gets involved.

I ended up following Sean's advice, and always using root relative
URLs. It turned out that there's some subtlety to how hiccup handles
contexts:

=> (with-base-url "x" (to-str (to-uri "a")))
"a"
=> (with-base-url "x" (to-str (to-uri "/a")))
"x/a"

=> (with-base-url "x" (html (include-js "/a")))
"<script src=\"x/a\" type=\"text/javascript\"></script>"
=> (with-base-url "x" (html (include-js "a")))
"<script src=\"a\" type=\"text/javascript\"></script>"


So I can get hiccup to generate root relative URLs by using
(wrap-base-url), and ensuring each URL starts with a leading '/'.


- Phil

James Reeves

unread,
Apr 12, 2013, 6:40:12 AM4/12/13
to Compojure
On 12 April 2013 10:56, Philip Aston <phi...@mail.com> wrote:
IMHO, the Compojure context macro does not handle trailing slashes in
paths in a useful manner. It clashes with Clout routes which I
understand have to start with a leading "/" (where's the spec for
routes?).

Clout doesn't have any opinion on whether routes start with a "/" or not.

However, the point you make about the context macro is a good one. Currently it returns a 200 OK response for "/foo" and "/foo/" when it should be returning either a redirect or nil for one of them.

I ended up following Sean's advice, and always using root relative
URLs. It turned out that there's some subtlety to how hiccup handles
contexts:

=> (with-base-url "x" (to-str (to-uri "a")))
"a"
=> (with-base-url "x" (to-str (to-uri "/a")))
"x/a"

So I can get hiccup to generate root relative URLs by using
(wrap-base-url), and ensuring each URL starts with a leading '/'.

Well, sure. How else could it possibly work?

If you want a URI relative to the root, it needs to begin with a "/". This isn't anything Compojure or Ring specific.

- James

Philip Aston

unread,
Apr 13, 2013, 11:24:24 AM4/13/13
to comp...@googlegroups.com
On 12/04/13 11:40, James Reeves wrote:
On 12 April 2013 10:56, Philip Aston <phi...@mail.com> wrote:
IMHO, the Compojure context macro does not handle trailing slashes in
paths in a useful manner. It clashes with Clout routes which I
understand have to start with a leading "/" (where's the spec for
routes?).

Clout doesn't have any opinion on whether routes start with a "/" or not.


OK. I was basing this on simple experimentation, and assuming it was down to Clout. Compojure routes defined without a leading "/" (whether within a context or not) did not seem to match anything useful.


However, the point you make about the context macro is a good one. Currently it returns a 200 OK response for "/foo" and "/foo/" when it should be returning either a redirect or nil for one of them.

Given my experience with other frameworks, I'd expect "/foo" to redirect to "/foo/". However, I'd prefer it if "/foo" returned nil, then the user can chose what to do using a separate route, or generalise it with middleware. Either way, I think context would also need implicitly to strip leading slashes from the wrapped routes.


I ended up following Sean's advice, and always using root relative
URLs. It turned out that there's some subtlety to how hiccup handles
contexts:

=> (with-base-url "x" (to-str (to-uri "a")))
"a"
=> (with-base-url "x" (to-str (to-uri "/a")))
"x/a"

So I can get hiccup to generate root relative URLs by using
(wrap-base-url), and ensuring each URL starts with a leading '/'.

Well, sure. How else could it possibly work?

If you want a URI relative to the root, it needs to begin with a "/". This isn't anything Compojure or Ring specific.

A couple of alternatives that Hiccup could have chosen:
  • Map both "a" and "/a" to "x/a".
  • Map "a" to "x/a" and leave "/a" unchanged. Arguably more useful, because the application could then use root relative URIs to some other module, outside the base URL.
- Phil

James Reeves

unread,
Apr 13, 2013, 1:26:29 PM4/13/13
to Compojure
On 13 April 2013 16:24, Philip Aston <phi...@mail.com> wrote:

OK. I was basing this on simple experimentation, and assuming it was down to Clout. Compojure routes defined without a leading "/" (whether within a context or not) did not seem to match anything useful.

Well, why would it? Without a context you're matching directly against the HTTP request URI, which in general has a leading "/".
 
However, the point you make about the context macro is a good one. Currently it returns a 200 OK response for "/foo" and "/foo/" when it should be returning either a redirect or nil for one of them.

Given my experience with other frameworks, I'd expect "/foo" to redirect to "/foo/". However, I'd prefer it if "/foo" returned nil, then the user can chose what to do using a separate route, or generalise it with middleware. Either way, I think context would also need implicitly to strip leading slashes from the wrapped routes. 

Ideally we want the redirects to be consistent, so it would make more sense for "/foo/" to redirect to "/foo" rather than the other way around, since "/foo.html" looks a lot better than "/foo.html/".

However, we also want to maintain nesting, so:

    (context "/foo" []
      (GET "/" [] "one")
      (GET "/bar" [] "two"))

Should be the same as:

    (routes
      (GET "/foo" [] "one")
      (GET "/foo/bar" [] "two"))

However, currently it produces the equivalent to:

    (routes
      (GET "/foo" [] "one")
      (GET "/foo/" [] "one")
      (GET "/foo/bar" [] "two"))

That middle route ideally shouldn't be matched, although if you're using middleware that always removes the ending slash, that extra route is never reached, so in practise it's less of a big deal.

Some standard middleware for removing ending slashes might be useful, though...

  
A couple of alternatives that Hiccup could have chosen:
  • Map both "a" and "/a" to "x/a".
  • Map "a" to "x/a" and leave "/a" unchanged. Arguably more useful, because the application could then use root relative URIs to some other module, outside the base URL.
None of those alternatives would work in the way I think you'd expect.

Consider a page at, say, "/foo/bar" with two links, one leading to "a" and the other leading to "/a". Under normal circumstances, the links are resolved by the browser like so:

    "a" => "/foo/a"
    "/a" => "/a"

Now we introduce a base URL, "/x" using the wrap-base-url middleware. The current Hiccup behaviour means you get:

    "a" => "/x/foo/a"
    "/a" => "/x/a

Which you can see matches up to what we'd expect if you added a context. Both links now get a common prefix of "/x".

On the other hand, your first suggestion leads to:

    "a" => "/foo/x/a"
    "/a" => "/foo/x/a"

And your second suggestion:

    "a" => "/foo/x/a"
    "/a" => "/a"

Which is probably not what you mean to do.

- James

Nick Bauman

unread,
Apr 13, 2013, 1:33:39 PM4/13/13
to comp...@googlegroups.com
On Sat, Apr 13, 2013 at 12:26 PM, James Reeves <ja...@booleanknot.com> wrote:

Ideally we want the redirects to be consistent, so it would make more sense for "/foo/" to redirect to "/foo" rather than the other way around, since "/foo.html" looks a lot better than "/foo.html/".

Start bike-shedding.

The middleware example I put in this thread earlier wouldn't do that. And I think the opposite: where "/foo" should redirect to "/foo/" not the other way around. Because "/foo", while acceptable, isn't a "real" URL in my book, where "/foo/" is. If you define all your routes with a trailing slash and use that middleware example, this generally isn't a problem.

End bike-shedding.

James Reeves

unread,
Apr 13, 2013, 1:46:29 PM4/13/13
to Compojure
Bike-shedding isn't much of a problem in this case, as one can devise middleware to convert between either system quite easily. What matters more is making the underlying routes consistent.

- James

Philip Aston

unread,
Apr 14, 2013, 7:14:11 AM4/14/13
to comp...@googlegroups.com
On 13/04/13 18:26, James Reeves wrote:
On 13 April 2013 16:24, Philip Aston <phi...@mail.com> wrote:

OK. I was basing this on simple experimentation, and assuming it was down to Clout. Compojure routes defined without a leading "/" (whether within a context or not) did not seem to match anything useful.

Well, why would it? Without a context you're matching directly against the HTTP request URI, which in general has a leading "/".

Agreed, without a context, routes with out a leading "/" make no sense. But my observation stands: currently all routes must begin "/" or they won't match.


 
However, the point you make about the context macro is a good one. Currently it returns a 200 OK response for "/foo" and "/foo/" when it should be returning either a redirect or nil for one of them.

Given my experience with other frameworks, I'd expect "/foo" to redirect to "/foo/". However, I'd prefer it if "/foo" returned nil, then the user can chose what to do using a separate route, or generalise it with middleware. Either way, I think context would also need implicitly to strip leading slashes from the wrapped routes. 

Ideally we want the redirects to be consistent, so it would make more sense for "/foo/" to redirect to "/foo" rather than the other way around, since "/foo.html" looks a lot better than "/foo.html/".

Why would you ever say (context "/foo.html")?



However, we also want to maintain nesting, so:

    (context "/foo" []
      (GET "/" [] "one")
      (GET "/bar" [] "two"))

Should be the same as:

    (routes
      (GET "/foo" [] "one")
      (GET "/foo/bar" [] "two"))

However, currently it produces the equivalent to:

    (routes
      (GET "/foo" [] "one")
      (GET "/foo/" [] "one")
      (GET "/foo/bar" [] "two"))

That middle route ideally shouldn't be matched, although if you're using middleware that always removes the ending slash, that extra route is never reached, so in practise it's less of a big deal.

Some standard middleware for removing ending slashes might be useful, though...


Or, you might specify:

    (context "/foo/" []
      (GET "" [] "one")
      (GET "bar" [] "two"))

be the same as:

    (routes
      (GET "/foo/" [] "one")
      (GET "/foo/bar" [] "two"))

not its current behaviour:

    (routes)

However, I think we can all agree that we don't want a bike shed committee, so having pointed out the problem, I'm going to shut up.



  
A couple of alternatives that Hiccup could have chosen:
  • Map both "a" and "/a" to "x/a".
  • Map "a" to "x/a" and leave "/a" unchanged. Arguably more useful, because the application could then use root relative URIs to some other module, outside the base URL.
None of those alternatives would work in the way I think you'd expect.

Consider a page at, say, "/foo/bar" with two links, one leading to "a" and the other leading to "/a". Under normal circumstances, the links are resolved by the browser like so:

    "a" => "/foo/a"
    "/a" => "/a"

Now we introduce a base URL, "/x" using the wrap-base-url middleware. The current Hiccup behaviour means you get:

    "a" => "/x/foo/a"
    "/a" => "/x/a

Which you can see matches up to what we'd expect if you added a context. Both links now get a common prefix of "/x".

On the other hand, your first suggestion leads to:

    "a" => "/foo/x/a"
    "/a" => "/foo/x/a"


Sorry, I wasn't clear, as I was working from


=> (with-base-url "x" (to-str (to-uri "/a")))
"x/a"

and omitted the leading "/" from "x/a". It would have been clearer if I'd said: Map both "a" and "/a" to "/x/a", giving

    "a" => "/x/a"
    "/a" => "/x/a"

And your second suggestion:

    "a" => "/foo/x/a"
    "/a" => "/a"


    "a" => "/x/a"
    "/a" => "/a"

All this being said, I'm not bothered about the current hiccup behaviour - it is at least consistent.

- Phil

James Reeves

unread,
Apr 14, 2013, 8:27:25 AM4/14/13
to Compojure
On 14 April 2013 12:14, Philip Aston <phi...@mail.com> wrote:
Ideally we want the redirects to be consistent, so it would make more sense for "/foo/" to redirect to "/foo" rather than the other way around, since "/foo.html" looks a lot better than "/foo.html/".
Why would you ever say (context "/foo.html")?

You wouldn't. The problem is more general than that.

If you have a route leading to "/foo/bar" and someone enters in "/foo/bar/", what should happen?

Returning a 404 for one and a 200 for the other isn't particularly user friendly, so one route needs to redirect to the other. Either "/foo/bar" redirects to "/foo/bar/", or conversely "/foo/bar/" redirects to "/foo/bar".

The simplest way to achieve this is to pick a rule and follow it consistently. For instance:

    (defn wrap-remove-ending-slash [handler]
      (fn [{uri :uri :as request}]
        (if (.endsWith uri "/")
          (redirect (str/replace uri #"/$" ""))
          (handler request))))

In this case, if a route ends with a "/", we redirect to one without. You could also do it the other way around, but then "/foo.html" would redirect to "/foo.html/", which to my mind looks wrong.
       

Or, you might specify:

    (context "/foo/" []
      (GET "" [] "one")
      (GET "bar" [] "two"))

be the same as:

    (routes
      (GET "/foo/" [] "one")
      (GET "/foo/bar" [] "two"))

But then you lose the ability to nest without changing code.

Consider a set of routes:

    (defroutes number-routes
      (GET "/" [] "one")
      (GET "/bar" [] "two"))

These routes will work straight up, but we can also nest them in a context without changing them:

    (context "/foo" [] number-routes)

If we wrote the routes as "" and "bar" instead of "/" and "/bar", they wouldn't work at the top level.

 
Sorry, I wasn't clear, as I was working from


=> (with-base-url "x" (to-str (to-uri "/a")))
"x/a"

and omitted the leading "/" from "x/a". It would have been clearer if I'd said: Map both "a" and "/a" to "/x/a", giving

    "a" => "/x/a"
    "/a" => "/x/a"

Your system doesn't handle links relative to the current page correctly.

When you have a href like "a", it's a path relative to the current page you're on. If you have a href like "/a", it's a path relative to the root of the website.

So let's say I'm on a page like:


On this page is a link:

    <a href="settings">Settings</a>

If I click the link, the browser will resolve the href of the link to the following URL:


Now let's say we want to add a base path, like "/demo-app". With your scheme, you end up with a link like:

    <a href="/demo-app/settings">Settings</a>

Which would resolve to:


Probably not what you want, right?

The correct way to handle it is to ignore hrefs relative to the current page, so:

    (absolute-path (add-base-url "settings"))
    => (absolute-path "settings")
    => "/demo-app/users/10/settings"

    (absolute-path (add-base-url "/users/10/settings"))
    => (absolute-path "/demo-app/users/10/settings")
    => "/demo-app/users/10/settings"

Now both routes map to the same page, with and without the base path added.

- James

Philip Aston

unread,
Apr 14, 2013, 8:54:04 AM4/14/13
to comp...@googlegroups.com, James Reeves
On 14/04/13 13:27, James Reeves wrote:
On 14 April 2013 12:14, Philip Aston <phi...@mail.com> wrote:
Ideally we want the redirects to be consistent, so it would make more sense for "/foo/" to redirect to "/foo" rather than the other way around, since "/foo.html" looks a lot better than "/foo.html/".
Why would you ever say (context "/foo.html")?

You wouldn't. The problem is more general than that.

If you have a route leading to "/foo/bar" and someone enters in "/foo/bar/", what should happen?

Returning a 404 for one and a 200 for the other isn't particularly user friendly, so one route needs to redirect to the other. Either "/foo/bar" redirects to "/foo/bar/", or conversely "/foo/bar/" redirects to "/foo/bar".

The simplest way to achieve this is to pick a rule and follow it consistently. For instance:

    (defn wrap-remove-ending-slash [handler]
      (fn [{uri :uri :as request}]
        (if (.endsWith uri "/")
          (redirect (str/replace uri #"/$" ""))
          (handler request))))

In this case, if a route ends with a "/", we redirect to one without. You could also do it the other way around, but then "/foo.html" would redirect to "/foo.html/", which to my mind looks wrong.

I think the best approach is to use custom middleware and let the application decide. This requires a way to map the two routes differently when using the context macro. Which is why I prefer to start with (context "/foo/").

But I'm shutting up. :-)


       

Or, you might specify:

    (context "/foo/" []
      (GET "" [] "one")
      (GET "bar" [] "two"))

be the same as:

    (routes
      (GET "/foo/" [] "one")
      (GET "/foo/bar" [] "two"))

But then you lose the ability to nest without changing code.

Consider a set of routes:

    (defroutes number-routes
      (GET "/" [] "one")
      (GET "/bar" [] "two"))

These routes will work straight up, but we can also nest them in a context without changing them:

    (context "/foo" [] number-routes)

If we wrote the routes as "" and "bar" instead of "/" and "/bar", they wouldn't work at the top level.

Yes, I agree its useful to be able to rebind code without altering the routes.

I was thinking about that when I murmured about the context macro implicitly dropping the leading "/" of nested routes. So

    (context "/foo/" []
      (GET "/" [] "one")
      (GET "/bar" [] "two"))

~

    (routes
       (GET "/foo/" [] "one")
       (GET "/foo/bar" [] "two"))

but that's more magic, so probably not a good idea.




 
Sorry, I wasn't clear, as I was working from

=> (with-base-url "x" (to-str (to-uri "/a")))
"x/a"

and omitted the leading "/" from "x/a". It would have been clearer if I'd said: Map both "a" and "/a" to "/x/a", giving

    "a" => "/x/a"
    "/a" => "/x/a"

Your system doesn't handle links relative to the current page correctly.


.. and the other approach I was suggesting (i.e. reverse the interpretation of "/a" and "a") also prevents links relative to the current page, but allows "absolute" root relative URLs. The latter are simple to handle anyway by unbinding base-url. Thanks James, I now understand and agree with the choices made by hiccup.

- Phil

Reply all
Reply to author
Forward
0 new messages