AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

B2c Controllers

skill-salesforcecommercecloud-b2c-developer-tooling-b2c-controllers · by SalesforceCommerceCloud

Create storefront controllers using SFRA or classic patterns with server.get/post, middleware chains, and res.render/json. Use this skill whenever the user needs to build a page route, handle form submissions, create AJAX endpoints, extend or override existing controllers, or add middleware to a request pipeline. Also use when debugging route registration or response rendering -- even if they jus…

No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add skill-salesforcecommercecloud-b2c-developer-tooling-b2c-controllers

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-salesforcecommercecloud-b2c-developer-tooling-b2c-controllers)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of B2c Controllers? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Controllers Skill

This skill guides you through creating storefront controllers for Salesforce B2C Commerce. Controllers handle HTTP requests and render responses for the storefront.

Overview

Controllers are JavaScript modules that handle storefront requests. A controller URL has this structure:

https://{domain}/on/demandware.store/Sites-{SiteName}-Site/{locale}/{ControllerName}-{FunctionName}

Example: https://example.com/on/demandware.store/Sites-RefArch-Site/en_US/Home-Show

Two Controller Patterns

B2C Commerce supports two controller patterns:

| Pattern | When to Use | Module Style | |---------|-------------|--------------| | SFRA | Storefront Reference Architecture sites | server module with middleware | | Classic | Non-SFRA sites, simple APIs | Direct exports with .public = true |

SFRA is recommended for most storefront development. Classic controllers are useful for simple endpoints or non-SFRA projects.

File Location

Controllers reside in the cartridge's controllers directory:

/my-cartridge
    /cartridge
        /controllers
            Home.js           # URL: Home-{function}
            Product.js        # URL: Product-{function}
            Cart.js           # URL: Cart-{function}

Naming: Controller filename becomes the URL prefix. Home.js handles Home-* requests.

SFRA Controllers (Recommended)

SFRA controllers use the server module for routing and middleware:

'use strict';

var server = require('server');

// Handle GET request
server.get('Show', function (req, res, next) {
    res.render('home/homepage');
    next();
});

// Handle POST request
server.post('Subscribe', function (req, res, next) {
    var email = req.form.email;
    // Process subscription...
    res.json({ success: true });
    next();
});

module.exports = server.exports();

Request Object (req)

req.querystring          // Query parameters: ?q=shoes -> req.querystring.q
req.form                 // Form POST data: req.form.email
req.httpMethod           // HTTP method: 'GET', 'POST', etc.
req.httpHeaders          // Request headers
req.currentCustomer      // Current customer object
req.locale               // Current locale
req.session              // Session object

Response Object (res)

res.render('template', model)   // Render ISML template with data
res.json(object)                // Return JSON response
res.redirect(url)               // Redirect to URL
res.setViewData(data)           // Add data to view model
res.getViewData()               // Get current view model
res.setStatusCode(code)         // Set HTTP status code

Middleware

Apply middleware to routes for cross-cutting concerns:

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

// Apply caching
server.get('Show', cache.applyDefaultCache, function (req, res, next) {
    res.render('home/homepage');
    next();
});

// Require HTTPS
server.post('Login', server.middleware.https, function (req, res, next) {
    // Handle login...
    next();
});

// CSRF protection for forms
server.post('Submit', csrfProtection.validateAjaxRequest, function (req, res, next) {
    // Handle form submission...
    next();
});

Common Middleware

| Middleware | Purpose | |------------|---------| | server.middleware.https | Require HTTPS connection | | cache.applyDefaultCache | Apply default page caching | | csrfProtection.validateAjaxRequest | Validate CSRF token | | consentTracking.consent | Check tracking consent | | userLoggedIn.validateLoggedIn | Require authenticated user |

Route Events

Execute code at specific points in the request lifecycle:

server.post('Submit', function (req, res, next) {
    var form = req.form;
    res.setViewData({ email: form.email });
    next();
}, function (req, res, next) {
    // Additional middleware
    next();
});

// Execute after all middleware, before render
this.on('route:BeforeComplete', function (req, res) {
    var viewData = res.getViewData();
    // Modify view data if needed
});

Extending Controllers

Extend existing controllers to add or modify functionality:

'use strict';

var server = require('server');
var page = module.superModule;  // Get parent controller

server.extend(page);

// Add new route
server.get('NewRoute', function (req, res, next) {
    res.render('newtemplate');
    next();
});

// Override existing route
server.replace('Show', function (req, res, next) {
    // Custom implementation
    res.render('custom/homepage');
    next();
});

// Prepend to existing route
server.prepend('Show', function (req, res, next) {
    // Runs before original handler
    next();
});

// Append to existing route
server.append('Show', function (req, res, next) {
    // Runs after original handler
    var viewData = res.getViewData();
    viewData.customData = 'value';
    res.setViewData(viewData);
    next();
});

module.exports = server.exports();

Classic Controllers (Non-SFRA)

For non-SFRA sites or simple endpoints, use direct exports:

'use strict';

var ISML = require('dw/template/ISML');

exports.Show = function () {
    var params = request.httpParameterMap;
    var productId = params.pid.stringValue;

    ISML.renderTemplate('product/detail', {
        productId: productId
    });
};
exports.Show.public = true;  // Required: marks function as accessible

exports.GetData = function () {
    var result = { status: 'ok', data: [] };

    response.setContentType('application/json');
    response.writer.print(JSON.stringify(result));
};
exports.GetData.public = true;

Key difference: Classic controllers use exports.FunctionName.public = true instead of the server module.

Module Imports

Import B2C Commerce APIs using require():

// B2C Commerce APIs
var ProductMgr = require('dw/catalog/ProductMgr');
var Transaction = require('dw/system/Transaction');
var Logger = require('dw/system/Logger');
var URLUtils = require('dw/web/URLUtils');
var Resource = require('dw/web/Resource');

// Cartridge modules (use */ for cartridge path resolution)
var collections = require('*/cartridge/scripts/util/collections');
var productHelper = require('*/cartridge/scripts/helpers/productHelpers');

Best Practice: Only require modules when needed, not all at the top of the file.

Error Handling

Wrap operations in try-catch blocks:

server.get('Show', function (req, res, next) {
    try {
        var product = ProductMgr.getProduct(req.querystring.pid);
        if (!product) {
            res.setStatusCode(404);
            res.render('error/notfound');
            return next();
        }
        res.render('product/detail', { product: product });
    } catch (e) {
        Logger.error('Product error: ' + e.message);
        res.setStatusCode(500);
        res.render('error/general');
    }
    next();
});

Generating URLs

Use URLUtils to generate locale-aware URLs:

var URLUtils = require('dw/web/URLUtils');

// Controller URL
var productUrl = URLUtils.url('Product-Show', 'pid', 'ABC123');
// Result: /on/demandware.store/Sites-RefArch-Site/en_US/Product-Show?pid=ABC123

// HTTPS URL
var loginUrl = URLUtils.https('Login-Show');

// Static resource URL
var imageUrl = URLUtils.staticURL('/images/logo.png');

Best Practices

  1. Always call next() in SFRA middleware chain
  2. Use ViewModels to prepare data for templates
  3. Keep controllers thin - move business logic to scripts/helpers
  4. Use hooks for functionality that works for both storefront and OCAPI
  5. Handle errors gracefully - never expose stack traces
  6. Use */cartridge/... for portable module paths

Detailed Reference

For comprehensive patterns and examples:

  • [SFRA Patterns](references/SFRA-PATTERNS.md) - Full SFRA patterns with middleware
  • [Classic Patterns](references/CLASSIC-PATTERNS.md) - Non-SFRA controller patterns

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.