reitit icon indicating copy to clipboard operation
reitit copied to clipboard

Implement #238, handle trailing slashes in frontend match-by-path

Open Deraen opened this issue 5 years ago • 4 comments

Does adding option to router make sense? Are there other ways to control this logic?

Deraen avatar Mar 15 '19 15:03 Deraen

Now implemented as custom Router, which wraps the parent router.

TODO:

  • [ ] Move to reitit-core
  • [ ] Migrate reitit-ring to use this.
  • [ ] Decide on API, do we add option on some basic routers? Maybe even reitit.core/router, or should user wrap another router in trailing-slash-router?
  • [ ] Check performance, alternative implementation would be to modify routes to match additional / missing slashes in Router creation time.

Deraen avatar Sep 20 '19 08:09 Deraen

I remembered some reason why it might not be necessary or even good idea to move this to core:

Frontend and backend have quite a different solutions on what to do in these cases: this frontend solution just returns the match as if the original route was matched. In backend ring handler will return redirect response.

Deraen avatar Sep 20 '19 08:09 Deraen

I can't talk about the implementation details (moving to core or not), but my 2c on (my) desired behaviour in the frontend:

  • Generally speaking, would like to have a "canonical" representation of the route. It's probably application specific about whether this is with, or without a trailing slash. This is something we can control today by using "" or "/" in a route definition.
  • Any non-canonical but equivalent paths are coming from either users typing directly into the URL bar (e.g. stripping off a path segment) or external applications linking in (where someone types the URL into an input field). In both cases, we can't control what the link looks like.
  • Would like the frontend to silently accept the equivalent path, and route to the canonical one. Sometimes we might want to change the visible URL to reflect the canonical path, but sometimes that's not necessary.

Thank you for your work on this!

orestis avatar Nov 13 '19 08:11 orestis

Not sure if useful for anyone, but here's a small snippet that seems to do the trick:

route! and navigation-fail are application-specific handlers. The try-without-slash is run upon a match fail, to see if we can recover.

(defn- try-without-slash [path router]
  (if (str/ends-with? path "/")
    (let [non-slash-path (subs path 0 (dec (count path)))]
      (if-let [match (rf/match-by-path router non-slash-path)]
        (do
          (.replaceState js/window.history nil "" non-slash-path)
          (route! match))
        (navigation-fail non-slash-path)))
    (navigation-fail path)))

orestis avatar Nov 13 '19 09:11 orestis