OCAPI Customization 23.2

You can customize Shop API resources that perform a modification on the server side, such as the Customer and Basket resources. These resources provide extension points, or hooks, that enable you to augment server-side logic with your own script code.

Each customizable resource provides before, after, and modifyResponse extension points. Use the before and after extension points to execute custom code before or after the server performs its processing, respectively. Use the modifyResponse extension point to apply final changes to the response document. In addition, some special convenience hooks allow you to perform actions like basket calculations or special checkout steps. These convenience hooks let you place your basket-calculation code in a single place, instead of including duplicate code in multiple after extension points.

For information on extension points and supported resources, see the Hooks topic.

Customization Processing

Before 13.6, when the server received a request to modify a resource, it directly modified the resource and then sent a response directly to the caller. Starting in 13.6, you can augment the server's basic processing with your own custom code. The processing flow is as follows:

Shop API Customization Details

Processing Step Comment
Server receives a request to modify a resource Instead of directly modifying the resource, the server checks for registered before extension points.
Server calls your registered before extension point code The server passes the request document and a Script API object (representing the resource that it will modify). Your custom code can manipulate both, but typically performs input validation on the request document.
Server modifies the resource The server uses the request document processed by the before extension point, applying it to the Script API object.
Server calls your registered after extension point code The server passes the request document (after any modifications by the before extension point) and the Script API object. Your custom code can do some change tracking here, or you can modify the Script API object. For example, you can recalculate the basket. Do not modify the request document, because it is not processed again. It is provided here for informational purposes.
Server creates the response document The server copies values from the Script API object (after any modifications by the after extension point) into the response document.
Server calls your registered modifyResponse extension point code The server passes the previous response document (after any modifications by the after extension point) and the Script API object. This hook type is meant to make final changes to the response document only. Don't modify a Script API object in this hook type, because it is not executed in a transactional context. It can cause an ORMTransactionException and an HTTP 500 fault.
Server sends the response to the caller The server renders the response document (after any modifications by the after extension point) into the requested format. Then the server returns the response to the caller.
Note: For state-changing HTTP methods (DELETE, PATCH, POST, PUT), the server executes any before and after hook logic, plus the system logic, in the context of one database transaction. The transaction ensures that everything (or nothing) is committed into the database.
Note: Do not modify a Script API object in an HTTP GET request or a modifyResponse hook, because they are never executed in a transactional context. It can cause an ORMTransactionException and an HTTP 500 fault response.

For each extension point, your custom code must return a Status object to the server. If the status is OK, the server continues processing. If the status is ERROR (representing a handled exception), the server aborts all further processing and responds with an HTTP 400 (Bad Request) fault. When an ERROR occurs, the server returns an OCAPI fault to the caller, containing information like the error code, message, and details from the Status object. Any uncaught script exceptions in your custom code cause an HTTP 500 (Internal Error) fault; in this case, the server rolls back the entire transaction.

The modify<HTTP Method>Response Hooks

Starting in 18.3, modify<HTTP Method>Response customization hooks are provided for the Shop API. These hooks support POST, PUT, PATCH, and GET methods, and replace the previous afterGET hooks.

Modify response hooks have the following characteristics:

  • They support GET, POST, PUT, and PATCH methods to enrich the response document with custom information.
  • They enable your customization code to change and unset document attributes and add, delete, and change custom attributes in the return document.
  • They disallow database transactions within your customized script code, making it impossible for your code to change persistent data.
  • If there is caching, they are only executed if the cache is empty or stale. But they are not executed for every GET or HEAD call.

The following example shows customization script code for the Shop API category method:


    importPackage( dw.system );

    exports.modifyGETResponse = function(scriptCategory, categoryWO)
    {
        if(!scriptCategory.online)
        {
            categoryWO.c_modify_response_data = "modifyResponseData";
        }

        return new Status( Status.OK );
    }
    

Registering Extension Points

The extension point registration is built upon CommonJS features like modules and package.json. (For more information, see Using Digital script modules.) You register extension points statically by creating a package.json file, which you must place in the top-level directory of a cartridge. In the package.json file, set the hooks property to the path of a hooks.json configuration file. This path is relative to the directory containing the package.json file.

{
   ...
   "hooks": "./cartridge/scripts/hooks.json"
}

The hooks.json file contains an array with mappings from extension point names to script files. Reference the script files with a relative path. The paths are relative to the directory where the hooks.json file is located.

{
   "hooks": [
      {
        "name" : "dw.ocapi.shop.basket.billing_address.beforePUT",
        "script" : "./basket_hook_scripts.js"
      },
      ...
   ]
}

Register your cartridge to the appropriate site in Business Manager. To customize organization-level resources, such as libraries, register it to the Business Manager site.

Extension Point Scripts

An extension point (or hook) script is loaded as a CommonJS module. All hook functions must be exported. The exported name must match the name of the extension point function, without the package qualification. For example, the dw.ocapi.shop.basket.billing_address.beforePUT extension point is exported as beforePUT.

/*  basket_hook_scripts.js  */

importPackage( dw.order );
importPackage( dw.system );

exports.beforePUT = function(basket,doc)
{
    // verify address
    ...

    if( valid )
    {
        doc.companyName="Salesforce";
        return new Status(Status.OK);
    }

    return new Status(Status.ERROR);
}

exports.afterPUT = function(basket,doc)
{
   // calculate basket by calling the convenience hook, which returns a status object
   return dw.system.HookMgr.callHook( "dw.order.calculate", "calculate", basket );
}

exports.calculate = function(basket)
{
    // do calculation
    ...

    return new Status(Status.OK);
}

Hook Circuit Breaker

The Hook Circuit Breaker feature protects the system from excessive Hook script execution failures. For more information, see Hook Circuit Breaker.

Calculate Hook

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, which you can override at any time. The default logic of the following hooks implicitly calls 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 table shows how this hook supports customization:
Extension point Method detail
dw.order.calculate

calculate (basket: Basket ): Status

Calculates (or recalculates) the basket sent in the request.

The dw.order.calculate extension point calls this function.

Parameters:
basket - the basket document to be calculated (or recalculated)
Returns:
a non-null Status ends the hook execution

The following code snippet shows a sample call:

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

In this sample call, the parameters are:

  • "dw.order.calculate" - the extension point to call
  • "calculate" - the script function to call
  • basket - the basket to be calculated
Note: SiteGenesis uses the default implementation of the dw.order.calculate hook for basket calculation logic.
X OCAPI versions 15.x and 16.x will be retired on March 31, 2021. For dates and more information, see the OCAPI versioning and deprecation policy and this Knowledge Article.