Have you ever wondered how Salesforce Commerce Cloud, especially SFRA (Storefront Reference Architecture), handles the rendering of pages based on controllers and routes?
It’s like embarking from point A to point B, with controlled detours and sudden stops. This blog will explore how SFRA allows us to navigate these situations and the various options available at different locations.
Let’s dive in!
Global Hooks
Before we discuss the SFRA specifics, let’s start with some global options that allow us to execute code for any request (SFRA or not).
For the technical details, please read this blog post by Johnny Tordgeman.
onRequest
The onRequest hook in SFCC allows you to intercept and modify an incoming HTTP request before the system processes it.
This hook is commonly used for session validation, request validation, or custom logging tasks.
onSession
The onSession hook is a server-side hook executed at the beginning of each new session. This hook allows you to perform custom logic or set session attributes before the session is initialised.
It can be used to customise the session behaviour (like plugin_slas), such as setting default values, checking for certain conditions, or performing any necessary setup before the session is fully established.
SFRA Routes?
Before we get started, we need to ensure we are on the same page on what a “route” is.
In the context of SFRA (Storefront Reference Architecture) of SFCC (Salesforce Commerce Cloud), a controller route is a mapping between a URL and a specific controller function.
When a user navigates to a specific URL within the SFRA storefront, the controller function, a key element of the SFRA architecture, handles the request and generates the appropriate response (usually ISML or JSON).
The standard available options, and the most common ones, are:
- GET
- POST
These will serve as the ‘base route’, the starting point of our project. But remember, this is just the beginning. We have the power to extend and customize this base route of SFRA, as we’ll discover in the options outlined in this blog post.
SFRA Server functions to extend and replace
Cartridge path: plugin_custom:app_storefront_base
server.prepend()
The `server.prepend` function adds a middleware function to the beginning of the route stack. This allows you to execute code before the base (app_storefront_base) processing begins.
Here’s a simple example of how you can use `server.prepend` with the homepage function:
server.prepend('Show', function (req, res, next) {
// Your code here will be executed before the app_storefront_base
next();
});
server.append()
The `server.append` function adds a middleware function to the end of the route stack. This allows you to execute code after the base (app_storefront_base) processing finishes.
Here’s a simple example of how you can use `server.append` with the homepage function:
server.append('Show', function (req, res, next) {
// Your code here will be executed after the show function in app_storefront_base
next();
});
server.replace()
The `server.replace` function replaces the entire route stack up until that point. This allows you to replace code in the base (app_storefront_base) fully.
Here’s a simple example of how you can use `server.replace` with the homepage function:
server.replace('Show', function (req, res, next) {
var Site = require('dw/system/Site');
var PageMgr = require('dw/experience/PageMgr');
var pageMetaHelper = require('*/cartridge/scripts/helpers/pageMetaHelper');
pageMetaHelper.setPageMetaTags(req.pageMetaData, Site.current);
var page = PageMgr.getPage('homepage');
if (page && page.isVisible()) {
res.page('homepage');
} else {
res.render('home/homePage');
}
next();
});
SFRA Route Hooks
The options explained above already give you quite a bit of flexibility. But what if I told you there is even more to come? The route itself also exposes a few “events” in which we can hook into:
- route:Start: Executes at the start of the route, before any middleware defined using “server.*”
- route:BeforeComplete: Executes after all route middleware is finished but before the “route:Complete” event.
- route:Complete: The final event, after everything else.
- route:Step: Executed between each route middleware.
- route:Redirect: Executed when a “res.redirect()” is executed.
server.replace('Show', function (req, res, next) {
this.on('route:BeforeComplete', function (req, res) {
var viewData = res.getViewData();
// Your custom logic, executed at the end of the route
});
next();
});
Bringing it all together
Multiple Cartridges
The cartridge path influences the order in which SFRA middlewares are executed.
Cartridges higher up in the path are given precedence over those lower down. This means that the middleware in cartridges at the beginning of the path will be executed before those in cartridges further down the path.
New to the concept of “cartridge path”? Have a look at this trail!