Customization with Hooks
Hooks allow you to alter and extend the behaviour of existing Shopper API resources using the Script API.
For more information on Script API, refer to the following documentation:
Each customizable resource provides before
, after
, and modifyResponse
hooks:
GET requests support before
and modifyResponse
hooks. State changing HTTP methods like POST, PATCH, PUT, and DELETE additionally support after
hooks. The latter also writes transactions to the database accordingly.
Typical use cases are:
before
: apply filter criteria for the API execution, and perform status checks.after
: finalize the mutation of an object such as setting status for a payment method or integrate with a third-party system like with an order placement.modifyResponse
: modify the response document to add or remove details.
The Hook List contains available hooks.
To use hooks for Commerce API, first enable it in Business Manager for your B2C Commerce instance.
Navigate to Administration > Global Preferences > Feature Switches and check Enable Salesforce Commerce Cloud API hook execution.
To enable, you must have the Account Manager role of Business Manager Administrator
for the instance.
- Place a
package.json
file in the top-level directory of your cartridge. - In the
package.json
file, define thehooks
property to the path of thehooks.json
configuration file. This path is relative to the directory containing thepackage.json
file: - In the
hooks.json
file, configure an array with the mappings of hooks to their script files with paths relative to thehooks.json
file: - For site specific use, register the cartridge to each appropriate site in Business Manager. To customize organization-level resources across all sites, such as libraries, register the cartridge to the Business Manager site.
Hook scripts are loaded as CommonJS modules. Hook functions must be exported. The exported name must match the name of the hook, without the package qualification. For example, the dw.ocapi.shop.basket.billing_address.beforePUT
hook is exported as beforePUT
:
For each hook, your code SHOULD return a Status
object to the server. Otherwise multiple registered hook scripts may be executed. If the status is OK
, the server continues processing. If the status is ERROR
, representing a handled exception, the server stops further processing, rolls back the transaction and responds with an HTTP 400 Bad Request fault. When an ERROR
occurs, the server returns a fault to the caller, containing information like the error code, message, and details from the Status
object. Uncaught exceptions in your code including the errors you throw cause an HTTP 500 Internal Error fault; in this case, the server rolls back the transaction.
When an ERROR
occurs, the server returns an RFC IETF rfc7807 ErrorResponse to the caller, containing information like the error code, message, and details from the Status
object.
The Hook Circuit Breaker protects the system from excessive hook execution failures. For more information, see Hook Circuit Breaker.
The Calculate hook, dw.order.calculate
, enables you to implement customized basket calculation logic. It can be used as the single place for basket calculation and recalculation. This hook provides a default implementation, can be overridden. The default logic of the following hooks implicitly call this hook:
- 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
The following code snippet shows a sample call:
In this sample call, the parameters are:
"dw.order.calculate"
- the extension point to call"calculate"
- the script function to callbasket
- the basket to be calculated
SiteGenesis uses the default implementation of the dw.order.calculate
hook for basket calculation logic.
Using hooks with the Salesforce Commerce API is similar to using hooks with OCAPI, but there are differences developers must be aware of. When you enable and maintain hooks, you must be aware that the same hooks are called for both SCAPI and the related OCAPI endpoints. This is important if you use both API frameworks for your client applications.
Hooks enabled for SCAPI still run under the timeout definition of the SCAPI endpoint. The amount of time that your hook takes to run adds to the overall processing time and the entire response, with the hook execution, and must still complete within the timeout period.
All Shopper APIs have a timeout of 10 seconds, except the Shopper-Products endpoint that has a timeout of 30 seconds.
One of the benefits of SCAPI is its contract-based API definition. It makes responses from SCAPI predictable, able to be documented, and the ability to put an SDK in use for them.
modifyResponse
hooks are a powerful way to create a response that best fits the needs of the application. You can add additional information to objects, or provide a more UI-friendly property set to improve the consumption on the client application. However, any changes to the response must fit in the API contract that has been established.
Keep the following in mind when dealing with modifyResponse
hooks:
- Additional properties must be added only as custom properties (
c_
properties). - Other modifications (deletion or changing of a property) must only occur within the boundaries of the API contract.
With the hooks enabled for SCAPI, the basket calculations built into the B2C Commerce backend are now in play for determining the basket information. There are endpoints created specifically for SCAPI (without hooks) that allowed the manipulation of tax information on the basket.
/checkout/baskets/{}/taxes
/checkout/orders/{}/taxes
/checkout/baskets/{}/items/{}/taxes
/checkout/baskets/{basketId}/price-books
These endpoints no longer work with the hooks enabled. Calling these endpoints result in a HTTP 409 error response from the request.
When writing your hook logic, it’s important to keep in mind the context of the API that is calling the hook. Both OCAPI and SCAPI share the same hooks, so it’s possible to write a hook that is used for both. Use request.isSCAPI()
to determine SCAPI or OCAPI usage, especially if you’re already using the calculate hook in the context of controllers and use transactions in that hook, as that breaks SCAPI.
To add conditional behaviour to a hook use custom query string parameters. Parameters must be prefixed with c_
:
Do not use HTTP headers for conditional behaviour as header values are not used to construct the cache keys for resources.
If a hook errors during processing, the request will fail. You can track hook errors with Log Center. Configure a search using the LCQL
query category: ( com.demandware.wapi.servlet.ShopRestServlet ) AND stackTrace: ( HookInvocationException )
.
As a result of many projects with customers, our community is maintaining a hook collection with many useful implementations to extend functionality or even provide new functionality. The hooks in the community collection cover a wide range of practical use cases. SCAPI supported hooks in the collection are:
- Order-Hooks
- OrderPaymentInstruments-Hooks
- Search-Hooks
- Basket-Hooks
- BasketPayments-Hooks
For more information, check out the OCAPI Hooks Collection on the Salesforce Commerce Cloud GitHub repository.
The OCAPI Hooks Collection GitHub repository isn’t open source. It’s part of a private collection of repositories for Salesforce Commerce Cloud customers. If you’re unable to access the repository, refer to the Salesforce Commerce Cloud GitHub Repositories and Access documentation in the Salesforce B2C Commerce Infocenter.