※ これから記載する事項は、私が所属する会社とは一切関係のない事柄です。
本記事では、B2C CommerceのHookとは何か。また利用方法について紹介したいと思います。
Info CenterのHooksに関するヘルプはこちら。
Hooks とは?
アプリケーションのロジックの中に機能を組み込みたいときや、特定のイベントが発生した時に機能を組み込みたいときに利用します。extension point(以下、Hook名)というのを指定して機能の追加や実行を行います。
Hooksのタイプには下記の3種類あります。
- SCAPI / OCAPI Hooks
- B2C Commerce Hooks
- Custom Hooks
SCAPI/OCAPI Hooks
SCAPI/OCAPI HooksはSCAPIやOCAPIの特定のAPIが呼ばれた際に発生する事前に定義されたHook名に対して機能を追加できます。(SCAPIとOCAPIについては以前紹介したQiitaをご覧ください)
例えば、注文を作る(/orders
にPOSTする)ときに dw.ocapi.shop.order.afterPOST
というHook名のHookが実行されるので、そのHook内に外部の注文管理システムへ注文情報を連携する機能を追加することができます。
現状、dw.ocapi~
から始まっていますが、OCAPIだけでもなく、SCAPIでも使えますのでご留意ください。
どのようなHookがあるかはHooks名の一覧(OCAPI, SCAPI)をご覧ください。また、SCAPIで利用する際は、こちらのヘルプをご覧ください。(改めてSCAPIの利用時の注意点は後述します。)
B2C Commerce Hooks
B2C Commerce Hooksはシステム内での特定の機能にロジックを追加したいときに使用します。
例えば、注文番号が作成される際にdw.order.createOrderNo
というHookが呼ばれるので、注文番号にプリフィックスを付け足すことができます。
他にも多くのB2C Commerce Hooksありますが、Info Centerで「Hooks」で検索して、「Class ~Hooks」と書かれているページを参照してみてください。
Custom Hooks
一方Custom Hooksは、開発者自身でHook名を定義し、機能を追加することができます。
例えば、app.customer.registered
というHookを定義して、SFRAで顧客登録した際に、登録用のコントローラからそのHookを実行し、外部システムに顧客情報を連携することができます。
Hooksの使い方
Hooksはカートリッジ内に実装していきます。Hookの使い方のサンプルはGithubをご覧ください。(要Account Manager アカウント)
※ カートリッジの作成方法やアップロード方法については割愛します。詳しくはTrailhead、Infocenter、以前紹介したQIita記事 をご参照ください
Hooksを利用するのにカートリッジに内には最低でも下記3つのファイルが必要です。
下記の例はSCAPIでGET /customers/{custimer id}
でリクエストしたときにレスポンスボディの c_test
というプロパティに「Sample Test」という文言がはいる実装です。
{
"hooks": "./hooks.json"
}
{
"hooks": [
{
"name": "dw.ocapi.shop.customer.modifyGETResponse",
"script": "~/cartridge/scripts/hooks/sampleSCAPIHook"
}
]
}
exports.modifyGETResponse = function (customer, customerResponse) {
customerResponse.c_test = "Sample Test"
};
※ JSファイル名とフォルダは任意ですが、Hooksは大抵 cartridge/scripts/hooks
フォルダ に入っていることが多いです。
※ SCAPI/OCAPI Hooksで 「modify*Response」というHook名でレスポンスに新しいプロパティを追加する際は 「c_」で始まるプロパティ名にする必要 があります。
Custom Hooksの作り方・使い方
Custom Hooksも同様にカートリッジ内に実装していきます。
下記の例はコントローラ内部でHookを呼んでそのレスポンスをJSONとしてブラウザへ返しています。
{
"hooks": "./hooks.json"
}
任意のHook名を設定できます。
{
"hooks": [
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHook"
}
]
}
exports.SampleHookOne = function(data) {
return data + " sample_base"
}
Hookを呼ぶときは dw.system.HookMgr.callHook
でHook名(sample.hook)とメソッド名(SampleHookOne)を指定します。
"use strict";
var server = require("server");
server.get("Show", function (req, res, next) {
var resultOne = dw.system.HookMgr.callHook("sample.hook", "SampleHookOne", "This is Data to Hook One");
res.json({ one: resultOne });
next();
});
module.exports = server.exports();
同じHook名に複数のスクリプトが設定されている場合
同じHook名に複数のスクリプトを設定することができますが、その際の挙動を紹介します。
同一カートリッジ内での挙動
例えば同一カートリッジ内に下記のように同じHook名に2つスクリプトを設定するとします。
{
"hooks": [
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHook"
},
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHookTwo"
}
]
}
このときの挙動はリストの上から順に実行されます_ので、この場合は、sampleHook → sampleHookTwo という順番で実行されます。
複数カートリッジに設定した場合の挙動
例えば、sample_base, sample_custom_one. sample_custom_two という3つのカートリッジそれぞれに sample.hook
というHook名にスクリプトを設定した場合、実行される順番はカートリッジパスの 左から になります。
例えば、sample_custom_two:sample_custom_one:sample_base
のような順番で設定した場合は左から順に sample_custom_two → sample_custom_one → sample_base の順番で実行されます。
返り値について
同じHook名に複数のスクリプトが設定されている場合下記のように実行した場合、resultに代入される返り値はどのようになるでしょうか?
var result = dw.system.HookMgr.callHook("sample.hook", "SampleHook");
答えは、最後に実行されたスクリプトの値となります。
先の「同一カートリッジ内での挙動」の例で言うと、sampleHookTwo.js
内の SampleHook
メソッドの返り値となります。
※ 注意点として、sampleHookTwo.js
にSampleHook
メソッドが設定されていなかった場合は、sampleHook.js
の返り値ではなく、何も返ってきませんのでご留意ください。複数カートリッジに設定した場合も同様に全てのカートリッジの同じHook名に設定されたメソッドで最後に実行されたスクリプトの結果が帰ってくるようなので、最後のスクリプトにメソッド名がなかった場合は何も返ってきません。
まとめ
同一カートリッジ内での挙動と複数カートリッジ内の挙動をまとめます。
例えば下記のようなHooksの設定になっているとします。
sample_custom_two カートリッジ
{
"hooks": [
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHookCustomTwo"
},
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHookTwo"
}
]
}
sample_custom_one カートリッジ
{
"hooks": [
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHook"
},
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleCustomHook"
}
]
}
sample_base カートリッジ
{
"hooks": [
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHook"
},
{
"name": "sample.hook",
"script": "~/cartridge/scripts/hooks/sampleHookTwo"
}
]
}
呼び出し
var result = dw.system.HookMgr.callHook("sample.hook", "SampleHook");
さらにカートリッジパスが、sample_custom_two:sample_custom_one:sample_base
となっている場合、下記の順番で実行されます。
- sample_custom_twoカートリッジのsampleHookCustomTwo.js内のSampleHookメソッド
- sample_custom_twoカートリッジのsampleHookTwo.js内のSampleHookメソッド
- sample_custom_oneカートリッジのsampleHook.js内のSampleHookメソッド
- sample_custom_oneカートリッジのsampleCustomHook.js内のSampleHookメソッド
- sample_baseカートリッジのsampleHook.js内のSampleHookメソッド
- sample_baseカートリッジのsampleHookTwo.js内のSampleHookメソッド
そして、呼び出し時の返り値は「sample_baseカートリッジのsampleHookTwo.js内のSampleHookメソッド」の値となります。また、sample_baseカートリッジのsampleHookTwo.js内にSampleHookメソッドが設定されていない場合、何も返ってきません。
SCAPIを使うときの注意点
デフォルトではSCAPI HooksはOffになっているので、Business Managerで 管理 > グローバル環境設定 > 機能スイッチ に遷移して、「Salesforce Commerce API リクエストでのフックの実行を有効にします。」にチェックを入れて適用ボタンをクリックする必要があります。詳細はヘルプをご覧ください。