フックによるカスタマイズ

フックにより、Script API を使用して既存の Shopper API リソースの動作を変更したり拡張したりできます。

このページ内のリンクには、既存のお客様のみがアクセスできるものがあります。Commerce Cloud リポジトリにアクセスする方法については Salesforce Commerce Cloud GitHub リポジトリとアクセスを参照してください。

Tip

Script API について詳しくは、以下のドキュメントを参照してください。

利用可能なフック 

リソースでは、次のフックを利用できます。

  • before: 検証したいアドレスを送信する場合など、カスタムの検証に便利です。
  • after: 外部システムで検証して保持する必要がある支払情報を送信する場合など、データを変更する場合に便利です。
  • modifyResponse: レスポンスに含まれる内容を変更できます。たとえば、不要な属性や必要な追加の属性がある場合は、レスポンスフックを使用して、外部システムから取得した内容を変更できます。

B2C Commerce のシステム構成で使用可能なフック

GET リクエストでは、beforemodifyResponse のフックを使用できます。POST、PATCH、PUT、DELETE などのステータスを変更する HTTP メソッドでは、さらに after フックを使用できます。後者は、それに応じてデータベースへのトランザクションの書き込みも行います。

フックはすべての Shopper API に適用されるわけではありません。たとえば、Shopper Experience API を使用すれば、ページやコンポーネントタイプで独自のカスタマイズ機能を利用できます。

フックメソッドの詳細には、使用可能なフックが含まれています。

フックの前提条件 

Commerce API のフックを使用するには、まず Business Manager で B2C Commerce インスタンスのフックを有効にします。

アプリケーションランチャー アプリケーションランチャー をクリックし、管理 > グローバル環境設定 > 機能スイッチを選択して Salesforce Commerce Cloud API フック実行の有効化にチェックを入れます。

有効にするには、インスタンスの Account Manager での役割が Business Manager Administrator でなければなりません。

Note

フックの登録 

  1. カートリッジの最上位ディレクトリに package.json ファイルを配置します。
  2. package.json ファイルの hooks プロパティに、hooks.json 構成ファイルのパスを定義します。このパスは、package.json ファイルを含むディレクトリからの相対パスです。
    1{
    2  "hooks": "./cartridge/scripts/hooks.json"
    3}
  3. hooks.json ファイルで、hooks.json ファイルからの相対パスをもつスクリプトファイルへのフックのマッピングを含む配列を構成します。
    1{
    2  "hooks": [
    3    {
    4      "name": "dw.ocapi.shop.basket.billing_address.beforePUT",
    5      "script": "./basket_hook_scripts.js"
    6    },
    7    {
    8      "name": "dw.ocapi.shop.basket.billing_address.afterPUT",
    9      "script": "./basket_hook_scripts.js"
    10    }
    11  ]
    12}
  4. サイト固有の使用の場合は、Business Manager で適切な各サイトにカートリッジを登録します。ライブラリなど すべて のサイトで組織レベルのリソースをカスタマイズするには、カートリッジを Business Manager サイトに登録します。

フックスクリプト 

フックスクリプトは CommonJS モジュールとして読み込まれます。フック関数はエクスポートする必要があります。エクスポートされる名前は、パッケージ修飾なしで、フックの名前と一致する必要があります。たとえば、dw.ocapi.shop.basket.billing_address.beforePUT フックは beforePUT としてエクスポートされます。

1//  basket_hook_scripts.js
2var Status = require("dw/system/Status");
3var HookManager = require("dw/system/HookMgr");
4
5exports.beforePUT = function (basket, doc) {
6  // Detect whether the address is valid.
7  var isValidAddress = true;
8  if (isValidAddress) {
9    return new Status(Status.OK);
10  }
11  return new Status(Status.ERROR);
12};
13
14exports.afterPUT = function (basket, doc) {
15  // Calculate the basket by calling the convenience hook, which returns a status object.
16  var status = HookManager.callHook("dw.order.calculate", "calculate", basket);
17  return status;
18};
19
20exports.calculate = function (basket) {
21  return new Status(Status.OK);
22};

各フックについて、コードはサーバーに Status オブジェクトを 返すことがあります。ステータスが OK の場合、サーバーは処理を続けます。ステータスが ERROR (処理された例外を表す) の場合、サーバーはそれ以上の処理を停止し、トランザクションをロールバック して、HTTP 400 Bad Request エラーのレスポンスを返します。ERROR が発生すると、サーバーは、エラーコード、メッセージ、オブジェクトから Status の詳細などの情報を含むエラーを呼び出し元に返します。スローしたエラーを含め、コード内でキャッチされない例外は、HTTP 500 Internal Error エラーの原因となります。この場合、サーバーはトランザクションをロールバックします。

値を返す Shopper API 拡張ポイントのフックは、フックのシステム実装と、その拡張ポイントの後続の登録済みフックを スキップ します。フックのシステム実装と、拡張ポイントの後続の登録済みフックがスキップされないようにするには、Shopper API フックが何も返さず、買い物カゴ計算フックなどの重要な関数を実行できるようにすることをお勧めします。

カスタム 拡張ポイントのフックは、戻り値に関係なく、登録されているすべてのフックポイントを常に実行します。

ERROR が発生すると、サーバーは、エラーコード、メッセージ、Status オブジェクトからの詳細などの情報を含む RFC IETF rfc7807 ErrorResponse を呼び出し元に返します。

フックコードが Status オブジェクトを返さない場合、オーバーライドされた基本実装を含め、複数の登録済みフックスクリプトが実行される可能性 があります。この場合、これらのフックによって返された Status オブジェクトまたは値が代わりに返されます。

フック間でのデータの受け渡し 

1 つのリクエストで複数のフックを呼び出すことができます。たとえば、新しい支払手段を買い物カゴに追加すると、以下が呼び出されます。

  • dw.ocapi.shop.basket.payment_instrument.beforePOST
  • dw.ocapi.shop.basket.payment_instrument.afterPOST
  • dw.ocapi.shop.basket.payment_instrument.modifyPOSTResponse

フック間でデータを渡すには、request.custom を使用します。リクエストに追加された JavaScript オブジェクトは、後続のフックで使用できます。

たとえば、買い物カゴに新しい支払手段を追加する トランザクション内で サードパーティの支払処理業者を呼び出すには、dw.ocapi.shop.basket.payment_instrument.afterPOST フック内でこの呼び出しを行うことができます (エラーがトランザクションをロールバックするようにするため)。決済サービスプロバイダーを呼び出して支払リクエストを初期化した後、dw.ocapi.shop.basket.payment_instrument.modifyPOSTResponse フックで関連データをクライアントに返すことができます。これを行うには、modifyPOSTResponse フックで処理される request.custom コンテナに関連データを追加します。

1// dw.ocapi.shop.basket.payment_instrument.afterPOST
2exports.afterPOST = function (order, paymentInstrumentRequest) {
3  //...
4  request.custom.paymentIntentID = callPaymentService();
5};
6// dw.ocapi.shop.basket.payment_instrument.modifyPOSTResponse
7exports.modifyPOSTResponse = function (basket, basketResponse, paymentInstrumentRequest) {
8  // retrieve payment instrument created in this hook execution
9  var addedPayment = basketResponse.paymentInstruments.toArray().filter(function (instr) {
10    return instr.paymentMethodId === paymentInstrumentRequest.paymentMethodId;
11  })[0];
12  addedPayment.c_paymentIntentID = request.custom.paymentIntentID;
13};

サンプルフックコレクション 

Salesforce のコミュニティでは、顧客との多数のプロジェクトを通して、機能を拡張したり、新しい機能を提供したりするための、多くの有用な実装をもつフックコレクションが管理されています。コミュニティコレクションのフックは、実用的なユースケースを幅広くカバーしています。

詳細については、Salesforce Commerce Cloud GitHub リポジトリの OCAPI Hooks Collection (OCAPI フックコレクション) を参照してください。

Calculate フック 

Calculate フック (dw.order.calculate) を使用すると、カスタマイズされた買い物カゴ計算ロジックを実装できます。これは、買い物カゴの計算と再計算を 1 か所で行うために使用できます。このフックはデフォルトの実装を提供し、オーバーライドできます。

次のフックのデフォルトのロジックは、このフックを暗黙的に呼び出します。

  • dw.ocapi.baskets.actions.afterMerge
  • dw.ocapi.baskets.actions.afterTransfer
  • dw.ocapi.shop.basket.afterPATCH
  • dw.ocapi.shop.basket.afterPOST
  • dw.ocapi.shop.basket.agent.afterPUT
  • dw.ocapi.shop.basket.billing_address.afterPUT
  • dw.ocapi.shop.basket.coupon.afterDELETE
  • dw.ocapi.shop.basket.coupon.afterPOST
  • dw.ocapi.shop.basket.customer.afterPUT
  • dw.ocapi.shop.basket.gift_certificate_item.afterDELETE
  • dw.ocapi.shop.basket.gift_certificate_item.afterPATCH
  • dw.ocapi.shop.basket.gift_certificate_item.afterPOST
  • dw.ocapi.shop.basket.item.afterDELETE
  • dw.ocapi.shop.basket.item.afterPATCH
  • dw.ocapi.shop.basket.items.afterPOST
  • dw.ocapi.shop.basket.payment_instrument.afterDELETE
  • dw.ocapi.shop.basket.payment_instrument.afterPATCH
  • dw.ocapi.shop.basket.payment_instrument.afterPOST
  • dw.ocapi.shop.basket.price_adjustment.afterDELETE
  • dw.ocapi.shop.basket.price_adjustment.afterPATCH
  • dw.ocapi.shop.basket.price_adjustment.afterPOST
  • dw.ocapi.shop.basket.reference.afterPOST
  • dw.ocapi.shop.basket.shipment.afterDELETE
  • dw.ocapi.shop.basket.shipment.afterPATCH
  • dw.ocapi.shop.basket.shipment.afterPOST
  • dw.ocapi.shop.basket.shipment.shipping_address.afterPUT
  • dw.ocapi.shop.basket.shipment.shipping_method.afterPUT
  • dw.ocapi.shop.basket.storefront.afterPUT
  • dw.ocapi.shop.order.beforePOST
  • dw.ocapi.shop.order.beforePUT

次のコードスニペットはサンプルの呼び出しを示します:

1dw.system.HookMgr.callHook("dw.order.calculate", "calculate", basket);

このサンプルの呼び出しでは、パラメーターは次のとおりです:

  • "dw.order.calculate" - 呼び出す拡張ポイント
  • "calculate" - 呼び出すスクリプト関数
  • basket - 計算される買い物カゴ

SiteGenesis では、買い物カゴ計算ロジックに dw.order.calculate フックのデフォルト実装が使用されます。

Note

買い物客のコンテキストとフック 

B2C Commerce バージョン 24.7 では、サイト固有のカートリッジをアップロードすることで、Shopper Context (買い物客のコンテキスト) フックをサイトレベルでアップロードできます。サイト固有のフックを呼び出す場合は、siteId を指定する必要があります。

siteId を指定しない場合、エラーメッセージは返されませんが、サイト固有のフックは呼び出されません。詳細については、createShopperContext および updateShopperContext を参照してください。

Note

制約とベストプラクティス 

B2C Commerce API (SCAPI) でのフックの使用は OCAPI でのフックの使用と似ていますが、デベロッパーが注意しなければならない違いがあります。フックを有効にして維持すると、SCAPI と関連する OCAPI エンドポイントの両方に対して 同じフック が呼び出されるため、両方に使用するフックを記述できます。これは、両方の API フレームワークをクライアントアプリケーションに使用する場合に重要です。

SCAPI や OCAPI の用途を判断する場合、request.isSCAPI() を使用します。特に、すでにコントローラーのコンテキストで計算フックを使用していて、そのフックでトランザクションを使用すると、SCAPI が破損してしまいます。

条件付き動作 

カスタムクエリパラメーター 

条件付き動作をフックに追加するには、カスタムクエリ文字列パラメーターを使用します。パラメーターには、c_ という接頭辞を付ける必要があります。

1const Status = require("dw/system/Status");
2
3exports.beforeGET = function () {
4  const isRequiredParameterPresent = request.httpParameterMap.get("c_required");
5  if (!isRequiredParameterPresent) {
6    return new Status(Status.Error);
7  }
8};

カスタムヘッダー 

SCAPI は、診断と情報提供の目的で、カスタムの HTTP リクエストヘッダーとレスポンスヘッダーをサポートしています。

  • カスタムヘッダーには、先頭に c_ を付ける必要があります。
  • カスタムヘッダーはキャッシュキーの構築時に考慮されないため、条件付き動作を実装するためにカスタムヘッダーを使用しないでください。詳細については、サーバー側の Web 階層キャッシングを参照してください。
  • カスタムリクエストヘッダーは、レスポンスボディに影響を与えるような方法で使用しないでください。カスタムヘッダーは、ログ記録などの診断または情報提供のみを目的としています。

Important

次の例では、リクエストヘッダーに欠落している必須パラメーター値のエラーメッセージをログに記録します。

1const Logger = require("dw/system/Logger");
2
3exports.beforeGET = function logClientVersion() {
4  const customClientVersion = request.httpHeaders.get("c_client_version");
5  if (customClientVersion) {
6    Logger.info("Client Version: " + customClientVersion);
7  }
8};

次の例は、サンプルのカスタムレスポンスヘッダーを示しています。

1const response = require("dw/system/Response");
2
3exports.afterGET = function sendCustomResponseHeader() {
4  const customClientVersion = request.httpHeaders.get("c_client_version");
5  if (customClientVersion) {
6    response.setHttpHeaders("c_client_version_response", customClientVersion);
7  }
8};

フックによるカスタム検証 

SCAPI と OCAPI フックを使用して、エラーを解析および処理するカスタム検証ロジックを実装できます。

たとえば、フックを使用して配送先住所のカスタム検証を追加するには、次のようにします。

1const Status = require("dw/system/Status");
2
3// dw.ocapi.shop.basket.shipment.shipping_address.beforePUT
4exports.beforePUT = function shipperAddressValidationBeforePut(address) {
5  const isValidAddress = myFancyAddressValidationLookup(address);
6  if (!isValidAddress) {
7    const status = new Status(Status.ERROR);
8    status.addDetail("validation_error", "Bad Shipping Address");
9    return status;
10  }
11};

Status.addDetail(key, value) を使用して、クライアントが解析して使用できるエラーの詳細を追加します。詳細については、クラスステータスを参照してください。

isValidAddress が false の場合、SCAPI はコンテンツタイプが application/problem+json の HTTP 400 レスポンスを返します。

1{
2  "title": "Hook Status",
3  "type": "https://api.commercecloud.salesforce.com/documentation/error/v1/errors/hook-status",
4  "detail": "An error occurred in ExtensionPoint 'dw.ocapi.shop.category.beforeGET'.",
5  "extensionPoint": "dw.ocapi.shop.category.beforeGET",
6  "statusCode": "ERROR",
7  "statusMessage": "ERROR",
8  "statusDetails": {
9    "validation_error": "Bad Shipping Address"
10  }
11}

フックのエラー処理 

未処理の例外 

フックが未処理の例外またはエラー (ネットワークエラー、コード構文エラー) を発生させた場合、HTTP 500 レスポンスが返されます。

1{
2  "title": "Hook Internal Server Error",
3  "type": "https://api.commercecloud.salesforce.com/documentation/error/v1/errors/hook-internal-server-error",
4  "detail": "Hook Execution Error"
5}

サーキットブレーカー 

フックのサーキットブレーカーは、フック実行の失敗が過剰に発生した場合にシステムを保護します。フックが生成するエラーが多すぎると、サーキットブレーカーがアクティブになり、HTTP 503 レスポンスが返されます。

1{
2  "title": "Hook Circuit Breaker",
3  "type": "https://api.commercecloud.salesforce.com/documentation/error/v1/errors/hook-circuit-breaker",
4  "detail": "The ExtensionPoint 'dw.ocapi.shop.category.beforeGET' failure rate was above the threshold of '50 %'.",
5  "extensionPointName": "dw.ocapi.shop.category.beforeGET",
6  "threshold": "50"
7}

詳細については、フックのサーキットブレーカーを参照してください。

フック実行エラーの追跡 

フックの処理中にエラーが発生すると、リクエストは失敗します。フックエラーは Log Center で追跡できます。検索は、LCQL クエリ category: ( com.demandware.wapi.servlet.ShopRestServlet ) AND stackTrace: ( HookInvocationException ) を使用して構成します。または、失敗したリクエストに関連付けられている相関 ID を使用します。

タイムアウト 

すべての SCAPI レスポンスは、指定されたタイムアウト期間内に返される必要があります。これには、適用されるフックの実行も含まれます。SCAPI リクエストへのレスポンスがタイムアウトしきい値を超えると、HTTP 504 ステータスコードが返されます。

タイムアウト値の詳細については、エラーレスポンスコードを参照してください。

ModifyResponse フックの制限事項 

modifyResponse フックは、アプリケーションのニーズに最適なレスポンスを作成するための強力な手段です。オブジェクトに情報を追加したり、UI で使いやすいプロパティセットを提供することで、クライアントアプリケーションでの消費を改善できます。

追加のプロパティは、カスタムプロパティ (c_ プロパティ) としてのみ追加します。

フックと SCAPI キャッシング 

SCAPI フックを使用するエンドポイントのキャッシュを有効にすると、フックロジックがアプリケーションサーバーによって実行され、結果がキャッシュされます。アプリケーションサーバーロジックもカスタムフックロジックも、オブジェクトがキャッシュから期限切れになるまで再実行されません。詳細については、サーバー側の Web 階層キャッシングを参照してください。

Taxes API とフック 

B2C Commerce バックエンドに組み込まれている買い物カゴ計算は、買い物カゴ情報を決定するために有効になっています。SCAPI エンドポイントを使用すると、買い物カゴの税務情報を操作できます。

B2C Commerce 24.5 では、フックが有効な場合、以下のエンドポイントがサポートされます。

  • /checkout/baskets/{}/taxes
  • /checkout/orders/{}/taxes
  • /checkout/baskets/{}/items/{}/taxes

以下の Script API メソッドを使用して、フックで SCAPI 外部課税 API をサポートできます。

次のエンドポイントは、フックが有効な状態ではサポートされません。フックを有効にしてこのエンドポイントを呼び出すと、リクエストから HTTP 409 エラーレスポンスが返されます。

  • /checkout/baskets/{basketId}/price-books