Tech & Engineering Blog

11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 8: A Tale of Two Events

🎼 Now this is a story all about how
My code got triggered only once
And I’d like to take a minute - just sit right there
I’ll tell you how I spent my day registering to events 🎼

So far in our SFCC journey, we saw how to write code that gets triggered by an action (for example, browsing to a route); but what if we want to run code that corresponds to an event? SFRA allows us to hook to all kind of events, such as payment events or analytics events, but on this post, we are going to focus on two very special events: onSession and onRequest.

Two Events Walk Into a Bar…

SFRA allows us to hook into all kinds of events, for example, app.communication.order.confirmation that notifies on an order confirmation or app.template.htmlHead , which, in turn, allows you to add content to the HTML head element — each handles a specific event in the flow of the storefront life.

onSession and onRequest represents different type of events as they enable us to hook into the life cycle of a storefront request and receive notifications on two different states:

  • onSession is called at the beginning of a new storefront session.
  • onRequest is called every single time a storefront request is received from the client.

 

Hook Me Up!

Hooking to events is done via a special file called hooks.json. This file contains hook entries for any number of events we wish to hook to and has to be declared inside of the cartridge’s package.json file. Each hook entry must contain the following two properties:

  • Name: The extension point (hook name)
  • Script: The script file to call when the event is fired.

🐘 Make sure that the script file you set for the hook entry contains a function which will run once the event is fired

For today’s project, we are going to hook to theonRequest event, check every storefront request for a query param called magic, and if found, and its value is true, redirect the user to our Magic-Show route.

We begin by declaring a hook entry for onRequest:

  1. cd to the services folder of MagicCartridge (cd cartridges/magicCartridge/cartridge/services), and create a new file named hooks.json.
  2. Add the following content to the newly created hooks.json:
{
  "hooks": [
    {
      "name": "dw.system.request.onRequest",
      "script": "./MagicValidator"
    }
  ]
}

Let’s break this JSON down:

Line 2: Declares a key called hooks and its value as an array of hook entries.

Lines 3–6: A hook entry.

Line 4: Sets the name of the event we wish to hook to. In our case we wish to validate every request to our storefront, so we will hook to the onRequest event.

Line 5: Sets the path and name of the script that will be called once the event fires. We will create the MagicValidator.js file in the same folder as hooks.json hence the use of ./ to specify the file path.

With the new hooks.js file in place, it’s time to register it:

  1. cd to the root folder of MagicCartridge (cd cartridges/magicCartridge), and create a new file named package.json.
  2. Add the following content to the newly created file:
{
	"hooks": "./cartridge/services/hooks.json"
}

 

Answer the Call!

With hooks.json registered, SFCC will fire an event for every incoming storefront request and call MagicValidator.js each time to handle the event. In turn, MagicValidator.js needs to export a method called onRequest to handle the event.

Let’s add MagicValidator.js to our cartridge and handle the event:

  1. cd to the services folder of MagicCartridge (cd cartridges/magicCartridge/cartridge/services), and create a new file named MagicValidator.js.
  2. Add the following content to the newly created MagicValidator.js file:
var Status = require('dw/system/Status');
var URLUtils = require('dw/web/URLUtils');

function onRequest() {
	if (request.httpRequest && !request.includeRequest) {
		if (request.httpQueryString.match(/magic=true/ig)) {
			response.redirect(URLUtils.url('Magic-Show'));
		}
	}
	
	return new Status(Status.OK);
}

module.exports = {
    onRequest: onRequest
};

So let’s see what we have here:

Line 5: Verifies the request we are processing is both an HTTP request and a top-level one (we don't want to start validating requests from remote sources on the page).

Line 6: Checks the request’s query params string for a parameter named magic with the value of true.

🐘 This query param check is rather naive and is only used in this case to demonstate the onRequest handler. If you are working with query params in your code — please use something better.

Line 7: Redirects the response to the Magic-Show route using the URLUtils class.

Line 11: If the request does not meet all of the above conditions, then pass the request back to SFCC’s request flow by setting its status to OK.

Lines 14–16: Exports the onRequest method.

 

Go Wild 🌈

Armed with the new event handler let’s test our new feature! Browse to any RL in your site front (for example /home). You should notice nothing changes and you are right on the home page as you should be. Now try to add the magic query params (/home?magic=true) and watch what happens:

Magic query params

No matter where we browse in our storefront now, we can go straight to the Magic route just by using a query param.

🐘 What if we want to be able to do this trick only once per session? Which event should we listen to in our hooks.json? (hint: it rhymes with passion)

And there you have it — a way to invoke code based on events and not by user interaction. Just make sure to use this wisely otherwise you will create some heavy load on the request flow, resulting in slow responses from the server.

Tomorrow we are going to deal with a really fun concept of SFCC — Jobs.

As always, looking forward to your comments either here or on Twitter 😎