Develop server-side extensions

In addition to providing REST APIs and webhooks for integrating with external systems, and widgets for extending your storefront, Commerce also includes support for developing server-side extensions written in JavaScript.

Server-side extensions (SSEs) are applications built using the Express web framework and executed in the Node.js runtime environment. These extensions implement custom REST endpoints. For example, you could create a custom shipping calculator whose path is /ccstorex/custom/v1/calculateShipping.

SSEs provide the ability to execute custom logic on the server. This capability allows you to:

  • Run critical code in a secure environment that cannot be easily modified by an end user.
  • Run integration code on Oracle CX Commerce servers in the Commerce PCI zone, making it easier to achieve PCI compliance with custom extensions.
  • Develop complex flows that integrate Commerce data and logic with external systems, and present a single endpoint to the storefront or to those systems.

SSEs perform and scale well. Note, however, that the server-side extension environment is not designed for large application development. It is intended for implementing integration code or small amounts of custom logic. An SSE application is limited to 1 GB of memory at runtime.

Access SSEs

Customer and partner developers do not have direct access to the Commerce Node.js servers. The storefront, admin, and agent server extension requests are routed to the Node.js servers, and the responses are sent back to the user. The custom server applications can be accessed using the following URL routes:

  • Storefront request route prefix: /ccstorex/custom/*
  • Admin request route prefix: /ccadminx/custom/*
  • Agent request route prefix: /ccagentx/custom/*
For example, if you develop a storefront endpoint with the route /v1/calculateShipping, it will be accessed at:
https://<storefront-hostname>:<storefront-port>/ccstorex/custom/v1/calculateShipping

Note that the /v1 portion is recommended for versioning but not required. This matches the versioning scheme used for standard Commerce endpoints.

For an admin or agent endpoint, the route prefix includes ccadminx or ccagentx, and the URL includes the hostname and port for the administration server. Admin and agent endpoints require authentication using bearer tokens or user credentials, as described in REST API authentication.

Create an extension

A shipping calculator SSE is an example of a Node.js application that implements a target for Commerce webhook requests. To make this application available in Commerce, you would export the Express subapplication object from the /app/index.js module. For example:

// Export the subapplication to be embedded in the server-side extension
var express = require('express');
var subApplication = express.Router();
module.exports = subApplication;

Extension packaging and structure

An extension consists of a single ZIP file that can be uploaded through the administration interface. The file should not be larger than 25 MB. The filename consists of the name of the application plus .zip. If an extension by the same name has already been uploaded, uploading this file will overwrite the existing extension.

Each extension needs to contain a JSON metadata file named package.json that provides information about the extension. For example:

{
   "name": "shippingCalculator",
   "version": "0.0.1",  
   "description": "SSE that calls an external shipping calculator service.",  
   "main": "/app/index.js",
   "author": "Fred Smith",  
   "dependencies" : { "config": "latest" },
   "devDependencies" : { "express" : "latest" },
   "authenticatedUrls": [],
   "publicUrls": [
      "/ccstorex/custom/v1/calculateShipping",
   ],
... 
}

The following describes key properties in the file:

  • main: Identifies the JavaScript file that is the entry point into the application. This is executed and loads the extension to be run. Required.
  • publicUrls: List all the routes for the extension that do not require authentication.
  • authenticatedUrls: Lists the routes that only logged-in users can access. Typically used for SSEs that implement admin or agent endpoints.
  • dependencies: Specifies the application's runtime dependencies. Ensure any modules you include here are also packaged with your application and uploaded to Commerce.
  • devDependencies: Specifies the application's development-only dependencies.

At least one route must be listed in either publicUrls or authenticatedUrls.

In addition, if your server-side extension needs to call out to any external domains, you must use the package.json file's whitelistUrls property to specify an array of these URLs. For example:
"whitelistUrls": [
   "https://www.example.com",
   "https://www.example2.com"
  ] 

The domains you specify are added to the list maintained by your Oracle CX Commerce environment. Calls to domains that are not on this list are blocked. Note that calls from SSEs must use HTTPS and be sent over port 443.

Development dependencies

The Oracle CX Commerce server-side extension framework includes a number of libraries that you can use in developing your application. Declare the ones you use as devDependencies:

  • Body-parser: Middleware that parses incoming request bodies.
  • Express: Node.js web application framework.
  • Jasmine: Development framework for testing JavaScript code.
  • Jshint: Tool that helps to detect errors and potential problems in JavaScript code.
  • Moment: Tool that parses, validates, manipulates, and displays dates and times in JavaScript.
  • Nconf: Simple key-value store with support for both local and remote storage.
  • Winston: Simple and universal logging library with support for multiple transports.

Supported MIME and file types

Server-side extensions support the following MIME types for inbound communication:

  • application/json
  • application/xml
  • text/xml
  • application/x-www-form-urlencoded

Template files, images, and other formats are not supported. You can use any MIME type for outbound communication.

An SSE's ZIP file should contain the following file types only:

  • .json
  • .js
  • .pem
  • .txt
  • .properties

SSL certificate files must in PEM format and stored in the top-level ssl/ folder of the extension. Each certificate must be in a separate file.

Outbound calls

The extension server runs behind a proxy, and all outbound calls from the extension server must include the proxy details directly or indirectly. The Commerce HTTPS module indirectly includes the proxy details, so you typically should not need to pass in the proxy details.

If, however, you are using any other HTTP client libraries (for example, node-fetch or Axios), check the corresponding library documentation to determine whether you need to provide the proxy details. If so, they can be accessed using the following:

const nconf = require ('nconf');
const proxyServer = nconf.get ("general:proxy-server");

Upload an extension

Before you upload a server-side extension to Commerce, be sure to clean out the node_modules folder. You should include only the modules that the application requires. Also, do not upload any of the Commerce modules listed as dependencies, such as Express, Winston, or Nconf. These modules, if included in your node_modules folder, may cause unpredictable behavior, because the Commerce SSE framework will use the local node_modules copy instead of the global copy.

To upload an extension to Commerce, you must first obtain an application key and use it to log into the Admin REST API. For example:

POST /ccadmin/v1/login  HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <application_key>

grant_type=client_credentials

Commerce returns a bearer token, which you supply with subsequent requests.

Now use the POST /ccadmin/v1/serverExtensions endpoint to upload the extension:

POST /ccadmin/v1/serverExtensions  HTTP/1.1
Content-Type: multipart/form-data
Authorization: Bearer <access_token>

filename: <extension_name>.zip
uploadType: extensions
force: true
fileUpload: <open_handle_to_extension_file>

Call SSE endpoints

You can use SSEs to implement custom endpoints for a variety of purposes. Depending on the logic you implement, the endpoint can be called by a Commerce component such as a widget or webhook, or by an external system. Note that widgets and webhooks should call these endpoints on the storefront server, not the administration server.

A common pattern is to implement an endpoint that is designed to receive a POST request from a Commerce webhook. The SSE then converts the POST data (if necessary) and sends it to an external system. When the endpoint receives a response from the external system, the SSE converts the response (if necessary) and passes it to the webhook, which sends its response to the storefront.

The external shipping calculator example described in this section can be implemented in this way. After you install this extension, you configure the Shipping Calculator webhook to call the /ccstorex/custom/v1/calculateShipping endpoint. See Configure webhooks for more information.

For additional information about developing server-side extensions, see the posts on Oracle Cloud Customer Connect.