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:
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. |
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.
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
Extension point | Method detail |
---|---|
dw.order.calculate |
calculate (basket: Basket ): Status Calculates (or recalculates) the basket sent in the request. The
|
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
dw.order.calculate
hook for basket calculation
logic.