SFRA Controllers

If you are starting a new storefront implementation, we recommend using Storefront Reference Architecture (SFRA) controllers instead of SiteGenesis controllers or pipelines for your application code. For information on the differences between pipelines and controllers, see Comparing Pipelines and Controllers.

What Are Controllers?

Controllers are server-side scripts that handle storefront requests. Controllers manage the flow of data in your application, and create ViewModels to process each storefront request as a route and generate an appropriate response. For example, in a storefront application, clicking a category menu item or entering a search term triggers a controller that renders a page.

Controllers are written in JavaScript and Salesforce B2C Commerce script. They must conform to the CommonJS module standard. For information on modules in B2C Commerce, see SFRA Modules and SFRA Hooks

A controller's file extension can be either .ds or .js. Controllers must be located in the controllers folder at the top level of the cartridge. Exported methods for controllers must be explicitly made public to be available to handle storefront requests.

Example: SFRA Base Cartridge Controller Hello.Js

'use strict';

var server = require('server');
var cache = require('*/cartridge/scripts/middleware/cache');

server.get('World', cache.applyDefaultCache, function (req, res, next) {
    res.render('helloworld', {
    	Message: 'Hello World! Again.'
    });;
    next();
});

module.exports = server.exports();
Controllers can use require to:
  • Import script modules. Any B2C Commerce script can be made into a CommonJS module and required by a controller.
  • Import B2C Commerce packages, instead of using the importPackages method. This approach is the recommended way to reference functionality from a controller. You can also use the require method to import a single B2C Commerce class. For example:
    var rootFolder = require('dw/content/ContentMgr').getSiteLibrary().root; 

While it isn't best practice, controllers can also:

  • Call other controllers. We don't recommend that controllers call each other, because controller functionality is self-contained to avoid circular dependencies. Sometimes, however, such as calling non-public controllers during the checkout process, it's unavoidable.
  • Call pipelets. We strongly discourage calling pipelets from within a controller. However, it's allowed while there are still pipelets that don't have equivalent B2C Commerce script methods.
  • Import packages. We discourage this approach because it doesn't use standard JavaScript patterns. This approach is Rhino-specific.
  • Call pipelines that don't end in interaction continue nodes. This technique is only intended for use with existing link cartridges and is highly discouraged for general development.
    Note: It isn't currently possible to call pipelines that end in interaction continue nodes.

Request URLs

A request URL for a controller has the format controller-function. For example, the request URL for the Hello.js controller World function looks like:
https://localhost/on/demandware.store/Sites-RefArch-Site/default/Hello-World
See also: B2C Commerce URL Syntax Without SEO.
Note: When beginning development

Reserved Names for Controllers

B2C Commerce has several system names that are reserved and can't be used for custom controllers and their functions. For a full list, see System Pipelines and Controllers.

Global Variables, Request Parameters, and Page Meta Data

SFRA uses the server.req and server.res objects for request and response data. While global variables are still available, we don't recommend that you use them.

Debugging

Almost any JavaScript-related error gets logged in the customerror_* log files, including errors from B2C Commerce scripts and controllers. The error_* log files contain Java-related errors on B2C Commerce, and are probably less useful to non-B2C Commerce employees

The Error.js controller services uncaught errors. By default, B2C Commerce returns a 410 error, which indicates that the resource is no longer available. If you prefer 404, it's fine to use as long as the related ISML template doesn't include <isslot>, <iscomponent>, or <isinclude> tags. When you want to handle these errors explicitly, you can use try/catch statements.

Best Practices

Performance

Only require modules when you need them, not at the top of a module.

Using with OCAPI

You can build a mobile or native app in addition to your storefront. If you want to create modules that work both for a desktop storefront and a mobile app, use hooks.

Jobs

It isn't possible to create jobs with controllers. Jobs can only be created using pipelines.