Service Level Transforms

Service level transforms are typically applied to a backend so that they can be inherited by the backend's service connections and by the service connection's endpoints. However, if you need to differentiate between the REST resources or between the endpoints (GET vs POST) of a system, for the service connection or its endpoints, you can choose a different .js transforms file or create a new one.

Within the hierarchy of service level transforms, an endpoint is first checked for a transform file, then the service connection, then the child backend (if there is one), and lastly, the backend. The first transform file that is found is used; any at the upper levels are ignored.

To see a backend, service connection, or endpoint's provided transform functions, navigate to its Overview tab, then click the Go to File link in the Transforms section. To create new transform functions, click the Source drop-down list and select Create.
Description of jsac-service-connection-transforms-file.png follows
Description of the illustration jsac-service-connection-transforms-file.png

Example of Creating Service Level Transforms

These steps show how to create a backend for service connections and how to create the file with the template transform functions for your new backend and its service connection endpoints:

  1. Open the Services panel, select the Backends tab, click the Add (+) icon and select Backend:

  2. In the Create Backend window, select Custom to create a custom backend.
  3. Provide a name for your custom backend, and optionally, enter its description.
  4. Enter the instance URL and any other required details. Later, when creating a service connection for the backend, this URL is used as the base for defining the endpoint. Click Create to create the backend.

  5. You can now create the file with the template transform functions for your new backend. On the Overview tab, in the Transforms section, click the Source field’s down-arrow and select Create:

  6. Provide the file name for the transforms file:

  7. For the Base transform dropdown, select the file to supply the base code for all of your transform functions. For ADF REST APIs, this file is always chosen for you.
  8. In the Override functions select the function(s) you want to add to the transforms file and click OK. Functions that you don't select won't be added to the transforms file.
  9. To open the transforms file, click Go to File under the Source field:

  10. Override the relevant transform functions as required. The provided built-in transform functions are: sort, filter, paginate, select, query (commonly used with GET collection endpoints), body (commonly used with POST and PATCH endpoints), and fetchByKeys.

    The transformsContext input parameter is a context object that is passed to every transform function by the associated SDP, so that you can retrieve and store contextual information for the current REST call. SDP variables have a transformsContext property that is passed to the transform functions. For more about an SDP's transformsContext property, see Oracle Visual Builder Page Model Reference - transformsContext SDP Property.



    Here's an example for the body(result) transform function, which adds text to all of the mass and height fields:

    
            body(result) {
                let tr = {};
                if (result.body) {
                    tr = result.body.results;
                    for (let i = 0; i < tr.length; i++) {
                      tr[i].mass = tr[i].mass + " kilos (kg)";
                      tr[i].height = tr[i].height + " cm";
                    }
                }
               // return tr;
            }

    The created transforms file is inherited by its related service connections, which are created by using the + Service Connection button on the Overview tab. To view the related service connections, click the Load related service connections link:
    Description of jsac-backend-related-services.jpg follows
    Description of the illustration jsac-backend-related-services.jpg

    For details about creating a service connection from an endpoint, including how to get an example of the body of the response, see Create a Service Connection from an Endpoint.

  11. To add a related service connection for your backend, click the + Service Connection button:

  12. Complete the URL for the service connection endpoint and provide the required details.
  13. To create a transform file for the endpoint, click the Source field’s down-arrow and select Create:

  14. To open the transforms file, click Go to File under the Source field.

Examples for Endpoints that Are Not from Oracle Cloud Applications

Here are examples of request and response transform functions for endpoints that aren't from Oracle Cloud Applications:
Request
A request transform function is called right before a request is made to the server/endpoint. It provides a chance for page authors to transform the options (filter, paginate, sort, and so on) and build the final request configuration. Here are some samples of how to write filter, paginate, and sort transform functions:
filter
/**
 * Filter Transform Function Implementation
 * @param configuration
 * @param options the JSON payload that defines the filterCriterion
 * @param context an object to store/retrieve any contextual information for the 
 *  current request lifecycle
 * @returns {object} configuration object. the url looks like ?filter=foo eq 'bar'
 */
 
PageModule.prototype.filter = function (configuration, options, context) {
  const c = configuration;
  const filterCriterion = options;
 
  function jetFilterOpToScim(fop) {
    switch (fop) {
      case '$eq':
        return 'eq';
      case '$ne':
        return 'ne';
      case '$co':
        return 'co';
      default:
        console.warn('unable to interpret the op ' + fop);
        return null;
    }
  }
 
  function isEmpty(val) {
    return (val === undefined || val === null || val === '');
  }
 
  if (typeof filterCriterion === 'object' && Object.keys(filterCriterion).length > 0) {
    if (filterCriterion.op && filterCriterion.attribute && 
          !isEmpty(filterCriterion.value)) {
      const atomicExpr = {};
      atomicExpr.op = jetFilterOpToScim(filterCriterion.op);
      atomicExpr.attribute = filterCriterion.attribute;
      atomicExpr.value = filterCriterion.value;
 
      if (atomicExpr.op && atomicExpr.attribute) {
        c.url = URI(c.url).addQuery({
          filter: `${atomicExpr.attribute} ${atomicExpr.op} ${atomicExpr.value}`,
        }).toString();
      }
    }
  }
 
  return c;
};
paginate
// paginate Transform Function
// Transform function appends limit and offset parameters to the URL
PageModule.prototype.paginate = function (configuration, options, context) { 
  const c = configuration;
  let newUrl = c.url;
  newUrl = `${newUrl}&limit=${options.size}&offset=${options.offset}`;
  c.url = newUrl;
  return c;
};
sort
/**
 * Sort Transform Function Implementation
 * @param configuration
 * @param options the JSON payload that defines the sortCriteria
 * @param context an object to store/retrieve any contextual information for the
 *  current request lifecycle.
 * @returns {object} configuration object. the url looks like ?orderBy=foo:asc
 */
PageModule.prototype.sort = function (configuration, options, context) {
  const c = configuration;
 
  if (options && Array.isArray(options) && options.length > 0) { 
    const firstItem = options[0]; 
    if (firstItem.name) { 
      const dir = firstItem.direction === 'descending' ? 'desc' : 'asc' 
      let newUrl = c.url; 
      newUrl = `${newUrl}&orderBy=${firstItem.attribute}:${dir}`; 
      c.url = newUrl; 
    } 
  } 
  return c; 
};
Response
A response transform function is called right after a request returns successfully. Here is a sample of how to write a paginate transform function:
// paginate() Response Transform Function
PageModule.prototype.paginateResponse = function (result, context) {
  const ps = {}; const tr = {};
 
  if (result.body) {
    const rb = result.body;
    if (rb.totalCount) {
      tr.totalSize = rb.totalCount;
    }
    if (rb.totalCount > 0) {
      tr.hasMore = !!rb.hasMore;
    } else {
      tr.hasMore = false;
    }
  }
  return tr;
};