Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Allow more regex for paths #8254

Closed
dbibbens opened this issue Nov 6, 2021 · 29 comments
Closed

[Feature]: Allow more regex for paths #8254

dbibbens opened this issue Nov 6, 2021 · 29 comments
Labels

Comments

@dbibbens
Copy link

dbibbens commented Nov 6, 2021

What is the new or updated feature that you are suggesting?

update current route.path to allow more conditional regex paths for multiple conditions like in v5.

v5 route: /(wines|whiskeys|sakes|beers)/:id/:productName?

Why should this feature be included?

current v6 doesnt include this anymore. only allow strict routes.

@SafaAlfulaij
Copy link

SafaAlfulaij commented Nov 7, 2021

This is what currently stops me from moving to V6. Moving the validation logic to components is not suitable IMOH, and waste resources.

I would suggest that instead of providing arbitrary regex in each path, we define some formats in the config level, then use them within paths. This also could be the only way to use regex within paths.

For example, Router's formatsConfig prop:

{
  "uuid": /([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/,
  "drinks": /(wines|whiskeys|sakes|beers)/
}

Then use them within paths:
Note: The curly brackets is just an example. Any other format that does this is fine.

<Route path="{drinks}/:id{uuid}" element={<Teams />}>
// or
<Route path="{drinks}/id:uuid" element={<Teams />}>
// or
<Route path="{drinks}/{uuid:id}" element={<Teams />}>

Or as a separate validation prop:

<Route path="{drinks}/:id" validate={{ id: 'uuid' }} element={<Teams />}>

Inspired from UI-Router

@wintercounter
Copy link

wintercounter commented Nov 11, 2021

I was also about to open a feature request for a similar case. In my codebase, I heavily rely on path-to-regexp features. The upgrade docs say to move such logic at the component level, but for me, that's not possible, paths are set by users from an admin interface where components don't (and can't) include such logic.

I was thinking if we can have a plugin-like solution where we can supply a pathParser prop to Router. This would allow using any custom solution we need, keeping the base library small and dependency-free, but allowing people to create 3rd party community packages to add support back to path-to-regexp for example. I think this could be a win-win solution for all parties.

@justrealmilk
Copy link

While an API for 3rd party path parsing sounds cool, I think this functionality is pretty basic and popular. Unsure why it was removed.

At the top of my switch, I have

<Switch>
  <Route path='/:membershipType([1|2|3|4|5])/:membershipId([0-9]+)/:characterId([0-9]+)?' component={ProfileRoutes} />
  ...

Am I now supposed to write a route for /1-5/?

@nuintun
Copy link

nuintun commented Nov 26, 2021

https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API

@Vincz
Copy link

Vincz commented Nov 26, 2021

I agree with all of the above. The pattern matching was handled nicely with v5, why remove such a critical feature?

@queengooborg
Copy link

+1 for getting this functionality added back in. Just like optional routing parameters, this was such a useful (and critical feature), and it's not clear why this functionality was removed...we're gonna have to stay on v5 because of it. I'd love to hear a reasoning from the package maintainers as to what led to this surprising and large change.

@wintercounter
Copy link

wintercounter commented Dec 6, 2021 via email

@bluepeter
Copy link

Likewise. In my opinion, it's a big step backwards. Removing (presumably) widely-used functionality with the terse note only to "remove it and simplify your route paths" is upsetting. It's a massive breaking change. Reducing file size is great, but this feels like an over-optimization at the expense of better functionality and backwards compatibility.

@singggum3b
Copy link

A lot of useful feature has been removed from v6. I think overly obsessive with the package size is really weighting on the usefulness of the library. What if the majority of user has to workaround those feature anyway, or just simply refuse to upgrade to v6?

@bluepeter
Copy link

The maintainers aren't responding to the concerns. As others mentioned, we are looking into https://github.com/molefrog/wouter as we doubt that v5 will be maintained, and we can't use the reduced feature v6.

@wintercounter
Copy link

wintercounter commented Dec 13, 2021 via email

@videni
Copy link

videni commented Dec 23, 2021

what is the solution at the moment?

      <Route path="/store" element={ <Products />}>
        <Route  path="nodes" element={<Nodes />} />
        <Route  path="checkout/:productId" element={<Checkout />} />
      </Route >

I got store/checkout/123e4567-e89b-12d3-a456-426655440006 , it always render Products not the Checkout
, but changing uuid to an integer , it works.

@kulakowka
Copy link

@videni it's similar to my problem with symbol - #8525

@videni
Copy link

videni commented Dec 27, 2021

@kulakowka, however , it works after changing it to

<Route path="/store" element={ <Products />} />
<Route  path="/store/nodes" element={<Nodes />} />
<Route  path="/store/checkout/:productId" element={<Checkout />} />

jtojnar added a commit to fossar/selfoss that referenced this issue Jan 6, 2022
Currently broken because regex pattern support has been removed:

remix-run/react-router#8254
@james-Ballyhoo
Copy link

Wish I'd known this had been removed before starting a migration from 5 to 6.

The migration docs did not make it clear this would be a breaking change, it's buried half way down the page as a side note.

@timdorr timdorr changed the title allow more regex for paths instead of the defaults [Feature]: [Feature]: Allow more regex for paths Feb 21, 2022
@timdorr timdorr mentioned this issue Feb 21, 2022
@paul23-git
Copy link

So what's the solution for this? I get redirected here on other bugs but there doesn't seem to be any solution provided?

In our case we depend on the functionality to extract the language parameters from the path seemlessly:

example.com/en-us/my-store

and

example.com/my-store

Where the language is grabbed by doing

<Route path={"/:lang([a-z]{2}-[a-z]{2})"}>

This must be possible right? The migration on the website stated nothing special about this, and as we also updated to a new version of react (and all other libraries) downgrading isn't really possible.

@aress31
Copy link

aress31 commented Mar 2, 2022

This is what currently stops me from moving to V6. Moving the validation logic to components is not suitable IMOH, and waste resources.

I would suggest that instead of providing arbitrary regex in each path, we define some formats in the config level, then use them within paths. This also could be the only way to use regex within paths.

For example, Router's formatsConfig prop:

{
  "uuid": /([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/,
  "drinks": /(wines|whiskeys|sakes|beers)/
}

Then use them within paths: Note: The curly brackets is just an example. Any other format that does this is fine.

<Route path="{drinks}/:id{uuid}" element={<Teams />}>
// or
<Route path="{drinks}/id:uuid" element={<Teams />}>
// or
<Route path="{drinks}/{uuid:id}" element={<Teams />}>

Or as a separate validation prop:

<Route path="{drinks}/:id" validate={{ id: 'uuid' }} element={<Teams />}>

Inspired from UI-Router

This would be perfect for my current use case, I vote for this solution. Any update on this?

@JaroVDH
Copy link

JaroVDH commented Apr 8, 2022

This is a required feature for us to move to v6.
Handling it inside the route element isn't an option either, as those routes then won't fall back to other routes.

We can't simply 'rethink all our routes', they're already being used.
Being told to do so is rather insulting, imo. Like everything is some kind of hobby project.

@cody-elhard
Copy link

I know this is not a clean solution and creates some ugly URL's, but if you need a hack you can base64 encode the param you want to pass.
In my instance I have the following

<Routes>
    <Route path="/" element={<Root />} />
    <Route path="/posts/:gid" element={<SinglePost />} />
</Routes>
function Root() {
    <Link to={`/posts/${btoa(post.id)}`}> {post.title} </Link>
}

function SinglePost() {
  const params = useParams();
  console.log('params', atob(params.gid)); // gid is base64 encoded to work with react router

  return (
    <div>
      A post route
    </div>
  )
}

@tpict
Copy link

tpict commented May 11, 2022

The lack of regex is an issue for brownfield projects with poor URL design. AFAIK if I wanted to mount a param-dependent component on all routes matching /base/(one hundred different URLs)/:myParam, under V6 I'd have to write them all out explicitly, or write the param matching code manually (or just reinstall path-to-regexp and call it with the old regex path).

@aliakbarazizi
Copy link

I was in the middle of the migration and saw this, and stopped doing that now my plan is to migrate to another library

this is a huge step back for this library.

@bluepeter
Copy link

Just an update that we have been able to successfully migrate to v6. A few code snippets that helped us...

The following 2 code snippets work together:

                <Route path="site/:siteId">                                                                
                  {viewLevel(<Site />, true)}                                                              
                  <Route path="session/:sessionId">                                                        
                    {viewLevel(<Session />, true)}                                                         
                    <Route path="page/:pageId">                                                            
                      {viewLevel(<Page />, true)}         
const viewLevel = (element, modals = false) =>
  !!element && (
    <Route
      element={
        <>
          {element}
          <Outlet />
        </>
      }
    >
      <Route element={null} index />
      {modals && <Route element={null} path=":modal" />}
      {viewerRoutes}
    </Route>
  );

And the following two work together...

<Route element={<TryFixUrl />} path="*" />
const TryFixUrl = () => {
  const path = window.location.pathname.replace(/^\/$/, "");
  return (
    <Navigate
      replace
      to={
        path.endsWith("view")
          ? path.replace(/[^/]+\/([^/]+)/, "$1") + window.location.search
          : "/404"
      }
    />
  );
};

@wintercounter
Copy link

wintercounter commented May 20, 2022 via email

@GlebAmbrazhevich
Copy link

GlebAmbrazhevich commented Jun 14, 2022

The lack of regex is an issue for brownfield projects with poor URL design. AFAIK if I wanted to mount a param-dependent component on all routes matching /base/(one hundred different URLs)/:myParam, under V6 I'd have to write them all out explicitly, or write the param matching code manually (or just reinstall path-to-regexp and call it with the old regex path).

@tpict Creating a folder structure with unlimited nesting and unique namespaces is a very common thing. Why is it a poor URL design?

@tpict
Copy link

tpict commented Jun 14, 2022

@GlebAmbrazhevich I meant in the case that :myParam represents the same resource under all URLs, and the remaining segments were subcategories of that resource. Normally I'd order URL segments from least to most specificity because it's easier to compose URL configurations/views/routers/etc that way... and because that's the way everyone does it! Though I'm not sure this practice is codified anywhere as "URL usability guidelines".

For a folder structure of unknown depth, I imagine the new React Router API works very well since nested relative routes are the crux of the thing.

@jeffersoneagley
Copy link

@GlebAmbrazhevich I meant in the case that :myParam represents the same resource under all URLs, and the remaining segments were subcategories of that resource. Normally I'd order URL segments from least to most specificity because it's easier to compose URL configurations/views/routers/etc that way... and because that's the way everyone does it! Though I'm not sure this practice is codified anywhere as "URL usability guidelines".

For a folder structure of unknown depth, I imagine the new React Router API works very well since nested relative routes are the crux of the thing.

I have a similar case where "anything ending in /auth should be shown the auth page"

jtojnar added a commit to fossar/selfoss that referenced this issue Oct 15, 2022
Currently broken because regex pattern support has been removed:

remix-run/react-router#8254
@VeXell
Copy link

VeXell commented Jan 8, 2023

+1 This is a good feature. Not with React Router 6.6.1 we have optional params, but i still can not use logic like that:

 const langs = `/:locale(${languages.join('|')})?`;

This is a small validation what language we can use. Instead of this simple logic we should create list of routes with all supported languages.

@brophdawg11
Copy link
Contributor

@VeXell If you need to do param validation, I would do that in a loader where you can then return a 404 or redirect to a known good language URL.

@brophdawg11
Copy link
Contributor

I'm going to convert this to a discussion so it can go through our new Open Development process. Please upvote the new Proposal if you'd like to see this considered!

@remix-run remix-run locked and limited conversation to collaborators Jan 9, 2023
@brophdawg11 brophdawg11 converted this issue into discussion #9844 Jan 9, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Projects
None yet
Development

No branches or pull requests