Pipeline Events

You can do more processing and customization using pipeline events. Pipeline events are JavaScript entry points to perform user-defined actions.
API Server calls the following types of pipeline events for every request:
  • Request pipelines.
    API Server invokes these pipeline events
    after
    it receives the request but
    before
    it processes request/row mapping and reactive logic.
  • Response pipelines.
    API Server invokes these pipeline events
    before
    it sends the (successful) final result to the client.
  • Options events.
    API Server recognizes Cross-Origin Resource Sharing (CORS) OPTIONS requests and invokes these pipeline events only for these requests.
  • Error Pipelines.
    API Server invokes these pipeline events when the request encounters an error or exception condition and
    before
    it sends the response to the client.
In this article:
3
Create a Pipeline Event
There is no limit to the number of pipeline events that you can create.
You can create only one options event per API.
Follow these steps:
  1. With your API open, in the Create section, click
    Pipeline Events
    .
  2. If your API does not have existing pipeline events, the Welcome to Request and Response Pipelines page appears. If your API has existing pipeline events, they are listed on the Pipeline Events page.
  3. Complete
    one
    of the following steps:
    • If you have not defined any pipeline events, on the Welcome to Request and Response Pipelines page, click
      Create Event
      .
    • If you have at least one pipeline event defined, click
      Add
      .
  4. Complete the following fields on the page, and then save your changes:
    Event type
    The type of pipeline event.
    Options:
    requestDeprecated, responseDeprecated, options, errorDeprecated, requestPipeline, responsePipeline, and errorPipeline
    Default:
    requestPipeline
    Event name
    The name for your pipeline event.
    Layer7 Live API Creator
    invokes pipeline events in alphabetical order based on their name. To have
    Layer7 Live API Creator
    invoke the pipeline event in a specific order, append the pipeline event name with a number sequence.
    Code
    The operations for this pipeline event. The following is an example of a response pipeline:
    if (“SalesResports” == req.resourceName) {
    //log.debug(‘***SalesReports Req Event - json: ' + json);
    var data = JSON.parse(json); // json from the request
    var theOrder = data[0];
    var keptItemNum = 0;
    var keptItems = [];
    log.debug(“theOrder: " + JSON.stringify(theOrder));
    for ( var i = 0; i < theOrder.Order_DetailsList.length; i ++) {
    var eachItem = theOrder.Order_DetailsList(i);
    delete eachItem[“@metadata”];
    if (eachItem.SupplierName == “Pavlova, Ltd.”) {
    delete eachItem.OrderID;
    delete eachItem.ProductID;
    ...
    Insert a code example or use code completion. For more information about the code examples that are available from the code editor, see JavaScript Code Examples. For more information about code completion, see Code Completion
    Verbs
    The verb for this request pipeline.
    Options:
    GET, PUT, PATCH, POST, and DELETE
    Applies to all resources
    When selected, this event applies to all resource names. To apply the event to only particular resources, clear the checkbox and enter a comma-separated list of resource names. For example, v1/AllCustomers or demo:customers.
    Active
    Select to indicate that this pipeline event is active.
The pipeline event is created.
How API Server Invokes Pipeline Events
The following section describes how API Server invokes each pipeline event.
Request Pipelines
API Server invokes pipeline events using the following process:
  1. API Server performs initial authentication.
  2. API Server invokes the request pipeline for every transaction, with the following variables pre-defined:
    Variable Name
    Description
    payload
    The raw JSON string that the client sends, if any. Set only for POST and PUT requests. You can modify this string.
    req
    The
    req
    object. For more information about this object, see The req Object.
    log
    The logger for the current request.
    headers
    The headers sent as part of the HTTP request. Excludes authorization headers.
  3. API Server establishes a connection to the database.
  4. API Server parses the JSON payload.
For more information about how API Server processes update requests, including how rules integrate with request pipeline, see Logic Execution.
Request Pipeline Examples
The following code snippets show examples of the code for a request pipeline.
In this code example, API Server rejects all requests on
SecretData
if the request does not use HTTPS:
// Reject all requests on SecretData if they do not use HTTPS
if ("SecretData" == req.resourceName && !req.clientUsesHttps) {
log.error('SecretData was accessed over HTTP by ' + req.clientAddress);
throw "Use HTTPS to access this resource";
}
In this code example, API Server deletes data from request pipelines except the data that is included in the JSON payload:
// Remove extraneous data that the client sends but that is not needed.
if ( ! json) {
// Only requests with a JSON payload are needed.
return;
}
var data = JSON.parse(json);
if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) {
delete data[i].uselessData;
}
}
else {
delete data.uselessData;
}
// Important: Serialize the data back to a string if you want to change it
json = JSON.stringify(data);
Response Pipelines
You can add the following variables to the JavaScript for response pipeline:
Variable name
Description
result
The complete response object, which is sent back to the client after
Layer7 Live API Creator
has executed the response pipeline (if any). You can (carefully) change or replace this object.
The
result
object is different from pipeline events. This variable is not a string, but rather an object or an array of objects. For a GET, this variable is a single object or an array of objects depending on the details of the request. For PUT/POST/DELETE, this variable is a single object with
statusCode
,
txsummary
,
rulesummary
elements. This variable can also be an error result. The
JSON.stringify()
method must be able to stringify the JSON object.
req
The
req
object.
For more information about this object, see The req Object.
response
The
response
object.
log
The logger for the request.
SysUtility
The
SysUtility
object.
For more information about this object, see The SysUtility Object.
Response Pipeline Examples
The following code snippets show examples of the code for a response pipeline.
The Sample database illustrates preparing a partner-specific response by materializing a resource and returning it as the response message. In this code example, API Server defines resource attribute aliases to match partner expectations:
// Remove all @metadata sections from the response for a specific table/resource
// Note: This would make it difficult for the client to update the data, but this is only an example.
// This only deals with top-level resources. To remove all
// @metadata sections from a complex resource, use recursion.
// An attribute 'TheVerb' is added to each array object or the single object
// with the name of request verb - GET, PUT, POST, PATCH, DELETE
// get the name used for metadata (configurable by project).
// You CAN convert from the Java string value to a JavaScript string object here
var metadataName = "@metadata";
if (Array.isArray(json)) {
// If the response is an array of objects
for (var i = 0; i < json.length; i++) {
delete json[i][metadataName];
json[i].txsummary && delete json[i].txsummary[0][metadataName];
// You MUST convert to native JavaScript string
json[i].TheVerb = req.verb;
}
}
else {
// The response is a single object
delete json[metadataName];
json.txsummary && delete json.txsummary[0][metadataName];
json.TheVerb = req.verb;
}
For more information:
In this code example, API Server adds the top 30 (by
amount_total
)
purchaseorders
where the employee is the sales rep by augmenting each employee in a GET of multiple employees:
// for a GET to an employee, add any PURCHASEORDERS where the employee is a sales rep
if ("GET" == req.verb && "demo:employee" == req.resourceName) {
var ordersAsSalesRep = [];
for (var i = 0; i < json.length; i++ ) {
// want purchase orders for this employee as sales rep
// top thirty purchase orders by amount_total
var detail = {
filter: '"salesrep_id" = ' + json[i].employee_id ,
order: '"amount_total" desc',
pagesize: 10,
offset: 0
};
if(json[i].employee_id) {
ordersAsSalesRep = SysUtility.getResource("PurchaseOrders", detail);
json[i].ordersAsSalesRep = ordersAsSalesRep;
}
}
}
In this code example, API Server includes the results of a resource GET by amending the transaction summary:
// for a PUT (perhaps to update the name) of one or more employees
// add the picture into the result
if ("PUT" == req.verb && "demo:employee" == req.resourceName) {
var txsummary = json.txsummary;
for (var i = 0, len = txsummary.length; i < len; i += 1) {
var meta = txsummary[i]["@metadata"];
if ("UPDATE" == meta.verb && "demo:employee" == meta.resource) {
var detail = { filter: '"employee_id" = ' + txsummary[i].employee_id };
var picInfo = SysUtility.getResource("the_employee_picture", detail);
if (picInfo && picInfo.length > 0) {
txsummary[i].the_picture = picInfo[0].picture;
}
}
}
}
Combine these examples and delete the typical transaction summary, redirecting it to be the result of the
SysUtility.getResource()
method.
For more information about transaction summaries, see Transaction Summary.
Options Events
Protect your data from unauthorized access by creating an options event for your API. You can get complete control over the response to CORS OPTIONS preflight requests with HTTP Options event.
For more information:
Options Event Example
The following code snippet shows an example of the code for an options event. This code instructs the client web browser that this API expects calls only from the specified URLs.
Layer7 Live API Creator
invokes the pipeline event only if the request includes an
Access-Control-Request-Method
header or an
Access-Control-Request-Headers
header:
return {
"Access-Control-Allow-Methods" : "GET,PUT,POST,DELETE",
"Access-Control-Allow-Origin" : "https://internal.acme.com,https://safe.acme.com",
"Access-Control-Allow-Headers" : "authorization,content-type,accept,x-requested-with,X-CALiveAPICreator-ResponseFormat",
"Access-Control-Max-Age" : 2400 ,
"HTTPStatusCode" : 200
};
Error Pipelines
You can have API Server intercept error conditions using error pipelines. You can change the error response that API Server sends to a response that the client of your API expects. In the error pipeline, you define the code that handles the error by modifying the error response.
For more information about how to have API Server catch and process them using standard JavaScript try/catch blocks, see JavaScript Code Examples.
For example, API Server sends the following error:
{
"statusCode": 500,
"errorCode": 50029,
"errorMessage": "Logic Execution failure: entity mssql:Deal, rule Deal, line 59/13, reason Only one Primary Broker allowed in RU3115 at line number 59 at column number 13"
}
API Server modifies the error and sends the following error response instead:
{
"statusCode": 500,
"errorCode": 999,
"errorMessage": "Only one Primary Broker allowed"
}
Error Pipeline Example
The following code snippet shows an example of the code for an error pipeline. This code example modifies the error response in API Server to a custom error response for your client:
var temp = json;//JSON response object json = { success : false, payload:{"req":JSON.parse(req.json)}, error: { code: temp.errorCode, statusCode: temp.statusCode, errorMessage: temp.errorMessage, message: temp.message } };
Advanced Usage
The following sections illustrate advanced usage of pipeline events.
Modify the JSON Request
You can look up the IDs of parent records when the JSON contains a key by inserting metadata action tags.
The
Insert_Lookup_Merge
request pipeline in the Business to Business (B2B) API sample illustrates this familiar pattern.
For more information about the B2B API sample, see B2B API Sample.
Modify the JSON Response
You have full control over the result. The following is an example:
  1. Define a new
    MyResource
    JavaScript resource, for example:
    return { Happy: ['New', 'Year']};
    For more information about how to define a JavaScript resource, see Define JavaScript Resource Types.
  2. In the REST Lab, view the result by performing a GET request, which is a different formatting of the previous JSON, by completing the following steps:
    1. Ensure that you are functioning by defining a simple response pipeline that includes the following code:
      // MUST be an object or an array, if not, it is coerced into one (and probably NOT what you want)
      if ('GET' == req.verb && 'MyResource' == req.resourceName) {
      json = ["I got what I expected"];
      }
      else {
      // this is returned on ALL other requests, make sure you delete this !!!
      json = ["Not what I wanted"];
      }
    2. Change to a more specific pipeline event without the else condition:
      // Note double equals, as you are comparing JavaScript strings with java.lang.String objects
      if ('GET' == req.verb && 'MyResource' == req.resourceName) {
      json = SysUtility.getResource('demo:customer');
      }
The pipeline event takes a value from the request and modifies the JSON response from the
demo:customer
resource.
Access Request Headers
Pipeline events have full access to the
headers
in the incoming request. Pipeline events have access to the
headers
object, for example:
//header names are usually lowercase
var contentType = headers["content-type"];
Modify the Response
Response pipelines can modify the outgoing response in multiple ways. The
response
variable is an instance of the
javax.ws.rs.core.Response.ResponseBuilder
Java class.
For more information about the
Response.ResponseBuilder
Java class, see the Oracle documentation.
In the response pipeline, you can modify the response by adding headers, adding cookies, and setting the response code, for example:
var NewCookie = Java.type("javax.ws.rs.core.NewCookie");
var cookie = new NewCookie("MyCookie", "My cookie value");
response.cookie(cookie);
response.header("X-my-special-header", "My header value");
response.status(299);