JavaScript Code Examples

You can use the following JavaScript code examples in the code editors in API Creator. The code examples are drawn from the API samples (Demo, Sample, B2B Pavlov, and B2B Northwind), so you can study them in context.
lac52
You can use the following JavaScript code examples in the code editors in API Creator. The code examples are drawn from the API samples (
Demo
Sample
B2B Pavlov
, and 
B2B Northwind
), so you can study them in context.
In this article:
Insert Code Examples into a Code Editor
With your cursor in a code editor, for example, the custom endpoints code editor, click the 
Examples
 drop-down, click the insert icon (+) next to the code example that you want to insert into the code editor, and then click 
Save
.
General-use Patterns
The following examples are common patterns that you can use in your JavaScript code:
Iterate Over Arrays
You can iterate for any array using the 
Iterate Over Arrays
 code example.
Example:
var items = row.lineitems;
for (i in items) {
log.debug("Found a line item: " + items[i].name);
}
// Same thing but different approach
for each (item in row.lineitems) {
log.debug("Found a line item: " + item.name);
}
Catch Exceptions
You can have API Server handle exception conditions and errors that some calls might throw by having it catch and process. Surround your code, including calls to Java, with try/catch blocks. The following 
Catch Exceptions
 code is an example.
Example:
 
try {
// This will throw a NullPointerException
Java.type("java.lang.Long").parseLong(null);
}
catch(e) {
// The exception is caught here
log.debug("Got an exception: " + e);
}
You can also have API Server handle exception conditions and errors by invoking error handlers that modify the condition or error. For more information about how to create error event handlers, see Event Handlers.
For more information about other methods you can use to handle exception conditions and errors, see Error Handling.
Throw Exceptions
You can throw exceptions, for example, if your code detects an error condition and you cannot handle that error, using the 
Throw Exceptions
 code example. API Server catches the error and stops processing the request.
Example:
 
if (row.price < 0) {
throw "Impossible condition: product " + product.name + " has a negative price";
}
Invoke a Command Line
You can invoke a command from the operating system on which the server is running using the 
Invoke a Command Line
 code example. This example demonstrates how to execute a Python script, but you can issue any command that can you can run from the command line using this method.
This code example uses the 
Runtime
 Java class, which offers several ways of invoking a process. It also uses the 
IOUtils
 Apache Commons class.
For more information:
Example:
 
// Start an arbitrary process
var process = Java.type("java.lang.Runtime").getRuntime().exec("/usr/bin/python myScript.py " + row.myColumn);
// Optional: if you're interested in the output of the command. Note that the command will be running
// in a different process, therefore if you want to get the full output, you may have to wait until
// the process ends.
var output = Java.type("org.apache.commons.io.IOUtils").toString(process.inputStream, "UTF-8");
// Optional: if you're interested in the return value of the process. If the process has not yet finished,
// this will throw an exception.
if (process.exitValue() != 0) {
// Something probably went wrong -- the process did not return 0
}
More advanced use of Java
Use the 
More advanced use of Java
 code example to invoke a Java library, in this case, to call a REST point using the Apache Commons library.
The following example is a working example. You cannot invoke an API in API Creator using the PATCH verb.
Example:
 
// First get a JSON object
var settings = {
headers: {
"Authorization": "CALiveAPICreator q6EQFnyRtzxu0J5ANcoS:1"
}
};
var obj = SysUtility.restGet("http://localhost:8080/rest/default/myapi/v1/main:Album/1", null, settings);
obj = JSON.parse(obj)[0];
out.println("Got the object: " + JSON.stringify(obj));
// Modify the object
obj.Title += "Hi there ";
// Now invoke a PATCH using the Apache Commons library directly
var clientBuilder = Java.type("org.apache.http.impl.client.HttpClientBuilder").create();
var client = clientBuilder.build();
var HttpPatch = Java.type("org.apache.http.client.methods.HttpPatch");
var patchReq = new HttpPatch(obj["@metadata"].href);
patchReq.setHeader("Content-Type", "application/json");
patchReq.setHeader("Authorization", "CALiveAPICreator q6EQFnyRtzxu0J5ANcoS:1");
var payload = JSON.stringify(obj);
var StringEntity = Java.type("org.apache.http.entity.StringEntity");
var entity = new StringEntity(payload);
patchReq.setEntity(entity);
var response = client.execute(patchReq);
if (response.getStatusLine().getStatusCode() > 299) {
return {status: "Error - call failed"};
}
var InputStreamReader = Java.type("java.io.InputStreamReader");
var inStr = new InputStreamReader(response.getEntity().getContent());
var BufferedReader = Java.type("java.io.BufferedReader");
var rd = new BufferedReader(inStr);
var json = "";
var line = rd.readLine();
while (line != null) {
json += line;
line = rd.readLine();
}
return {result: JSON.parse(json)};
Sending an email
Depending on your email provider, you can use the 
Sending an email
 code example to send an email, for example:
var props = new java.util.Properties(); props.put("mail.smtp.host", "mail.acme.com"); props.put("mail.debug", "true"); var Session = Java.type("javax.mail.Session"); var mailSession = Session.getInstance(props, null); var MimeMessage = Java.type("javax.mail.internet.MimeMessage"); var msg = new MimeMessage(mailSession); var InternetAddress = Java.type("javax.mail.internet.InternetAddress"); msg.setFrom( new InternetAddress("[email protected]")); var Message = Java.type("javax.mail.Message"); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("[email protected]")); msg.setSentDate(new java.util.Date()); msg.setSubject(parameters.subject); msg.setText(parameters.text); var Transport = Java.type("javax.mail.Transport"); Transport.send(msg);
Many mail servers require authentication. If you need to send more than a few emails, you can use a service such as Amazon SMS or MailChimp, which have their own API.
With authentication, you can use the following code example:
var props = new java.util.Properties();
props.put("mail.smtp.host", "smtp.mail.yahoo.com");
props.put("mail.debug", "true");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");
var Authenticator = Java.type("javax.mail.Authenticator");
var auth = new Authenticator ({
getPasswordAuthentication: function() {
var PasswordAuthentication = Java.type("javax.mail.PasswordAuthentication");
return new PasswordAuthentication("[email protected]", "secret");
}
});
var Session = Java.type("javax.mail.Session");
var mailSession = Session.getInstance(props, auth);
var MimeMessage = Java.type("javax.mail.internet.MimeMessage");
var msg = new MimeMessage(mailSession);
var InternetAddress = Java.type("javax.mail.internet.InternetAddress");
msg.setFrom( new InternetAddress("[email protected]"));
var Message = Java.type("javax.mail.Message");
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("[email protected]"));
msg.setSentDate(new java.util.Date());
msg.setSubject("This is a test email");
msg.setText("Hi Jane,\n\nthis is a test email.\n\nSee you later,\n\n-- Joe\n");
var Transport = Java.type("javax.mail.Transport");
Transport.send(msg);
Validation Rules
For more information about how to create validation rules, see Validation Rule Type.
New/Old Values
The 
New/Old Values
 JavaScript code example is available from the validation rule code editor.
Example
 
The following code snippet shows the code for the 
New/Old Values
 JavaScript code example. This example verifies that employee salaries are not decreased:
return row.base_salary >= oldRow.base_salary;
This code example is available from the validation rule code editor.
Custom Endpoints
The following JavaScript code examples are available from the custom endpoints code editor:
For more information about how to run custom endpoints, see Manage Custom Endpoints.
Non-JSON endpoints
Your custom endpoint can return non-JSON responses, such as this HTML for browser execution, as shown in the following code snippet:
The 
B2B Northwind
 API sample defines the 
Menu
 custom endpoint with this code. This custom endpoint creates a simple HTML page that includes the content.
For more information about this API sample, see B2B API Sample.
var html = "<!DOCTYPE html>\n";
html += "<html>";
html += "<body>";
html += "<title>B2B Menu</title>";
html += "<p>Illustrates you can build simple html pages - no deploy";
html += "<p>.. See Custom Endpoints (disable Short Menus)";
html += "<h1>B2B Documentation</h1>";
html += "<a href='https://docops.ca.com/ca-live-api-creator/5-2/en/tutorials-and-samples/b2b-api-sample' target='_blank'>Docs</a>";
html += "<h1>B2B Execution</h1>";
html += "<a href='http://localhost:8080/DataExplorer/index.html#/?serverName=http:%2F%2Flocalhost:8080%2Frest%2Fdefault%2Fb2bderbynw%2Fv1%2F&forceLogin=true' target='_blank'>Run Data Explorer</a>";
html += "</body>";
html += "</html>";
responseHeaders.put('Content-Type', 'text/html');
return html;
This code example is available from the custom endpoint code editor.
Retrieve Request Payload
Your custom endpoint can access the payload for PUT/POST requests and use the 
request
 object's 
getInputStream()
 method to read the inputStream and get the request payload, as shown in the following code snippet:
var IOUtils = Java.type("org.apache.commons.io.IOUtils");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
var inputStream = request.getInputStream();
// get the payload
var result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
// add additional code to process payload
This code example is available from the custom endpoint code editor.
Logic Events
The following JavaScript code examples are available from the event rule code editor:
 For more information about how to create an event rule type, see Event Rule Types.
Allocation
In this example, when you add a Customer Payment, the business logic allocates a provider's 
Payment.amount
 to designated Purchase Orders 
recipient
. For each allocation, Payment Purchase order Allocation allocation objects (a provider/recipient junction) are created. 
Payment_order_allocations
 logic determines the exact amount that is allocated.
For more information about the 
allocateFromTo
 system method, including detailed information about this example, see The allocateFromTo System Method.
Example
 
The following code snippet shows the code for allocating a payment to outstanding orders by way of a rule:
if (logicContext.verb == "INSERT") {
SysLogic.allocateFromToUndisbursed(
logicContext,
SysLogic.findWhere(
row.paymentCustomer.ordersList,
"row.is_ready == true && row.amount_un_paid > 0",
"placed_date a"),
"payment_order_allocations",
"amount_un_disbursed");
}
This code example is available from the event rule code editor.
Auditing
This example creates a child 
purchaseorder_audit
 row if the purchaseorder's 
amount_total
 is changed. This is often called state transition logic. API Creator does the following:
  • Compares the old/new values of the 
    amount_total
     using the row/oldRow supplied variables.
    The row/oldRow variables are part the JavaScript object model that API Creator builds. For more information about the object model, see Row Objects.
  • Creates the 
    purchaseorder_audit
     row either by direct code or by 
    SysLogic.insertChildFrom
    .
    For more information about the 
    InsertIntoFrom
     system method for auditing rule type, see Rule Types.
Example
 
The following code snippet shows the code for the auditing JavaScript code example:
if (row.amount_total != oldRow.amount_total) {
var newPurchaseorder_audit = logicContext.createPersistentBean("purchaseorder_audit");
newPurchaseorder_audit.amount_total = oldRow.amount_total; // set resource attributes from old values
newPurchaseorder_audit.paid = oldRow.paid;
newPurchaseorder_audit.customer_name = oldRow.customer_name;
newPurchaseorder_audit.order_number = oldRow.order_number; // set the foreign key
logicContext.insert(newPurchaseorder_audit); // saves (fires logic)
}
// better: re-use alternative using System or your own Loadable Libraries:
// if (row.amount_total != oldRow.amount_total) {
// SysLogic.insertChildFrom("purchaseorder_audit", logicContext);
// }
This code example is available from the event rule code editor.
Event Sourcing (RPC-style APIs)
 
CA Live API Creator
 invokes table event handlers with the current/old table rows on POST, PUT, and DELETE operations.
Example
 
The following code snippet shows the code for the 
Event sourcing (RPC-style APIs)
 JavaScript code example:
B2B.copyAttributes(logicContext, row.EmployeeRaises_OwnedBy_Employees);
In this example, you can update (parent) employee salaries when a row is inserted into (child) EmployeeRaises:
  • The event for the 
    EmployeeRaises
     table is defined, inserts only.  
  • Like-named attributes are copied from the source row (EmployeeRaises, wrapped in 
    logicContext
    ) to the parent 
    Employee
     row by invoking the 
    B2B.copyAttributes
     shared library routine. The parent row is obtained through the parent accessor, part of the JavaScript object model that 
    CA Live API Creator
     creates.
This code example is available from the event rule code editor.
Posting APIs
This code example uses a resource as a transformation definition. In this example, the event rule uses the 
ShipperAPIDef
 resource to send the inserted or altered order to a supplier. The event rule code example:
  1. Obtains the shipper, if there is one.
  2. Invokes the 
    transformCurrentRow()
     method to transform the order into the required format, including related data, such as items in the order.
  3. Declares the 
    ShipperAPIDef
     resource, which defines the transformation. You can choose/alias attributes and include related data.
  4. Posts the transform by way of a system library by invoking the 
    SysUtility.restPost()
     method. 
Example
 
The following code snippet shows the code for the Posting APIs JavaScript code example:
var shipper = row.Shippers; // object model (row) provides accessors to related objects
if (shipper !== null && shipper.OrderChangeWebHook !== null) {
var msg = logicContext.transformCurrentRow("ShipperAPIDef"); // ShipperAPIDef resource: transformation
SysUtility.restPost(shipper.OrderChangeWebHook, {}, ConstantsLib.supplierAuth, msg); // find with Control-Space, or by clicking Examples
}
This code example is available from the event rule code editor.
For more information about the 
transformCurrentRow()
 method, see transformCurrentRow Method.
Sending Messages
In this example, you can publish an explicitly defined resource, created from a row, to a message queue:
  1.  
    CA Live API Creator
     checks a row state. 
  2.  
    CA Live API Creator
     transforms the order into the required format, including related data, such as items in an order, by invoking 
    logicContext
     object's 
    transformCurrentRow()
     method.
    You define the transformation by explicitly defining a resource in your API, for example 
    MyResourceName
    , where you can choose and alias attributes and include related data.
  3.  
    CA Live API Creator
     publishes a message to a topic in an MQTT or Kafka broker by invoking the 
    listenerUtil
     object's 
    publishMessage()
     method.
Example
 
The following code snippet shows the code for the Sending Messages code example:
// object model (row) provides accessors to related objects, available via code completion (control+space)
if (row.status == 'ready' && row.status !== oldRow.status) {
var msgContent = logicContext.transformCurrentRow("MyResourceName");
var result = SysUtility.publishMessage("ConnectionName", "TopicName", msgContent);
}
This code example is available from the event rule code editor.
Persist Payload
In this example, you can post a payload, for example, from an MQTT or Kafka broker containing multiple kinds of related rows, to the underlying table:
  1.  
    CA Live API Creator
     acquires the message content. 
  2.  
    CA Live API Creator
     transforms and decomposes the payload onto multiple underlying tables, by invoking 
    SysUtility
     object's 
    restPost()
     method.
    You define the transformation by explicitly defining a resource in your API, for example 
    MyResourceName
    , where you can match the message payload by choosing and aliasing attributes and by including related data.
Example
 
The following code snippet shows the code for the Persist Payload code example:
// object model (row) provides accessors to related objects, available via code completion (control+space)
var messageContent = row.msgContent; // the json/xml payload data
var resourceURL = req.localFullBaseURL + 'MyResourceName'; // mapping and transformation defined by Custom Resource
var parms = {};
var settings = { 'headers': {'Authorization' : 'MyAuthToken:1'} }; // e.g., define on Auth Tokens screen
if (messageContent.startsWith("<"))
settings.headers["Content-Type"] = "application/xml"; // omit this if strictly JSON
var postResponse = SysUtility.restPost(resourceURL, parms, settings, messageContent);
logicContext.logDebug(title + "Post Response: " + postResponse);
This code example is available from the event rule code editor.
Data Access
In this example, you can learn how to:
  • Retrieve a table row using 
    logicContext.getBeanByPrimaryKey()
     method.
  • Retrieve multiple rows from a table by passing in a SQL query into the 
    logicContext.getRowsByQuery()
     method.
  • Modify a column in a table using the 
    logicContext.update()
     method.
  • Insert a new row into a table using 
    logicContext.createPersistentBean()
     and 
    logicContext.insert()
     methods.
Example
The following code snippet shows the code for the Data Access code example:
var db = "Event Data Access Test: "; // various read/write examples, you can add this as a demo:customer event
logicContext.logDebug(db + "running"); // to test: alter credit_limit for Alpha and Sons, verify changed in Sample
if (row.name == "Alpha and Sons") {
// read a (single) row by primary key
var customer = logicContext.getBeanByPrimaryKey("demo:customer", "Argonauts");
logicContext.logDebug(db + "read: " + customer);
// read a set of rows (syntax is DB specific. Hint: use RESTlab + Logs to see sql for your database)
var sql = 'select * from "product" where "name" <> \'Drill\''; // good for Derby (where schema defined as lower case)
// var sql = 'select * from `product` where `name` <> \'Drill\''; // good for MySQL
var rows = logicContext.getRowsByQuery("demo:product", sql);
for (var i = 0; i < rows.length; i++) {
logicContext.logDebug(db + 'Found product:' + rows[i].name);
}
// alter the current row (no need to touch)
row.credit_limit += 1;
logicContext.update(row); // re-run rules
logicContext.logDebug(db + 'updated row: ' + row);
// alter a row (read above)
logicContext.touch(customer); // required, to set up optimistic locking
customer.credit_limit += 1;
logicContext.update(customer);
logicContext.logDebug(db + 'updated customer: ' + customer);
// insert a row
var newCustomer = logicContext.createPersistentBean("demo:customer");
newCustomer.name = 'My new customer';
newCustomer.credit_limit = 100;
logicContext.insert(newCustomer);
logicContext.logDebug(db + "inserted: " + newCustomer);
}
This code example is available from the event rule code editor.
RESTful Data Access
In this example, you can learn how to copy credit_limit changes for customer 
Alpha and Sons
 from the Demo API to the Sample API. 
Example
 
The following code snippet shows the code for the RESTful Data Access code example:
var db = "REST Access test: "; // to test: alter credit_limit for Alpha and Sons, verify changed in Sample
logicContext.logDebug(db + "running");
if (row.name == "Alpha and Sons" && row.credit_limit != oldRow.credit_limit) {
logicContext.logDebug(db + "Syncing credit_limit changes..");
var url = req.baseUrl;
url = url.replace("/demo","/sample"); // compute baseURL of target system
url = url + "v1/sample:customers"; // add version/ resource endPoint on target
var key = "'" + row.name + "'"; // search strings must be quoted
var params= {
sysfilter: "equal(name:" + key + ")"
}; // result API: http://localhost:8080/rest/default/sample/v1/sample:customers?sysfilter=equal(name:'Alpha and Sons')
var settings = {
headers: {
Authorization: "CALiveAPICreator AdminKey:1" //special Auth Token in this project to allow access
}
};
var response = SysUtility.restGet(url, params, settings);
var sampleRowResult = JSON.parse(response);
var sampleRow = sampleRowResult[0];
logicContext.logDebug(db + "got Sample Customer: " + JSON.stringify(sampleRow));
sampleRow.credit_limit = row.credit_limit;
response = SysUtility.restPut(url, params, settings, sampleRow);
logicContext.logDebug(db + "Put Response: " + response);
}
This code example is available from the event rule code editor.
RESTful Data Access with Structured Filter and Sort
Use this example to learn how to call RESTful endpoints with structured filters and sorts, using the Demo API.
Example
The following code snippet shows the code for calling REST endpoints with structured filters:
var url = "http://localhost:8080/rest/default/demo/v1/demo:customer"
params= {
// sysfilter: "equal(name:'" + "Argonauts" +
"')",
// sysfilter: "like_or(name:'A%',name:'B%)",
// sysfilter: "greater(balance: 2000)",
sysfilter: "like(name:'A%')",
// sysorder: "(name: desc)"
sysorder: "(name: asc)"
};
var settings = {
headers: {
Authorization: "CALiveAPICreator demo_full:1"
}
};
var response = SysUtility.restGet(url, params, settings);
This code example is available from the event rule code editor.
Formula Rules
The following JavaScript code examples are available from the formula rule code editor:
For more information about how to create formula rule types, see Formula Rule Type.
If/Else logic
Use this example to compute the amount of line item as price*quantity, conditionally applying a discount.
Example
 
The following code snippet shows the code for the If/Else logic JavaScript code example:
if (row.qty_ordered <= 6) { // discount (using conditional JavaScript logic) return row.product_price * row.qty_ordered; } else { return row.product_price * row.qty_ordered * 0.8; }
This code example is available from the formula rule code editor.
Dealing with dates
Use this example to compute the 
due_date
 from the 
placed_date
.
This example uses the 
moment.js
 system library for date handling. You must make this library available inside your API to use this example in JavaScript logic.
For more information about how to make this library available, see Logic Libraries.
Example
 
The following code snippet shows the different types of date values that are acceptable:
if (row.due_date === null) {
// specify use of moment() library;
return new Date(moment(row.placed_date).add('months', 1));
}
else {
return row.due_date;
}
/*
You can also manipulate dates as follows:
var due_date = row.getRawObject("due_date");
if (due_date === null) {
var SimpleDate = Java.type("com.kahuna.util.SimpleDate");
due_date = SimpleDate.valueOf("2016-12-31");
// due_date = new SimpleDate(2016,12,31);
// due_date = SimpleDate.fromJavaUtilDate(row.placed_date); //use existing placed_date
// due_date = new Date(row.placed_date);
// due_date = "2016-12-31";
}
*/
This code example is available from the formula rule code editor.
Dealing with times
Use this example to check to see if the current 
CurrentTime
 attribute is null and to calculate a default value.  
Example
 
The following code snippet shows the different types of time values that are acceptable:
var time = row.getRawObject("CurrentTime");
if (time === null) {
var SimpleTime = Java.type("com.kahuna.util.SimpleTime");
time = SimpleTime.valueOf("23:59:59");
// time = new Date();
// time = "23:59:59";
// time = "23:59:59.123456789012";
// time = new SimpleTime(23, 59, 59, 123456789012); // hour, minute, second, picos
// time = SimpleTime.fromJavaUtilDate(new Date());// time on server
}
return time;
This code example is available from the formula rule code editor.
Dealing with timestamps
Use this example to check to see if the current 
CurrentTimestamp
 attribute is null and to calculate a default value.  
Example
 
The following code snippet shows the code for the Dealing with timestamps JavaScript code example:
var sts = row.getRawObject("CurrentTimestamp");
if (sts === null) {
var SimpleTimestamp = Java.type("com.kahuna.util.SimpleTimestamp");
sts = SimpleTimestamp.valueOf("2016-12-31T23:59:59");
// sts = new Date();
// sts = "2016-12-31T23:59:59.123456789012";
// sts = new SimpleTimestamp(2016, 12, 31, 23, 59, 59, 123456789012); //year, month, day, hour, minute, second, picos
// sts = SimpleTimestamp.fromJavaUtilDate(new Date()); // time on server
}
return sts;
This code example is available from the formula rule code editor.
Dealing with timestamps with offset
Use this example to check to see if the current 
CurrentTimestamp (with GMT offset)
 attribute is null and to calculate a default value. 
Example
 
The following code snippet shows the code for the Dealing with timestamps with offset JavaScript code example:
var stso = row.getRawObject("CurrentTimestamp");
if (stso === null) {
var SimpleTimestampOffset = Java.type("com.kahuna.util.SimpleTimestampOffset");
stso = SimpleTimestampOffset.valueOf("2016-12-31T23:59:59-05:00"); // New York from GMT
// stso = new Date();
// stso = "2016-12-31T23:59:59+05:00";
// stso = "2016-12-31T23:59:59.123456789012GMT";
// stso = new SimpleTimestampOffset(2016, 12, 31, 23, 59, 59, 123456789012, false, 5, 0); // year, month, day, hour, minute, second, picos, offsetPositive, offsetHours, offsetMinutes
// stso = SimpleTimestampOffset.fromJavaUtilDate(new Date()); // time on server
}
return stso;
This code example is available from the formula rule code editor.
Functions
The following JavaScript code examples are available from the functions code editor:
For more information about how to create functions and define the JavaScript code in functions, see Manage Functions.
Resource-oriented functions
Use this example to create a function that is associated with an entity and a resource.
Example
 
The following code snippet shows the code for the Resource-oriented function JavaScript JavaScript code example:
var theRaise = parameters.percentRaise * (row.Salary/100);
row.Salary += theRaise; // runs logic, persists change row(s) to database...
return [ {"status": "Success"}, {"raise": theRaise} ];
/*
This works with the Employees Table:
http://localhost:8080/rest/default/b2bnwderby/v1/nw:Employees/1/giveRaise?percentRaise=10
It also works with the EmployeesWithRaises Custom Resource, even though the Salary field as aliased.
The 'row.Salary' reference above works because the system has already performed Resource/Object Mapping.
So, row is a *table* row. This enables you to re-use the function over many Resources.
http://localhost:8080/rest/default/b2bnwderby/v1/EmployeesWithRaises/1/giveRaise?percentRaise=10
*/
This code example is available from the functions code editor.
Top-level functions
Use this example to create a function that is not associated with a table.
Example
 
The following code snippet shows the code for the Top-level functions JavaScript code example:
// Trivial example: find greatest common divisor for two positive numbers
// with a URL like: http://localhost:8080/rest/default/demo/v1/gcd
//
var div = 2
var gcd = 1;
if (parameters.n1 < 2 || parameters.n2 < 2) {
return {
n1: parameters.n1,
n2: parameters.n2,
gcd: 1,
message: "One or both of your parameters were less than 2, so the result is 1"
};
}
if (parameters.n1 > 1000000000000 || parameters.n2 > 1000000000000) {
return {
n1: parameters.n1,
n2: parameters.n2,
gcd: null,
message: "One or both of your parameters were greater than 1,000,000,000,000, so the result is too expensive to compute"
};
}
while (parameters.n1 >= div && parameters.n2 >= div) {
if (parameters.n1%div === 0 && parameters.n2%div === 0) {
gcd = div;
}
div++;
}
return {
n1: parameters.n1,
n2: parameters.n2,
gcd: gcd
};
This code example is available from the functions code editor.
Publish to RabbitMQ broker
Use the 
Publish to RabbitMQ broker
 code example to create a function that can publish a message to a RabbitMQ broker.
For more information about RabbitMQ listeners, see RabbitMQ Listeners.
Example
 
The following code snippet shows the code for the 
Publish to RabbitMQ broker
 JavaScript code example:
// Configure publisher options to have the Exchange Routing Key.
var HashMap = Java.type("java.util.HashMap");
var headerMapObj = new HashMap();
headerMapObj.put("rabbitmq.ROUTING_KEY","lactestkey");
// Get message. This could also be retrieved via a query parameter to this function endpoint call.
var messageObject = {
dateObject : new Date(),
id : 1,
comment : "Test Message"
};
// Convert messageObject to JSON.
var messageAsJSON = JSON.stringify(messageObject);
// Publish and return the status.
return SysUtility.publishMessage("RabbitProducer", null,messageAsJSON, {headers: headerMapObj});
This code example is available from the functions code editor.
Publish to a JMS provider
Use this example to create a function that can publish a message to a JMS broker.
For more information about JMS listeners, see JMS Listeners.
Example
 
The following code snippet shows the code for the Publish to a JMS provider JavaScript code example:
// Get message. This could also be retrieved via a query parameter to this function endpoint call.
var messageObject = {
dateObject : new Date(),
id : 1,
comment : "Test Message"
};
// Convert messageObject to JSON.
var messageAsJSON = JSON.stringify(messageObject);
// Publish and return the status.
return SysUtility.publishMessage("JMSProducerConnection", null,messageAsJSON, null);
This code example is available from the functions code editor.
Request Events
The following JavaScript code examples are available from the request and response event code editor:
For more information about how to create request and response events, see Event Handlers.
Insert lookup and merge-insert actions
Use this example to insert metadata action tags that activate system services to:
  • Look up foreign keys.
  • Merge-Insert: Cause the request row to be updated, or inserted if they do not exist.
You must specify the resource property part of the defined key for the parent resource attributes that 
CA Live API Creator
 uses for the lookup/match.
This code example is available from the request events code editor.
Lookup
 
External systems typically cannot know internal keys such as part numbers, so the API must accept part names and look up the associated foreign key.
This example uses the 
insertActions.js
 & 
jsonpath-0.8.0.js
 JavaScript libraries from the B2B sample quick install. You must make this library available inside your API to use this example in JavaScript logic.
The request event that is defined in this example does the following:
  • Inserts action tags to activate lookup processing.
  • Defines an array of resource names, paths, and associated insert tags.
  • Invokes a shared library routine to insert actions.
  • API Server processes the transformed request.
    For more information about metadata action tags for parent lookup, see B2B API Sample.
Example
 
The following code snippet shows the code for the Insert lookup and merge-insert actions, to the PartnerOrder resource. The third action within this code snippet activates Merge-Insert processing for posts to the SupplierSelfService resource. This enables Suppliers (the source of data) to update or create their information.
var actions = [ {resource: "PartnerOrder", path: "$..Product", insertActions: "LOOKUP"}, {resource: "PartnerOrder", path: "Shipper", insertActions: "LOOKUP"}, {resource: "SupplierSelfService", path: "", insertActions: "MERGE_INSERT"} ]; json = insertActions.insertActions(req, json, actions); // API Server processes this... // log.debug("requestEvent json: " + json);
Merge Insert
 
The previous code activates Merge-Insert processing for posts to the SupplierSelfService resource. This enables Suppliers (the source of the data) to maintain their information by posting a request for their organization: 
  1. If their Supplier row does not exist, insert the row.
  2. If their Supplier row exists, update the row (merge).
For more information:
Reformat request
In this example, the API agreement that 
CA Live API Creator
 has with external systems or partners might designate a request format different from the standard formats 
CA Live API Creator
 supports. As illustrated in the B2B sample, in the 
B2B Pavlov
 API, you can define request events to transform the incoming request:
  1. Restrict the transformation to POST operations on the SalesReports resource.
  2. Alter the JSON.
    API Server processes the transformed request.
Example
 
The following code snippet shows the code for the Reformat request JavaScript code example:
if ("SalesReports" == req.resourceName && req.verb.toString() == 'POST') {
// log.debug('***SalesReports Req Event - json: ' + json);
var data = JSON.parse(json); // json from the request
if(Array.isArray(data) && data.length > 0) {
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;
delete eachItem.Quantity;
delete eachItem.SupplierName;
eachItem.CompanyName = theOrder.CompanyName;
log.debug("*********keep item: " + JSON.stringify(eachItem));
log.debug("from Order: " + JSON.stringify(theOrder));
keptItems[keptItemNum] = eachItem;
keptItemNum ++;
}
}
log.debug("Kept Items"); log.debug(keptItems);
json = JSON.stringify(keptItems); // Important: you must serialize the data back to a string if you want to change it
}
log.debug('***SalesReports Req Event - ALTERED json: ' + json);
}
This code example is available from the request events code editor.
Reformat response
In this example, the API agreement that 
CA Live API Creator
 has with external systems/partners might designate a response format different from the standard formats 
CA Live API Creator
 supports. As illustrated in the Sample API, you can define request events to transform the outgoing response:
  1. Restrict the transformation to POST operations on the 
    PartnerOrders
     resource.
  2. Alter the JSON.
    API Server returns the transformed response.
Example
 
The following code snippet shows the code for the Reformat response JavaScript code example:
var reqResourceName = req.resourceName;
if ("POST" == req.verb && "PartnerOrder" == reqResourceName) {
delete json.txsummary; // remove from response
delete json.rulesummary;
var reqJson = JSON.parse(req.json); // convert req's JSON string to JSON objects
var custName = reqJson.customer; // get the name from the request (e.g., 'Max Air')
var options = { filter: "\"name\" = '" + custName + "'" };
// so.. http://localhost:8080/rest/default/sample/v1/cust?filter="name"='Max Air'
var custAccount = SysUtility.getResourceAsString("cust", options); // get resource JSON
log.debug("***return account summary as response: " + custAccount);
json.accountSummary = JSON.parse(custAccount); // inject into response
}
This code example is available from the request events code editor.
Reformat error response
In this example, 
CA Live API Creator
 returns custom error responses. This example demonstrates how you can evaluate the 
json
 object in an error event handler and modify the error code and message. 
Example
 
The following code snippet shows the code for the Reformat error response JavaScript code example:
var reqResourceName = req.resourceName;
if ("POST" == req.verb && "PartnerOrder" == reqResourceName) {
var temp = json;//JSON response object
print("ERROR EVENT" + JSON.stringify(json));
log.debug("ERROR EVENT" + JSON.stringify(json));
json = {};
json.success=false;
json.payload={"req":JSON.parse(req.json)};
var errorJ={};
errorJ.code = temp.errorCode;
errorJ.message= temp.message;
json.error=errorJ;
}
This code example is available from the error events code editor.
Modify CORS Response
In this example, 
CA Live API Creator
 returns custom CORS responses based on the requested resource name.
This example demonstrates the following:
  • How to use HTTP OPTIONS events. 
  • How the 
    req
     object is used inside the event to fetch the URL of the requested resource.
  • The modification of CORS response headers based on a condition.
Example
 
The following code snippet shows the code for the Modify CORS Response JavaScript code example:
// Get the full URL of the resource.
var url = req.fullBaseURL;
var domain = url.replace("http://","").replace("https://","").split(/[/?#]/)[0];
// Allow Origin only from baseURL of the resource.
var corsResponseObject =
{ "Access-Control-Allow-Methods" : "GET,OPTIONS,POST,PUT",
"Access-Control-Allow-Origin" : "http://"+domain,
"Access-Control-Allow-Headers" : "authorization,content-type, accept",
"Access-Control-Max-Age" : 2400 ,
"HTTPStatusCode" : 200
};
if(req.resourceName === 'demo:PurchaseOrder') {
// Restrict access of demo:PurchaseOrder to calls from the same domain return corsResponseObject;
}
else{
// For the other resources, allow access from all origins.
corsResponseObject["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS";
corsResponseObject["Access-Control-Allow-Origin"] = "*";
return corsResponseObject;
}
This code example is available from the request events code editor.
Resource Events
The following JavaScript code examples are available for resource events:
Service calls to integrate external data
Use this example to call an outside REST service and connect to multiple servers of any type. Your JavaScript code is responsible for retrieving data and for formatting it into JSON. Use the 
containingRow
 context variable to access data from the containing resource. 
Use 
req.json
 if you POST to your JavaScript resource endpoint. This contains the payload that is passed by the client.
Example
 
The following code snippet shows the code for the Details Event JavaScript code example:
var url = req.baseUrl; log.debug(url); // this is the base URL for this server url = url.replace("/demo","/sample");// compute baseURL of target system url = url + "v1/orders"; // add version/ resource endPoint on target var key = containingRow.name; // containingRow is system supplied log.debug("..using key: " + key + ", and url: " + url); key = JSON.stringify(key, null, 0); var params= { sysfilter: "equal(customer_name:" + key + ")" }; //special Auth Token in this project to allow access from url (?auth=AdminKey:1) var settings = { headers: { Authorization: "CALiveAPICreator AdminKey:1" } }; //////////// Built in utility to make REST GET call var response = SysUtility.restGet(url, params, settings); return JSON.parse(response);
This code example is available from the code editor for JavaScript resources.
GET Event Lookup
Use this example to set a virtual attribute that you define in your tabled-based resources.
Example
 
The following code snippet shows the code for the GET Event JavaScript code example:
log.debug("The row object has been read from the data source");
var params = {
columns: [
'name'
],
usingValues: {
product_number:
tableRow
.product_id
}
};
var products = SysUtility.
findEntities
("demo:product", params);
if (null !== products && products.length > 0) {
virtuals.product_name
= products[0].name;
}
log.debug("The virtual attribute values: " +
virtuals
.toString());
row.foo = 'This will create a new attribute named foo - however, it will not appear in OpenAPI (Swagger)';
The 
product_name
 virtual attribute is set using a value that is retrieved from another endpoint using the 
SysUtility.findEntities()
 method. The 
tableRow
 variable contains the values from the data source. The 
virtuals
 variable holds the values for the virtual attributes.
 You can only change virtual attributes to values that matches the defined JSON type.
This code example is available from the resource GET event code editor.
PUT/POST Lookup
Use this example to look up and populate foreign keys in a PUT or POST call to your table-based resource.
Example
 
The following code snippet shows the code for the PUT/POST Lookup JavaScript code example. The 
product_id
 attribute, a foreign key, is set using the 
tableRow
 variable:
log.debug("Payload passed in Put or Post event " + row.toString());
var params = {
columns: [
'product_number'
],
usingValues: {
name: row.product_name
}
};
log.debug("Set the product_id using the found product_name");
var products = SysUtility.
findEntities
("demo:product", params);
if (null !== products && products.length > 0) {
tableRow
.product_id = products[0].product_number;
}
This code example is available from the resource PUT/POST event code editor.
User Libraries
User libraries are logic libraries contain JavaScript functions that you can reuse across APIs. You can access user libraries from your logic, for example, formulas, events, validations, and functions.
The following JavaScript code examples are available for user libraries:
For more information about user libraries, see Logic Libraries.
Save state between events
Use this example to create a function that can save data between table event handlers.
Example
 
The following code snippet shows the code for the 
Save state between events
 code example:
/* you can save state in logicContext.userProperties, including complex objects such as Maps to save (e.g., from event-1):
B2B.putPropertyMap(logicContext, "order.supplierHooks", supplier.CompanyName, supplier.URL);
to retrieve (e.g., from event-2):
var webHooks = req.getUserProperties().get("order.supplierHooks"); // userProperties to maintain state in transaction
*/
B2B.putPropertyMap = function putPropertyMap(logicContext, propertyName, key, value) {
var RestRequest = Java.type('com.kahuna.server.rest.RestRequest');
var req = RestRequest.getCurrentRestRequest();
logicContext.logDebug("*** B2B.putPropertyMap - propertyName: " + propertyName + ", key: " + key + ", value: " + value + ", on req: " + req);
var property = req.getUserProperties().get(propertyName); // userProperties to maintain state in transaction
if (property === null) {
var HashMap = Java.type('java.util.HashMap');
property = new HashMap();
}
property.put(key, value);
req.setUserProperty(propertyName, property);
};
This code example is available from the libraries code editor.
Custom Authentication Provider
Use this example to create a function that can save data between table event handlers.
Example
 
The following code snippet shows the code for the 
Custom Authentication Provider
 code example:
// Custom authentication provider, uploaded in B2B install script.
// Authenticates using RESTful service, configured to be employees table in Northwind-B2B.
// At its core, an Authorization Provider is a JavaScript function that returns an object (see end) containing these 4 functions:
// getConfigInfo: function () {...}, configure: function (values) {...}, getLoginInfo: function () {...}, authenticate:
out = java.lang.System.out;
function create() {
var result = {};
var configSetup = {
logonApiKey : '',
loginBaseURL : '',
loginGroupURL : '',
keyLifetimeMinutes : 60
};
// This function is called by API Creator when the user enters a value
// for the parameters specified by getConfigInfo and clicks Save.
// Returns configuration values which API Creator will save into Admin DB;
// these are exported in the json config file
result.configure = function configure(myConfig) {
configSetup.logonApiKey = myConfig.logonApiKey || 'demo_full'; // supply, or default
configSetup.loginBaseURL = myConfig.loginBaseURL || 'http://localhost:8080/rest/default/v1/...';
configSetup.loginGroupURL = myConfig.loginGroupURL || 'http://localhost:8080/rest/default/v1/...';
configSetup.keyLifetimeMinutes = myConfig.keyLifetimeMinutes || 60;
};
// Main crux of Auth Provider - called by API Server on post to @authenticate, to return list of Roles
// NOTE: the function configure must be called first - this will validate the user/pw
// The argument passed in will contain whatever values were provided to the @authentication service.
// If the caller is well-behaved, this should correspond to the parameters described by getLoginInfo,
// but you should not depend on that.
// This function must return an object containing just an error message if the authentication failed.
// If the authentication succeeded, then it must return an object with the following properties:
result.authenticate = function authenticate(payload) {
out.println("Authentication called...");
var roles = [];
var errorMsg = null;
var resetPasswordURL = null;
var forgotPasswordURL = null;
var myUserData = {};
var params = null;
var settings = {
headers : {
'Authorization' : 'CALiveAPICreator ' + configSetup.logonApiKey + ':1'
}
};
try {
if (payload.username == 'admin' || payload.username == 'demo') {
out.println("Authentication - default admin/demo/ user - good to go..");
// out.println("Lab test OK..."); // uncomment this for Readiness Lab
roles = ['Full access']; // || HARD CODED FOR DEMO (we even ignore the pwd)
errorMsg = null; // authorized successfully
}
else if (payload.username == 'pavlov' || payload.username == 'Pavlov') {
out.println("Authentication - Pavlov - role is Supplier, with Global ID===7");
roles = ['Supplier']; // Permission's Row Filter uses the following Global
myUserData = {ID: '7', AnotherParm: 'like this'}; // reference like this: "SupplierID" = @{ID}
errorMsg = null; // authorized successfully
}
else {
// GET this JSON request to determine if username and password is valid
// if so, return an array of role names (here just 'Full Access')
// and, to simplify typing in demos, will allow the default Password1
var pwd = payload.password;
if (payload.username == "Janet" && payload.password == "Password1") {
pwd = "Leverling";
}
var loginAttemptURL = configSetup.loginBaseURL
+ "?sysfilter=equal(FirstName:'"+ payload.username
+ "')&sysfilter=equal(LastName:'" + pwd
+ "')";
out.println("Authentication - finding [" + payload.username + "." + pwd + "]");
out.println("... via Rest URL: " + loginAttemptURL);
out.println("... using settings: " + JSON.stringify(settings));
var loginAttempt = SysUtility.restGet(loginAttemptURL, params, settings);
var groups = JSON.parse(loginAttempt);
// out.println(JSON.stringify(groups, null, 2));
if (groups.hasOwnProperty('errorMessage')) {
out.println("...errorMessage found in loginAttempt: " + loginAttempt);
errorMsg = groups.errorMessage;
}
else {
// change the field name below .name to the name of your
// roleName column
errorMsg = 'Username ' + payload.username + ' not found with last name as password';
for ( var row in groups) {
roles = ['Full access']; // || HARD CODED FOR DEMO
// roles.push(groups[row].Region);
// myUserData.push(groups[row].Region)
errorMsg = null; // if one role is found then we are good to return
}
}
if (errorMsg != null) {
out.println("...get failed to find this user, loginAttempt: " + loginAttempt);
}
}
}
catch (e) {
errorMsg = e.message;
}
var autResponse = {
errorMessage : errorMsg,
roleNames : roles,
userIdentifier : payload.username,
keyExpiration : new Date(+new Date()
+ (+configSetup.keyLifetimeMinutes) * 60 * 1000),
userData : myUserData,
lastLogin : {
datetime : null,
ipAddress : null
}
};
return autResponse;
};
// FUNCTION getAllGroups is used to map all available groups for existing application -
// unused in this example, provided for illustration purposes only...
result.getAllGroups = function getAllGroups() {
var roles = [];
var errorMsg = null;
var params = null;
var settings = {
headers : {
'Authorization' : 'CALiveAPICreator ' + configSetup.logonApiKey + ':1'
}
};
try {
var loginAttemptURL = configSetup.loginGroupURL; // no filter needed- get all roles?
var groupsResponse = SysUtility.restGet(loginAttemptURL, params, settings);
var groups = JSON.parse(groupsResponse);
if (groups.hasOwnProperty('errorMessage')) {
errorMsg = groups.errorMessage;
}
else {
// change the .name to refrelect the name of your roles returned
// in the JSON object
for ( var row in groups) {
roles.push(groups[row].name);
}
}
}
catch (e) {
errorMsg = e.message;
}
var autResponse = {
errorMessage : errorMsg,
roleNames : roles
};
return autResponse;
};
// FUNCTION getLoginInfo is used to create the login dialog - DO NOT CHANGE
// This function is called by API Server when a client needs to know what kind of information is required for authentication.
// Basically, this describes what the login dialog should look like (assuming the client is an interactive application).
result.getLoginInfo = function getLoginInfo() {
return {
fields : [
{
name : "username",
display : "Username",
description : "Enter your First Name",
type : "text",
length : 40,
helpURL : "http://liveapicreator.ca.com"
},
{
name : "password",
display : "Password",
description : "Enter your Last Name as Password",
type : "password",
length : 40,
helpURL : "http://liveapicreator.ca.com/"
} ],
links : [
]
};
};
result.getConfigInfo = function getConfigInfo() {
return {
current : {
"keyLifetimeMinutes" : configSetup.keyLifetimeMinutes,
"logonApiKey" : configSetup.logonApiKey,
"loginBaseURL" : configSetup.loginBaseURL,
"loginGroupURL" : configSetup.loginGroupURL
},
fields : [ {
name : "logonApiKey",
display : "logonApiKey",
type : "text",
length : 60,
helpURL : ""
}, {
name : "loginBaseURL",
display : "loginBaseURL",
type : "text",
length : 120,
helpURL : ""
}, {
name : "loginGroupURL",
display : "loginGroupURL",
type : "text",
length : 120,
helpURL : ""
}, {
name : "keyLifetimeMinutes",
display : "API Key Lifetime (Minutes)",
type : "number",
length : 8,
helpURL : "http://www.liveapicreator.ca.com"
} ],
links : []
};
};
// returns object containing the 4 functions that define a Custom Authentication Provider:
// getConfigInfo: function () {...}, configure: function (values) {...}, getLoginInfo: function () {...}, authenticate:
return result; // returns the 4 func
}
This code example is available from the libraries code editor.
Timers
Timers are pieces of JavaScript code that can get executed at a specific time, or regularly according to a schedule. The 
Make a REST call at regular intervals
 code example is available.
For more information about timers, see Creating Timers.
Make a REST call at regular intervals
The 
Calling a REST request
 code example to make a POST request to an endpoint and parse the response using the 
timerUtil
 object. 
CA Live API Creator
 logs the result in the timer logs. 
Example:
 
The following code snippet shows the code for this code example:
var payload = {
date: "George Washington",
title: "General"
};
var params = {
isPresident: true
};
// pass in the required auth token to POST
var settings = {"headers": {"Authorization" : "LetMeInPlease"}};
var json = timerUtil.restPost("https://api.acme.com/myAPI/myEndPoint", params, settings, payload);
var responseObject = JSON.parse(json);
log.debug("The response's foo attribute is: " + responseObject.foo);
// Log that timer was run
log.debug("My timer has executed!");
This code example is available from the code editor for timers.
Listeners
Listeners are pieces of JavaScript code that non-REST events can invoke when certain events occur, such as when the server starts up or when a listener receives a message on a given connection.
The following code examples are available from the code editor for listeners:
For more information about listeners, see Creating Listeners.
Registering with an external service
This example demonstrates how to register the 
CA Live API Creator
 server with an external registry, such as Consul. 
Example
 
The following code snippet shows the code for the 
Registering with an external service
 code example:
var json = listenerUtil.restPost(
'https://consul.rocks/v1/agent/members',
{},
{headers:
{"X-Consul-Token": "abcd1234"}
},
{name: listenerUtil.getHostName()}
);
This code example is available from the code editor for startup listeners.
Notifying an external service
This example demonstrates how to notify an external service, such as Consul, that the 
CA Live API Creator
 server is coming down.
Example
 
The following code snippet shows the code for the 
Notifying an external service
 code example:
var json = listenerUtil.restPost(
'https://consul.rocks/v1/agent/members',
{},
{headers:
{"X-Consul-Token": "abcd1234"}
},
{name: listenerUtil.getHostName()}
);
This code example is available from the code editor for shutdown listeners.
Update backend upon Kafka record reception
This example demonstrates how to log incoming messages to a table in your database. The database can be your own or it can be a managed database.
Example
 
The following code snippet shows the code for the 
Update backend upon Kafka record reception
 code example:
// Getting the string equivalent of the record message.
var messageContent = record.value();
// Create the payload
var messageAudit = {};
var date = new Date();
messageAudit.date = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
messageAudit.message = messageContent;
// Insert the payload into the audit table
var resourceURL = 'http://localhost:8080/APIServer/rest/default/demo_mysql/v1/demo:message_audit';
var parms = {};
var settings = { 'headers': {'Authorization' : 'CALiveAPICreator demo_full:1'}};
var postResponse = listenerUtil.restPost(resourceURL, parms, settings, messageAudit);
log.debug(postResponse);
log.debug('Logged '+messageAudit+' into message_audit table.');
// Listener code goes here or check out examples ( see top right dropdown menu )
log.debug("KAFKA Listener on topic: "+ record.topic() + " value: "+record.value());
This code example is available from the code editor for Kafka listeners.
Update backend upon Message reception
The 
Update backend upon Message reception
 code example demonstrates how to log incoming messages to a table in your database. The database can be your own or it can be a managed database.
Example
 
The following code snippet shows the code for this code example:
// Getting the string equivalent of the message.
var messageContent = message.toString();
// Create the payload
var messageAudit = {};
var date = new Date();
messageAudit.date = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
messageAudit.message = messageContent;
// Insert the payload into the audit table
var resourceURL = 'http://localhost:8080/APIServer/rest/default/demo_mysql/v1/demo:message_audit';
var parms = {};
var settings = { 'headers': {'Authorization' : 'CALiveAPICreator demo_full:1'}};
var postResponse = listenerUtil.restPost(resourceURL, parms, settings, messageAudit);
log.debug(postResponse);
log.debug('Logged '+messageAudit+' into message_audit table.');
This code example is available from the code editor for MQTT listeners.
Update backend upon JMS message reception
This example demonstrates how to log incoming messages to a table in your database. The database can be your own or it can be a managed database. 
Example
 
In the following code snippet, string equivalent of an incoming JMS Message is logged into a table:
// Getting the string equivalent of the record message.
var messageContent = payloadAsString;
// Create the payload
var messageAudit = {};
var date = new Date();
messageAudit.date = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
messageAudit.message = messageContent;
// Insert the payload into the audit table
var resourceURL = 'http://localhost:8080/APIServer/rest/default/demo_mysql/v1/demo:message_audit';
var parms = {};
var settings = { 'headers': {'Authorization' : 'CALiveAPICreator demo_full:1'}};
var postResponse = listenerUtil.restPost(resourceURL, parms, settings, messageAudit);
log.debug(postResponse);
log.debug('Logged '+messageAudit+' into message_audit table.');
This code example is available from the code editor for JMS listeners.
Update backend upon RabbitMQ message reception
This example demonstrates how to log incoming messages to a table in your database. The database can be your own or it can be a managed database. 
Example
 
In the following code snippet, a string equivalent of an incoming RabbitMQ Message is logged into a table:
// Getting the string equivalent of the record message.
var messageContent = payloadAsString;
// Create the payload
var messageAudit = {};
var date = new Date();
messageAudit.date = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
messageAudit.message = messageContent;
// Insert the payload into the audit table
var resourceURL = 'http://localhost:8080/APIServer/rest/default/demo_mysql/v1/demo:message_audit';
var parms = {};
var settings = { 'headers': {'Authorization' : 'CALiveAPICreator demo_full:1'}};
var postResponse = listenerUtil.restPost(resourceURL, parms, settings, messageAudit);
log.debug(postResponse);
log.debug('Logged ' + messageAudit + ' into message_audit table.');
This code example is available from the code editor for RabbitMQ listeners.
Authentication Provider Code Examples
Authentication providers are pieces of JavaScript code that authenticate API user login credentials (username/password) and return a set of roles.
The following code examples are available from the code editor for authentication providers that use the 
HTTP Auth Provider
 authentication method.
  •  
    Authenticate
     code
    • Simple Authenticate
    • Shared Secret Authenticate
  •  
    Get configuration options
     code
    • Simple Get Configuration Options
    • Shared Secret Get Configuration Options
  •  
    Configure
     code
    • Simple Configure
    • Shared Secret Configure
  •  
    Get login info
     code
    • Simple Get login info
For more information about how to define the code for an HTTP authentication provider, see Authenticate API Users using an HTTP Authentication Provider.
The following code example are available from the code editor for authentication providers that use the 
JavaScript Auth Provider
 authentication method:
JavaScript Authenticate
Create a custom JavaScript authentication provider–such as OAuth, Microsoft Azure Active Directory (AD), Lightweight Directory Access Protocol (LDAP)–that authenticates against a database table.
Example
 
The following code snippet shows the code for the 
JavaScript Authenticate
 code example:
out = java.lang.System.out;
function create() {
var result = {};
var configSetup = {
logonApiKey : '',
loginBaseURL : '',
loginGroupURL : '',
keyLifetimeMinutes : 60
};
// This function is called by API Creator when the user enters a value
// for the parameters specified by getConfigInfo and clicks Save.
// Returns configuration values which API Creator will save into Admin DB;
// these are exported in the json config file
result.configure = function configure(myConfig) {
configSetup.logonApiKey = myConfig.logonApiKey || 'demo_full'; // supply, or default
configSetup.loginBaseURL = myConfig.loginBaseURL || 'http://localhost:8080/rest/default/v1/...';
configSetup.keyLifetimeMinutes = myConfig.keyLifetimeMinutes || 60;
};
// Main crux of Auth Provider - called by API Server on post to @authenticate, to return list of Roles
// NOTE: the function configure must be called first - this will validate the user/pw
// The argument passed in will contain whatever values were provided to the @authentication service.
// If the caller is well-behaved, this should correspond to the parameters described by getLoginInfo,
// but you should not depend on that.
// This function must return an object containing just an error message if the authentication failed.
// If the authentication succeeded, then it must return an object with the following properties:
result.authenticate = function authenticate(payload) {
out.println("Authentication called...");
var roles = [];
var errorMsg = null;
var myUserData = [];
var params = null;
try {
if (payload.username == 'admin' || payload.username == 'demo') {
out.println("Authentication - default admin/demo/ user - good to go..");
roles.push('Full access'); // HARD CODED FOR DEMO -Some examples use this as their role name
roles.push('API Owner'); // HARD CODED FOR DEMO (we even ignore the pwd) for full access
errorMsg = null; // authorized successfully
myUserData.push("Free Form Data");
}
}
catch (e) {
errorMsg = e.message;
}
var autResponse = {
errorMessage : errorMsg,
roleNames : roles,
userIdentifier : payload.username,
keyExpiration : new Date(+new Date()
+ (+configSetup.keyLifetimeMinutes) * 60 * 1000),
userData : myUserData,
lastLogin : {
datetime : null,
ipAddress : null
}
};
return autResponse;
};
// FUNCTION getLoginInfo is used to create the login dialog - DO NOT CHANGE
// This function is called by API Server when a client needs to know what kind of information is required for authentication.
// Basically, this describes what the login dialog should look like (assuming the client is an interactive application).
result.getLoginInfo = function getLoginInfo() {
return {
fields : [
{
name : "username",
display : "Username",
description : "Enter your First Name",
type : "text",
length : 40,
helpURL : "http://liveapicreator.ca.com"
},
{
name : "password",
display : "Password",
description : "Enter your Last Name as Password",
type : "password",
length : 40,
helpURL : "http://liveapicreator.ca.com/"
} ],
links : [
]
};
};
//getConfigInfo is used to generate the Auth Provider User Interface to prompt for variables passed to the system at authentication time
result.getConfigInfo = function getConfigInfo() {
return {
current : {
"keyLifetimeMinutes" : configSetup.keyLifetimeMinutes,
"logonApiKey" : configSetup.logonApiKey,
"loginBaseURL" : configSetup.loginBaseURL
},
fields : [ {
name : "logonApiKey",
display : "logonApiKey",
type : "text",
length : 60,
helpURL : ""
}, {
name : "loginBaseURL",
display : "loginBaseURL",
type : "text",
length : 120,
helpURL : ""
}, {
name : "loginGroupURL",
display : "loginGroupURL",
type : "text",
length : 120,
helpURL : ""
}, {
name : "keyLifetimeMinutes",
display : "API Key Lifetime (Minutes)",
type : "number",
length : 8,
helpURL : "http://www.liveapicreator.ca.com"
} ],
links : []
};
};
// returns object containing the 4 functions that define a Custom Authentication Provider:
// getConfigInfo: function() {...}, configure: function(values) {...}, getLoginInfo: function() {...}, authenticate:
return result;
}
This code example is available from the code editor for JavaScript authentication providers.
Simple LDAP Authenticate
Create a custom LDAP JavaScript authentication provider that authenticates against a database table.
Example
 
The following code snippet shows the code for the 
Simple LDAP Authenticate
 code example:
// This is a simple LDAP authentication provider for CA Live API Creator.
// It connects to a public LDAP server (ldap.forumsys.com), which recognizes
// a few users: boyle, curie, einstein, euclid, euler, gauss, newton, pasteur, tesla.
// All users have the same password: "password" (without quotes).
// Each user belongs to a group: chemists, mathematicians, or scientists.
// Each user has an attribute named mail, and some users have an attribute named telephoneNumber.
//
// To adapt this to your specific LDAP environment, you will have to change the code to fit
// your schema, e.g. what attribures are relevant, how you figure out which roles a user has, etc...
//
// You don't have to change the parameters, they are only shown as an example.
// select this new auth provider for your project (API Properties -> Authentication Provider)
// You should now be able to log in (e.g. using Data Explorer) as e.g. einstein/password.
function SimpleLDAPAuthProvider () {
var result = {};
var configSetup = {};
// This gets called first to pass in the required LDAP configuration values
result.configure = function configure(myConfig) {
configSetup.serverName = myConfig.serverName || "ldap://ldap.forumsys.com";
configSetup.keyLifetimeMinutes = myConfig.keyLifetimeMinutes || 60;
};
// This gets called to validate the user payload against LDAP service
result.authenticate = function authenticate(payload) {
java.lang.System.out.println("Authenticating with LDAP: " + payload.username);
var authResponse = {
roleNames: [],
userIdentifier: payload.username,
keyLifetimeSeconds: configSetup.keyLifetimeMinutes,
userData: {},
// We hard-code userInfo here, but you can add information that will be returned
// to the authenticator in the response, along with the auth token.
userInfo: {typeOfPerson: 'Cool'},
// If you are writing an auth provider for use with the *admin* project,
// then you will need to include the accountIdent in the userInfo, e.g.:
// userInfo: {typeOfPerson: 'Cool', accountIdent: 1000},
// If you know when and from where this user last logged in, you can
// optionally return it here.
lastLogin : {
datetime: null,
ipAddress : null
}
};
// Set up the JNDI environment
var Hashtable = Java.type("java.util.Hashtable");
var env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
env.put("java.naming.provider.url", "ldap://ldap.forumsys.com");
var userCN = "uid=" + payload.username + ",dc=example,dc=com";
env.put("java.naming.security.authentication", "simple");
env.put("java.naming.security.principal", userCN);
env.put("java.naming.security.credentials", payload.password);
env.put("java.naming.referral", "follow");
var InitialDirContext = Java.type("javax.naming.directory.InitialDirContext");
try {
// First, can we connect? If not, then either the user is unknown,
// or the password is wrong, and this will throw an exception.
var ctx = null;
try {
ctx = new InitialDirContext(env);
}
catch (e) {
return {
errorMessage: "Unable to authenticate with LDAP server: " + e.getMessage()
}
}
// Next, we retrieve the mail and phone attributes of the user, if present
var attrs = ctx.getAttributes(userCN, ["mail", "telephoneNumber"]);
var attrsEnum = attrs.getAll();
while (attrsEnum.hasMore()) {
var attrib = attrsEnum.next();
authResponse.userData[attrib.getID()] = attrib.get().toString();
}
// If there are multi-valued attributes, this is how to retrieve them
// attrs = ctx.getAttributes(userCN, ["groups"]);
// attrsEnum = attrs.getAll();
// if (attrsEnum.hasMore()) {
// var mvAttr = attrsEnum.next();
// var attrEnum = mvAttr.getAll();
// while (attrEnum.hasMore()) {
// var groupName = attrEnum.next();
// // For example, we're only interested in groups starting with "LAC-"
// if (groupName.startsWith("LAC-")) {
// authResponse.roleNames.push(groupName.substring(4));
// }
// }
// }
// Look for all the groups that contain our user. This is highly dependent
// on your LDAP schema -- many schemas store the memberships in the users.
var SearchControls = Java.type("javax.naming.directory.SearchControls");
var ctls = new SearchControls();
ctls.setReturningAttributes(["ou"]);
var answer = ctx.search("dc=example,dc=com",
"(&(objectClass=groupOfUniqueNames)(uniqueMember=" + userCN + "))", ctls);
while (answer.hasMore()) {
var groupName = answer.next().getAttributes().get("ou").get();
if (groupName == "scientists") {
java.lang.System.out.println("User " + payload.username +
" is a scientist and therefore gets full access.");
authResponse.roleNames.push("API Owner");
authResponse.roleNames.push("Full access");
}
else if (groupName == "mathematicians") {
java.lang.System.out.println("User " + payload.username +
" is a mathematician and therefore gets read-only access.");
authResponse.roleNames.push("Read only");
}
else {
// Ignore other groups
java.lang.System.out.println("Ignoring group: " + groupName);
}
}
if ( ! authResponse.roleNames.length) {
java.lang.System.out.println("User " + payload.username + " gets no access");
return {
errorMessage: "User " + payload.username +
" is neither a mathematician nor a scientist: access denied."
}
}
}
catch (e) {
return {
errorMessage: e.getMessage()
}
}
return authResponse;
};
// getLoginInfo gets called to create the logon dialog - you can change this if your
// authentication method does not use username/password, or if you don't like the names,
// but of course you'll have to change the authenticate function correspondingly.
result.getLoginInfo = function getLoginInfo() {
return {
fields: [
{
name: "username",
display: "User name",
description: "Enter your Username, e.g. einstein",
type: "text",
length: 40,
helpURL: ""
},
{
name: "password",
display: "Password",
description: "Enter your password, e.g. password",
type: "password",
length: 40,
helpURL: ""
}
],
links : []
};
};
// This function is called to determine what parameters can be configured in this auth provider.
// The values are stored in the admin database when the user saves the auth provider.
result.getConfigInfo = function getConfigInfo() {
return {
current : {
"serverName": configSetup.serverName,
"keyLifetimeMinutes" : configSetup.keyLifetimeMinutes
},
fields : [
{
name: "serverName",
display: "LDAP Server Name",
type: "text",
length: 40,
helpURL: ""
},
{
name: "keyLifetimeMinutes",
display: "API Key Lifetime (Minutes)",
type: "number",
length: 8,
helpURL: ""
}
],
links: []
};
};
return result;
}
This code example is available from the code editor for JavaScript authentication providers.