Custom middleware(routing) to discriminate URL parameters

My two last examples are two different implementations of the solution you are proposing actually. You wouldn’t change urls with there two implementations.

You might still be confused with the fact that /:param1/:param2 is not actually a URL but a regex expression.

So when I say you could keep a single route called /:service/:cf you are not changing routes. You could actually call it /:mydog/:eatscats and you still wouldn’t be changing URLs.

SEO wise and old links pointing to your website like www.yourwebsite.com/plumber/france would still match /:mydog/:eatscats.

Now in the SC associated to that route you would query the database to figure out if $_GET.eatscats is a country or a function.

Now as it seems that $_GET.eatscats is a country(france) you could do two things from the SC action:
a) Redirect to /s/plumber/c/france which will match /s/:service/c/:country and that will take them to the right content page
b) Send them to a page that will show partials depending if it’s a country or a function and data specific to /plumber/france

But the users would still use /plumber/france and you keep your SEO authority for the original URL and old links working in both cases.

Thank you JonL, sorry - don’t mean to offend with my response - so much work has gone into this, and frustrated I appear to have the concept a little wrong.

I think when you say ‘redirect’ I automatically mean a more basic redirect we would all normally see in a browser where the url path would change.

I have not used a SC Redirect action - so not sure how this actually works in relation to redirecting the user / Google Crawler for a fully rendered page of content.

Thank you for your response - I’m encouraged that you feel this is in fact possible so I’m going to try and make it work based on your examples

1 Like

Absolutely none taken! How on earth can you even consider your reply offensive? I have no doubt you will tackle this problem.

1 Like

@JonL - I’ve been exploring this again today, to try an get it working.

I found (because our existing project uses the same paths, and Symfony) this talks to the exact problem I’m having and how in Symfony you can use ‘requirements’ in the page parameter:

Now, I know I’m not using Symfony or PHP (NodeJS) project - but are you aware of any such option in NodeJS and importantly, already within Wappler capabilities with no custom code?

@patrick - you might have some advice around this with regex patterns?

If you can solve it with regex it can be done indeed. I was under the impression that regex was not an option because you had no convention rules for the paths.

I get lost in some of the terminology, so i’m not sure if I do or don’t.

This is particularly interesting, but I think I misunderstand it:
To have more control over the exact string that can be matched by a route parameter, you can append a regular expression in parentheses ( () ):

Route path: /user/:userId(\d+)
Request URL: http://localhost:3000/user/42
req.params: {"userId": "42"}

From: https://expressjs.com/en/guide/routing.html#:~:text=Route%20parameters%20are%20named%20URL,path%20as%20their%20respective%20keys.

This looks like I could perhaps have /recruiters/:country(\c+)/:state(\s+) for example but doesn’t appear to be working.

Would you mind explaining what you mean by no convention rules for paths? I’m using purely Wappler, nothing custom

By convention I mean you know beforehand that a url is going to have:

  1. Only numbers
  2. Two numbers a dash and one letter or more
  3. Some letters a dash and more letters
  4. Etc

Then you could use two routes for your case. Can you paste a few example urls for both routes?

If I understand what you are asking correctly (I hope I do! thank you for helping).

The ‘routes’ in Wappler examples:
/recruiters/:country/:state/:city
/recruiters/:industry/:state/:city
/recruiters/:function/:state/:city
/recruiters/:service/:industry/:function/:country/:state/:city
and so on

Actual URLs examples:
/recruiters/united-states/california/los-angeles
/recruiters/united-states/california/san-francisco
/recruiters/software-development/california/san-francisco
/recruiters/executive-search/software-development/react/united-states/california/san-francisco

The url parameters are never random, and there is an order to the way they will always display, e.g. it will always be country then state then city, and it will always be industry and function before location.

The only times there are numbers are when we introduce an id for the actual final page which is the profile of the user, for example and this url parameter route and url path will always be as follows:

/recruiters/:firstname-:lastname-:id
or
/recruiters/john-smith-35

These two routes are “the same”. There is no regex(in our context) that could discriminate between them.

These are all the same.
It reads:

/recruiters/:parameter/:parameter/:parameter

I believe Patrick and George explained this to you already.

Yes I understand that - the article I reference above, and what i’m looking at in the express.js documentation is adding requirements to the URL’s to validate which route should be taken.

In the Symfony docs:
“If the user requests /blog/my-first-post , both routes will match and Symfony will use the route which was defined first.”

Which is my issue - the route cannot determine the difference between them as they are he same.

"To fix this, add some validation to the {page} parameter using the requirements option:

/**
 * @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"})
 */

I am looking at the Express.JS and it looks like (maybe I’m wrong) there may be some way to validate the route / add specific requirements to the routes - so I was asking re: this.

E.g. for the user page, it will also have issues matching with the directory pages, so perhaps if I do something like this, I can solve that:

/recruiters/:firstname-:lastname-:userId([0-9]+) - if I understand correctly, this will then return only a route that has the user ID with a digit?

It is not a limitation in Wappler, Express or any framework or programming language. It is just that the convention rules used in the urls of your old page are not good enough for a machine to discriminate between them via regular expressions(requirements in symfony routing).

That means that your old app is not discriminating at routing level for the two specific routes that are causing you issues.

1 Like

Both of these urls evaluate to true with this regex /recruiters/one_or_more_chars maybe a dash and one_or_more_chars/one_or_more_chars maybe a dash and one_or_more_chars/one_or_more_chars maybe a dash and one_or_more_chars

Regex(symfony requirements) doesn’t understand what a country is or what a function is.

Yeah I can see that now - looking at available regex and the descriptions - uses. It can differentiate between a number and a letter, but that’s the extent of it for my specific use case. Oh well, thought I was onto something there - back to the drawing board.

1 Like

Good luck!
Now back to my cave. I’ll be back tomorrow at beer time.

1 Like

Thank for your help Jon.

Just at a bit of a loss here, there are sites that have the exact same URL structure, e.g.

They would not have fixed parameters for every single state, industry and city i’m sure and don’t need to append with /c/ or /p/ :frowning:

Will keep trying to figure out how to do it.

Hey @JonL - sorry one final question for you, I hope, and I hope you don’t mind.

I’ve tried to create a SC only route, and using the $_GET variable, from the url parameter - but I am unable to get the url parameter unless the SC is on a page load, rather than just a route path.

Would you mind explaining what you mean when you say SC associated to that route?

Would I assign for example a SC to the layout page for example, and on the layout page have all 6 query parameters that I pass through to 6 $_GET variables on the SC?

Or would I need a separate content page (/view) for each variation of parameters, e.g. /:parameter1 /:parameter1:/parameter2 & /:parameter1/:parameter2/:parameter3 etc. and then that page is blank, but holds the SC that passes those URL parameters to the SC on each page?

Hopefully I can figure out the rest if I can figure out how first to capture the route params.

Sorry for the late reply @mgaussie I am on and off due to holidays and poor signal reception.

You can’t use $_GET.parameter in this scenario. You need to use $_PARAM.parameter

So if your url is /this/that/:param1/:param2

You access them in the SC as $_PARAM.param1 and $_PARAM.param2

1 Like

No apologies! I appreciate your help. I thought as much but couldn’t get any data with this approach either on a SC route without loading an actual page first. I’ll try again this morn now i know that’s the way to do it

@mgaussie the basics have not changed and you still need to redirect somehow but now that you can add custom middleware you could probably do all that in custom route.
Instead of having it in SC actions.

1 Like