If you are reading this post, chances are that you have been trying to implement a catch-all route into Vue 3, or upgrading one from Vue 2, and not being able to succeed. This article is going to provide you with the details you need to upgrade your application and successfully set up a route that would catch all endpoints.
TLTR;
Vue-router 4 (the version of vue-router that works with Vue 3) introduced a breaking change that require you to define a star or catch-all route using a parameter with a custom regex. An example for a 404 route would be “{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound }
“.
What is a catch all route
A catch all route, also known as a wildcard, is a route that is specifically set to redirect users to a specific page in the case in which the inserted URL is not existing. This wildcard is very commonly used for a 404 page.
Regex in catch all route
Routes are usually defined by creating rules on the specific URL path. So for example creating a route for a path of /user
would be caught when the user enters website.com/user
, but it won’t if the user enters website.com/my-user
or any other word that is not precisely the one set in the path rule.
For the case of a wildcard, or catch all route the rule is usually set using a regular expression. A regular expression is:
A regular expression (shortened as regex or regexp; sometimes referred to as rational expression) is a sequence of characters that specifies a search pattern in text
https://en.wikipedia.org/wiki/Regular_expression
For the case of a catch all, the router rule would be defined by using a regex that would catch all character. This would be defined using the two symbols .*
. These two symbols means respectively:
.
– indicates any character*
– mean “0 or more instances of the preceding regex token”
How do you define a catch all in Vue 3
Now that we have learned what a catch all actually is, it is time to see how to use this in practice in our Vue 3 application. As I mentioned at the very start of this post, the syntax required to define this route in Vue 3 has changes from Vue 2 due to a breaking change.
The main change in Vue 3 require us to setup the Regex using a parameter with custom regex.
What are parameters with custom regex
Before we move forward it is important to really understand what a parameters with custom regex are in Vue router. Many people, included me, would jump to the definition of the catch all rule, without actually understanding what a parameter with custom regex is and its usage.
As the name explain, this feature merges two important options of routes: parameters and regex.
Parameters
In the site expressjs.com parameters in route are expressed as:
Route parameters are named URL segments that are used to capture the values specified at their position in the URL
https://expressjs.com
So for example a route set with the following path /:orderId
would capture any value inserted after the forward slash and provide it to the server. Please note that the name used for the parameter is completely arbitrary and we could have used whatever we want as it does not affect the URL accessed, as shown below:
// Routes
{ path: '/:arbitraryParameter' }
// Correct URL
mywebsite.com/123
mywebsite.com/simone
mywebsite.com/simone123
Regex
The next features offered by the parameter with custom regex is the ability to define a regex for our route. So for example, we could enhance the example above by making sure that the route is just hit if the orderId is made of all numbers:
{ path: '/:orderId(\\d+)' }
Using a bunch of custom regex to define paths is not really advised, as custom regex can be very fragile and hard to maintain. To avoid complicated routes, it is suggested to created nested routes to easily differentiate between routes without the need of a custom regex.
{ path: '/order/:orderId' }, // accessed from mywebsite.com/order/123
{ path: '/user/:userId' } // accessed from mywebsite.com/user/simone
The wildcard (catch all) scenario
Even if above we have indicated that regex should to not be used, there are some special cases where the use of regex can create helpful feature, for example when creating a catch all or 404 route.
As we mentioned above, this route is used in the case in which the user has miss-typed a route and did not enter anything that exist on the site, and returns a 404 (not found) page.
In this scenario, the use of a regex is beneficial as it helps us to define a rule that would catch URL entered, by creating a very generic regex.
To define a catch all rule in vue-router 4 we would enter the following code:
{ path: '/:pathMatch(.*)', name: 'not-found', component: NotFound }
As we can see, the catch all route is defined using the parameter with custom regex that we have recently introduced. The above rule will work with any URL that cannon be found in our defined rules, so for example mywebsite.com/fake/url
and mywebsite.com/404
will redirect correctly to the NotFound component, but unfortunately it wont work if we try to call our route by its name.
How to create a catch all route that can be called by its name
There are cases in which the developers may want to redirect an user to the 404 page dynamically. This is usually the result of a bad request or an action that has resulted in the wrong outcomes. When defining a programmatic navigation, it is usually beneficial to do so using the name of routes, as it makes the code more readable. For example in our case the code to programmatically navigate to a catch all route would look like this:
router.push({ name: 'not-found'});
As we quickly mentioned previously, the above programmatic navigation will not work with out defined route. This is because the parameter that we have defined in our not-found
route is currently required and it cannot be omitted.
To be able to navigate to this route with the use of its name (and without having to pass extra parameter) we need to make our route parameter optional.
Paramethers can be made optional in 2 different ways:
- ? Mark a parameter as optional and cannot be repeated
- * Mark a parameter as optional but repeatable.
In our case we would like to receive a list of all parameters sent as part of the URL and we would therefore use the *
. Our route will now look like this:
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound }
With the above code, we are not only able to catch wrong URL, but also able to dynamically access the route.
Conclusion
Creating a catch all route is quite simple, and searching on the internet usually provided the answer that we all wanted, but it is important sometimes to investigate things further and try to understand how things actually work and the main reason behind specific features.
In my case fully understand the catch all, has helped me to fully comprehendthe parameter with custom regex and “optional” options.
I hope this post has been helpful to you as it has been to me, and please feel free to leave a comment to help me improve this post for future readers.