mcpField
B
b2c-controllers

b2c-controllers

github.com/salesforcecommercecloud開発57102 回インストール今日更新
リポジトリ

b2c-controllers について

Salesforce B2C Commerce のストアフロントコントローラー開発を支援するスキルです。SFRA と Classic のルーティング、ミドルウェア、リクエスト処理、拡張方法を扱います。

主な機能

  1. 01SFRA のルーティングとミドルウェア
  2. 02Classic コントローラーのエクスポート
  3. 03リクエストとレスポンスの処理
  4. 04既存コントローラーの拡張
  5. 05ローカライズ URL の生成

活用シーン

  1. 01ストアフロントページへのルート追加
  2. 02シンプルな API 用コントローラーの作成
  3. 03既存コントローラーへの機能追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-controllers

インストール後、Claude Code で/b2c-controllersを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
trigger-evals.json
references/
CLASSIC-PATTERNS.md
SFRA-PATTERNS.md

詳細

コントローラースキル

このスキルでは、Salesforce B2C Commerce のストアフロントコントローラーの作成方法を説明します。コントローラーは HTTP リクエストを処理し、ストアフロント向けのレスポンスをレンダリングします。

概要

コントローラーは、ストアフロントのリクエストを処理する JavaScript モジュールです。コントローラーの URL は次の構造です。

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

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

2 つのコントローラーパターン

B2C Commerce は、次の 2 つのコントローラーパターンをサポートしています。

パターン使用する場面モジュール形式
SFRAStorefront Reference Architecture のサイトミドルウェアを使用する server モジュール
ClassicSFRA 以外のサイト、シンプルな API.public = true を指定した直接エクスポート

ほとんどのストアフロント開発では、SFRA が推奨されます。Classic コントローラーは、シンプルなエンドポイントや SFRA 以外のプロジェクトで役立ちます。

ファイルの場所

コントローラーは、カートリッジの controllers ディレクトリに配置します。

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

命名規則: コントローラーのファイル名が URL のプレフィックスになります。Home.js は Home-* リクエストを処理します。

SFRA コントローラー(推奨)

SFRA コントローラーでは、ルーティングとミドルウェアに server モジュールを使用します。

'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();
リクエストオブジェクト(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
レスポンスオブジェクト(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
ミドルウェア

横断的な関心事に対応するため、ルートにミドルウェアを適用します。

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();
});
一般的なミドルウェア
ミドルウェア用途
server.middleware.httpsHTTPS 接続を必須にする
cache.applyDefaultCacheデフォルトのページキャッシュを適用する
csrfProtection.validateAjaxRequestCSRF トークンを検証する
consentTracking.consentトラッキングへの同意を確認する
userLoggedIn.validateLoggedIn認証済みユーザーを必須にする
ルートイベント

リクエストのライフサイクルにおける特定のタイミングでコードを実行します。

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
});
コントローラーの拡張

既存のコントローラーを拡張して、機能を追加または変更します。

'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 コントローラー(SFRA 以外)

SFRA 以外のサイトやシンプルなエンドポイントでは、直接エクスポートを使用します。

'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;

主な違い: Classic コントローラーでは server モジュールの代わりに exports.FunctionName.public = true を使用します。

モジュールのインポート

require() を使用して B2C Commerce API をインポートします。

// 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');

ベストプラクティス: モジュールをファイルの先頭ですべて読み込むのではなく、必要なときにのみ読み込みます。

エラー処理

処理を try-catch ブロックで囲みます。

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();
});

URL の生成

URLUtils を使用して、ロケールに対応した URL を生成します。

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');

ベストプラクティス

  1. SFRA のミドルウェアチェーンでは、必ず next() を呼び出します
  2. テンプレート用のデータを準備するには ViewModels を使用します
  3. コントローラーは薄く保ちます。ビジネスロジックはスクリプトやヘルパーに移します
  4. ストアフロントと OCAPI の両方で機能する処理にはフックを使用します
  5. エラーを適切に処理します。スタックトレースを決して公開しないでください
  6. 移植可能なモジュールパスには */cartridge/... を使用します

詳細リファレンス

包括的なパターンと例については、以下を参照してください。

コメント