JavaScript Code Examples
The following JavaScript code examples are available from the code editor within API Creator. They are drawn from the sample APIs (Demo, Sample, B2B Pavlov, and B2B Northwind), so you can study the code in context.
lac42
The following JavaScript code examples are available from the code editor within API Creator. They are drawn from the sample APIs (
Demo
, Sample
, B2B Pavlov
, and B2B Northwind
), so you can study the code in context.In this article:
General-use Patterns
The following examples are common patterns that you can use in your code:
- Iterate Over Arrays
- Catch Exceptions
- Invoke a Command Line
- More advanced use of Java
- Sending an email
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 approachfor 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 catching and processing them by surrounding your code, including calls to Java, with try/catch blocks. The following
Catch Exceptions
code is an example.Example:
try {// This will throw a NullPointerExceptionJava.type("java.lang.Long").parseLong(null);}catch(e) {// The exception is caught herelog.debug("Got an exception: " + e);}
You can also have API Server handle exception conditions and errors by invoking error handlers that modify the error. For more information about how to create error event handlers, see Event Handlers.
For more information about error handling, 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:
- About theRuntimeJava class, see the JavaDoc documentation.
- About the theIOUtilsApache Commons class, see the JavaDoc documentation for full details.
Example:
// Start an arbitrary processvar 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 objectvar 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 objectobj.Title += "Hi there ";// Now invoke a PATCH using the Apache Commons library directlyvar 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]bigcorp.com")); var Message = Java.type("javax.mail.Message"); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("[email protected]acme.com")); 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, if not most, mail servers require authentication. If you need to send more than a few emails, you can use a service like 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]yahoo.com", "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]yahoo.com"));var Message = Java.type("javax.mail.Message");msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("[email protected]acme.com"));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);
Validations
Validation rules are expressions that you assign to an entity that must be true for a transaction to commit. The
New/Old Values
JavaScript code example is available from the code editor for validation rules.For more information about how to create validation rules, see Validation Rule Type.
New/Old Values
The following 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
You can define arbitrary new RESTful endpoints in JavaScript using custom endpoints. The
Non-JSON endpoints
code example is available from the code editor for custom endpoints.For more information about how to run custom endpoints, see Manage Custom Endpoints.
Non-JSON endpoints
You can return non-JSON responses, such as this HTML for browser execution. The Business to Business (B2B) sample defines the
Menu
custom endpoint, as shown in the following code snippet: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.
Logic Events
API Creator invokes events with the current/old table rows on POST, PUT, and DELETE operations.
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 Purchaseorder 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 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 theamount_totalusing 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 thepurchaseorder_auditrow either by direct code or bySysLogic.insertChildFrom.For more information about theInsertIntoFromsystem 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 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)
API Creator invokes table event handlers with the current/old table rows on POST, PUT, and DELETE operations.
In this example, you can update (parent) employee salaries when a row is inserted into (child) EmployeeRaises:
- The event for table EmployeeRaises is defined, inserts only.
- Like-named attributes are copied from the source row (EmployeeRaises, wrapped in logicContext) to the parent (Employee) Row by invoking theB2B.copyAttributesshared library routine. The parent row is obtained through the parent accessor, part of the automatically created Object Model.
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);
This code example is available from the event rule code editor.
Posting Webhooks
Use this example to send an inserted or altered order to a supplier, which is formatted per the
ShipperAPIDef
resource:- Obtain the shipper, if there is one.
- Invoke thetransformCurrentRow()method to transform the order into the required format, including related data such as items in the order.
- The transformation is defined by declaring theShipperAPIDefresource, where you can choose/alias attributes, include related data, etc.
- Invoke theB2B.sendToWebHookre-usable JavaScript library function to post the transform.
Example
The following code snippet shows the code for the Posting Webhooks JavaScript code example:
// object model (row) provides accessors to related objects var shipper = row.FK_Orders_Shippers; if (shipper !== null) { // resource defines transform: cols, aliases, related objects var transform = logicContext.transformCurrentRow("ShipperAPIDef"); // find with code completion B2B.sendToWebHook(transform, shipper.webHookURL); // loadable library (API Properties > Libraries) }
This code example is available from the event rule code editor.
For more information about the
transformCurrentRow()
method, see transformCurrentRow Method.Sending Messages
Table event handlers are invoked with the current/old table rows on POST, PUT, and DELETE operations.
In this example, you can publish an explicitly defined resource, created from a row, to a message queue:
- CA Live API Creatorchecks a row state.
- CA Live API Creatortransforms the order into the required format, including related data, such as items in an order, by invokinglogicContextobject'stransformCurrentRow()method.You define the transformation by explicitly defining a resource in your API, for exampleMyResourceName, where you can choose and alias attributes and include related data.
- CA Live API Creatorpublishes a message to a topic in an MQTT or Kafka broker by invoking thelistenerUtilobject'spublishMessage()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
Table event handlers are invoked with the current/old table rows on POST, PUT, and DELETE operations.
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:
- CA Live API Creatoracquires the message content.
- CA Live API Creatortransforms and decomposes the payload onto multiple underlying tables, by invokingSysUtilityobject'srestPost()method.You define the transformation by explicitly defining a resource in your API, for exampleMyResourceName, 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 datavar resourceURL = req.localFullBaseURL + 'MyResourceName'; // mapping and transformation defined by Custom Resourcevar parms = {};var settings = { 'headers': {'Authorization' : 'MyAuthToken:1'} }; // e.g., define on Auth Tokens screenif (messageContent.startsWith("<"))settings.headers["Content-Type"] = "application/xml"; // omit this if strictly JSONvar 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
Table event handlers are invoked with the current/old table rows on POST, PUT, and DELETE operations.
In this example, you can learn how to:
- Retrieve a table row usinglogicContext.getBeanByPrimaryKeymethod.
- Retrieve multiple rows from a table by passing in a SQL query into thelogicContext.getRowsByQuerymethod.
- Modify a column in a table using thelogicContext.updatemethod.
- Insert a new row into a table using logicContext.createPersistentBeanandlogicContext.insertmethods.
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 eventlogicContext.logDebug(db + "running"); // to test: alter credit_limit for Alpha and Sons, verify changed in Sampleif (row.name == "Alpha and Sons") {// read a (single) row by primary keyvar 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 MySQLvar 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 ruleslogicContext.logDebug(db + 'updated row: ' + row);// alter a row (read above)logicContext.touch(customer); // required, to set up optimistic lockingcustomer.credit_limit += 1;logicContext.update(customer);logicContext.logDebug(db + 'updated customer: ' + customer);// insert a rowvar 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
Table event handlers are invoked with the current/old table rows on POST, PUT, and DELETE operations.
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 SamplelogicContext.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.
Formulas
Formulas are derivation rules that compute the value of a table or view column. Formulas can reference other columns in the row as
row.attribute
and parent columns.You can get a list of attribute names by pressing the
Control+Space
keys on your keyboard.You specify rules using JavaScript notation. You can use normal JavaScript services for if/else, looping, and date datatype handling.
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 attribute CurrentTimestamp is null and to calculate a default value.
Example
The following code snippet shows the code for the Dealing with timestamps 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 attribute CurrentTimestamp (with GMT offset) is null and to calculate a default value.
Example
The following code snippet shows the code for the Dealing with timestamps with offset 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
Functions are coded in JavaScript, with full access to the JavaScript libraries and Java JAR files. They are user-defined endpoints that:
- You can associate with one or more tables, views, or table-based resources.
- Can have optional input parameters.
- Should return a proper JSON response.
- Are authenticated.
- Are included in Swagger documentation.
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 Row Operations (methods) 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=10It 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 Code (unrelated to data row) 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 = 2var 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 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 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/Response Events
Request events fire before system processing, where you can alter the Request JSON. Response events fire after all system processing, giving you an opportunity to change the response before it is sent to the caller.
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 actions that activate system services to:
- Look up foreign keys.
- Merge-Insert: cause 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 attributes that are used 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.
- The API Server processes the transformed request.For more information about metadata tags for parent lookup, see Explore the 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 data) to maintain their information by posting a request for their organization:
- If their Supplier row does not exist, insert the row.
- If their Supplier row exists, update the row (merge).
For more information:
- About theLOOKUPmetadata action tag, see LOOKUP Metadata Action Tag.
- About theMERGE_INSERTmetadata action tag, see MERGE_INSERT Metadata Action Tag.
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:- Restrict the transformation to POST operations on the SalesReports resource.
- 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 requestif(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:- Restrict the transformation to POST operations on thePartnerOrdersresource.
- 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 objectprint("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 thereqobject 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
Use the JavaScript resource type to write server-side JavaScript code that is executed whenever the resource is accessed.
The following JavaScript code examples are available for resources:
- (From the JavaScript resource code editor) Service calls to integrate external data.For more information about how to define JavaScript resources, see Define JavaScript Resource Types.
- (From the row event code editor) Row event.For more information about how to create resource row events and insert code examples into the code editor, see Resource Row 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.
Row Event
Provide JavaScript that is executed for each row, for example, alter/create attributes.
New attributes are not reflected in the Swagger definition. We recommend using non-persistent attributes.
For more information about how to create non-persistent attributes, see Manage Non-Persistent Attributes
Example
The following code snippet shows the code for the Row Event JavaScript code example. The
foo
attribute is created:row.foo = 'these reps have sold more than 20 items';
This code example is available from the resource row 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 POSTvar 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 runlog.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 payloadvar 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 tablevar 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 payloadvar 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 tablevar 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 payloadvar 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 tablevar 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 payloadvar 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 tablevar 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.- Authenticatecode
- Simple Authenticate
- Shared Secret Authenticate
- Get configuration optionscode
- Simple Get Configuration Options
- Shared Secret Get Configuration Options
- Configurecode
- Simple Configure
- Shared Secret Configure
- Get login infocode
- 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 fileresult.configure = function configure(myConfig) {configSetup.logonApiKey = myConfig.logonApiKey || 'demo_full'; // supply, or defaultconfigSetup.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 nameroles.push('API Owner'); // HARD CODED FOR DEMO (we even ignore the pwd) for full accesserrorMsg = null; // authorized successfullymyUserData.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 timeresult.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.