Routing system
Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
In EverShop we make use of ExpressJs for routing.
Before we dive into the routing system, we suggest you checkout the module structure document to understand more about the way a module is organized.
info
Check this document to understand more about EverShop project folder structure.
The fundamental
Let’s take a look a core module structure
In the picture above, there are 3 important things that we need to understand:
1: The controller folders
You can see there are 2 folders named “controllers” and “apiControllers” located under the “catalog” folder. They are where we organize our controller.
There 2 folders are identical. There are only 2 differences:
- The ‘api controller’ route will only return a JSON response
- The ‘api controller’ route URL will be prefixed by ‘v1’ automatically
2: The ‘admin’ and ‘site’ folders
Those folders are used for scoping. All routes located under the ‘site’ folder are used for front-page routing.
And all routes located under the ‘admin’ folder will be used for the admin panel and therefore several authentication middleware functions will be added to those routes.
3: The route folders
They are folders located under either the ‘site’ or ‘admin’ folder.
Basically, they contain 2 important things
The middleware functions will be executed when the route is triggered. You can learn more about how does middleware system works in this document The declaration of the route And the folder name will be used as a ‘route ID’.
info
Since the route folder name will be used as a ‘route ID’.So it has to be unique and basically, we do not accept special characters or whitespace.
The declaration of the route
In the above picture, in each route folder, there is a file named ‘route’. It is where we define our route specification.
Let’s take a look at one example:
GET,POST
/category/:url_key
In the above example, the route file has 2 lines:
GET,POST
: This is the list of accepted HTTP methods for the route. In case of multiple methods, you can use commas to separate them/category/:url_key
: This is the URL path of the route. We make use of Path-to-RegExp for route path. You can find more information route path here.
That is how we define our route specification.
Generate a URL of a specific route
When you are developing a module or a theme, there are many times that you need to generate a URL of a specific route.
EverShop has a function that helps you to general a URL of a route base on its ID.
Let’s take a look at an example
const { commit, rollback } = require('@evershop/mysql-query-builder');
const { buildUrl } = require('../../../../../lib/router/buildUrl');
// eslint-disable-next-line no-unused-vars
module.exports = async (request, response, stack, next) => {
const promises = [];
Object.keys(stack).forEach((id) => {
// Check if middleware is async
if (stack[id] instanceof Promise) {
promises.push(stack[id]);
}
});
const connection = await stack.getConnection;
const results = await Promise.allSettled(promises);
if (results.findIndex((r) => r.status === 'rejected') === -1) {
await commit(connection);
// Store success message to session
request.session.notifications = request.session.notifications || [];
request.session.notifications.push({
type: 'success',
message: request.body.product_id ? 'Product was updated successfully' : 'Product was created successfully'
});
request.session.save();
response.json({
data: { redirectUrl: buildUrl('productGrid') },
success: true,
message: request.body.product_id ? 'Product was updated successfully' : 'Product was created successfully'
});
} else {
await rollback(connection);
}
};
In the above example, we use function buildUrl
to generate a URL.
This function takes 2 arguments:
- The
route ID
. This is the ID of the route that you want to generate a URL. - Param list. A ‘key-value’ pare of route params in case your route has some dynamic params. And it returns a final URL.
buildUrl('productEdit', { id: 1 });