b2c-controllers について
Salesforce B2C Commerce のストアフロントコントローラー開発を支援するスキルです。SFRA と Classic のルーティング、ミドルウェア、リクエスト処理、拡張方法を扱います。
主な機能
- 01SFRA のルーティングとミドルウェア
- 02Classic コントローラーのエクスポート
- 03リクエストとレスポンスの処理
- 04既存コントローラーの拡張
- 05ローカライズ URL の生成
活用シーン
- 01ストアフロントページへのルート追加
- 02シンプルな API 用コントローラーの作成
- 03既存コントローラーへの機能追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ salesforcecommercecloud/ b2c-developer-tooling --skill b2c-controllersインストール後、Claude Code で/b2c-controllersを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/trigger-evals.jsonreferences/CLASSIC-PATTERNS.mdSFRA-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 つのコントローラーパターンをサポートしています。
| パターン | 使用する場面 | モジュール形式 |
|---|---|---|
| SFRA | Storefront Reference Architecture のサイト | ミドルウェアを使用する server モジュール |
| Classic | SFRA 以外のサイト、シンプルな 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.https | HTTPS 接続を必須にする |
cache.applyDefaultCache | デフォルトのページキャッシュを適用する |
csrfProtection.validateAjaxRequest | CSRF トークンを検証する |
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');
ベストプラクティス
- SFRA のミドルウェアチェーンでは、必ず
next()を呼び出します - テンプレート用のデータを準備するには ViewModels を使用します
- コントローラーは薄く保ちます。ビジネスロジックはスクリプトやヘルパーに移します
- ストアフロントと OCAPI の両方で機能する処理にはフックを使用します
- エラーを適切に処理します。スタックトレースを決して公開しないでください
- 移植可能なモジュールパスには
*/cartridge/...を使用します
詳細リファレンス
包括的なパターンと例については、以下を参照してください。
- SFRA パターン - ミドルウェアを含む SFRA パターンの全容
- Classic パターン - SFRA 以外のコントローラーパターン