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.
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 pipelines that modify the condition or error. For more information about how to create error pipelines, see Pipeline Events.
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("jd[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)
Layer7 Live API Creator
invokes table pipeline events 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
    Layer7 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. Layer7 Live API Creator
    checks a row state.
  2. Layer7 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. Layer7 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. Layer7 Live API Creator
    acquires the message content.
  2. Layer7 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 Pipelines
The following JavaScript code examples are available from the request and response pipeline code editor:
For more information about how to create request and response pipelines, see Pipeline Events.
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
Layer7 Live API Creator
uses for the lookup/match.
This code example is available from the request pipelines 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 pipeline 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
Layer7 Live API Creator
has with external systems or partners might designate a request format different from the standard formats
Layer7 Live API Creator
supports. As illustrated in the B2B sample, in the
B2B Pavlov
API, you can define request pipelines 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 code editor for a request pipeline.
Reformat response
In this example, the API agreement that
Layer7 Live API Creator
has with external systems/partners might designate a response format different from the standard formats
Layer7 Live API Creator
supports. As illustrated in the Sample API, you can define request pipelines 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 code editor for a request pipeline.
Reformat error response
In this example,
Layer7 Live API Creator
returns custom error responses. This example demonstrates how you can evaluate the
json
object in an error pipeline 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 code editor for an error pipeline.
Modify CORS Response
In this example,
Layer7 Live API Creator
returns custom CORS responses based on the requested resource name.
This example demonstrates the following:
  • How to use 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 code editor for an Options event.
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
parentTableRow
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 = parentTableRow.name; // this context variable 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, pipelines, 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 pipelines.
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 pipeline events.
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.
Layer7 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
Layer7 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
Layer7 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.