Transforms - vbPrepare Request Transform

In order to fetch the data required by the application, clients are expected to use the VB RestHelper directly or, for example, via a RestAction or ServiceDataProvider. Regardless of the invocation mechanism, there are two main pieces of information that are usually provided for the request to happen: the identifier of the endpoint and, if relevant, the values of the endpoint "parameters" (such as server variables, path parameters, query parameters, and header parameters).

The vbPrepare request transform provides a hook that clients can use to programmatically modify the parameters, which can effectively change the URL of of the request issued by Visual Builder.

Signature

The vbPrepare transform can be declared as follows:

Request.prototype.vbPrepare = function(configuration, options, transformsContext) {
  // Clients can manipulate the parameters of the fetch via the 'options.parameters' object.
}

This transform is invoked before any other transform. Its arguments are also slightly different from the other transforms:

  • The configuration parameter provides the information about the endpoint being fetched, including the endpoint identifier, the OpenAPI path for the endpoint, and the server details (including URL templates and server variables).
  • The options parameter has a property parameters that exposes the object holding the parameters passed to the RestHelper. The value of parameters is a "live" object: in other words, changing the properties of options.parameters actually modifies the values used by the RestHelper.
  • The transformsContext is an object that is set at the RestHelper, which is then passed to all transforms.

vbPrepare Request Transform Examples

The examples below illustrate the arguments passed to the vbPrepare transform, as well as the effect its code has on the fetch performed by the RestHelper.

The 'store' service

The examples below use a service store, defined as follows:

  • The service is located on an extension extA, and is exposed to extensions that depend on extA.
  • The server of the service refers to the backend storeapi, and has a server variable storeId:
    "servers": [
      {
        "url": "vb-catalog://backends/extA:storeapi/{storeId}",
        "variables": {
          "storeId": {
            "default": "001"
          }
        }
      }
    ],
  • The backend storeapi is defined in the catalog.json artifact of extA, and also has a server variable:
    "backends" {
      "storeapi": {
        "extensionAccess": true,
        "transforms": {
          "path": "./storeapi.js"
        },
        "servers": [{
          "url": "https://www.mystore.com/{version}",
          "variables": {
            "version": {
              "default": "1.0"
            }
          }
        }]
      }
    }
  • The service has an operation listProduct with both a "path" and a "query" parameter:
    "/products/{productId}": {
      "get": {
        "operationId": "listProduct",
        "description": "List a product",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "description": "The ID of product.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "manufactureModel",
            "in": "query",
            "description": "Whether or not to use the manufacture's model.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          ...
        }
      }
    }

Transform Script

As indicated above, the transform script storeapi.js is provided by the storeapi backend, so that's the artifact that must contain the vbPrepare transform method.

If the service store itself had a transform script, the method for vbPrepare should be declared there.

Example 1-84 RestAction

Assume that the following RestAction is defined in an action chain.

"getProduct": {
  "module": "vb/action/builtin/restAction",
  "parameters": {
    "endpoint": "extA:store/listProduct",
    "uriParams": {
      "productId": "[[ $chain.variables.productId ]]"
    }
  },

The getProduct action provides only the value for the productId path parameter, which is required. The data fetch fails if the path is not specified.

The vbPrepare transform could be implemented in storeapi.js like this (this example uses the traditional, "function-prototype" design for transforms):

define([], function () {
  var Request = function () {};

  Request.prototype.vbPrepare = function(configuration, options) {
    /*
     * configuration = {
     *   endpointId: 'extA:store/listProduct',
     *   endpointPath: '/products/{productId}',
     *   serverUrlTemplates: [
     *     {
     *       // The url of the server of the store service.
     *       template: 'vb-catalog://backends/extA:storeapi/{storeId}',
     *
     *       // The value that VB would use for the 'storeId' server variable,
     *       // which in this case is the default value provided by the
     *       // OpenAPI definition.
     *       variables: {
     *         storeId: '001',
     *       },
     *     },
     *     {
     *       // The url of the server of the storeapi backend.
     *       template: 'https://www.mystore.com/{version}',
     *
     *       // The value that VB would use for the 'version' server variable,
     *       // which in this case is the default value provided by the
     *       // OpenAPI definition.
     *       variables: {
     *         version: '1.0',
     *       },
     *     },
     *   ],
     * }
     */

    /*
     * options = {
     *   // The resolved uriParams specified by the RestAction.
     *   parameters: {
     *     productId: 'tv001',
     *   },
     * }
     */

     // Changing both the 'productId' path parameter and the 'version' server variable.
     options.parameters.productId = 'notebook003';
     options.parameters['server:version'] = '2.1';

     // Adding a query parameter that is not specified in the OpenAPI definition.
     options.parameters.internalSKU = true;
  };

  var Response = function() {};

  return {
    request: Request,
    response: Response
  };
});

With the transform above, the request URL that is fetched is https://www.mystore.com/2.1/001/products/notebook003?internalSKU=true.

Example 1-85 RestHelper

Assume that the following code is defined in a script located in extension extB that depends on extA.

const restHelper = RestHelper.get('extA:store/listProduct', { extensionId: 'extB' });

restHelper.parameters({
  'server:storeId': 'To-001',
  manufactureModel: true,
  productId: 'tv001',
});

restHelper.transformsContext({
  myValue: 123,
});

return restHelper.fetch;

Also, assume that the web application defines the following value on the index.html artifact:

<script type="text/javascript">
  window.vbInitParams = {
    'services.catalog.common.version': 'untested',
  };
</script>

The vbPrepare transform could be implemented in storeapi.js like this (this examples uses an alternative, simpler design for transforms):

'use strict';

define([], () => ({
  request: {
    vbPrepare: (configuration, options, transformsContext) => {
      /*
       * configuration = {
       *   endpointId: 'extA:store/listProduct',
       *   endpointPath: '/products/{productId}',
       *   serverUrlTemplates: [
       *     {
       *       // The url of the server of the store service.
       *       template: 'vb-catalog://backends/extA:storeapi/{storeId}',
       *
       *       // The value that VB would use for the 'storeId' server variable,
       *       // which in this case is provided via the 'RestHelper.parameter'
       *       variables: {
       *         storeId: 'To-001',
       *       }
       *     },
       *     {
       *       // The url of the server of the storeapi backend.
       *       template: 'https://www.mystore.com/{version}',
       *
       *       // The value that VB would use for the 'version' server variable,
       *       // which in this case is provided via the 'vbInitParams' from index.html.
       *       variables: {
       *         version: 'untested',
       *       }
       *     },
       *   ],
       * }
       */

      /*
       * options = {
       *   // The parameters set via 'RestHelper.parameters'.
       *   parameters: {
       *     'server:storeId': 'To-001',
       *      manufactureModel: true,
       *      productId: 'tv001',
       *   },
       * }
       */

      /*
       * // The value set via 'RestHelper.transformsContext'
       * transformsContext = {
       *   myValue: 123,
       * }
       */

      // Not setting the 'manufactureModel' query parameter to use the server's
      // default value.
      delete options.parameters.manufactureModel;
    },
  },
}));

With the transform above, the request URL that is fetched is https://www.mystore.com/untested/To-001/products/tv001.