
Welcome to the ACC JS SDK. This post introduces a series of posts around Campaign API and the SDK.
Here are a couple of ideas about how you can use the SDK
Start with the concepts behind Campaign and the SDK.
Here's an advanced example which illustrates how to create a REST API for Campaign using the SDK. This code is expected to run inside an express server, or even inside a lambda function.
See the advanced topic of Dynamic Invocation to understand how SOAP calls can be dynamically constructed from HTTP requests
const sdk = require('@adobe/acc-js-sdk');
// ... perform authentication and get connection parameters here
const client = await sdk.init(connectionParameters);
// It is useful to log the IP address of the server where the SDK
// runs so that it can be whitelisted in the Campaign configuration
const ip = await sdk.ip();
console.log(`Outbound IP address is '${JSON.stringify(ip)}'`);
// Log on to Campaign
await client.logon();
// Decode path which must be <namespace>/<schema-id>/<method>.
// Here we consider we're running inside an Adobe Runtime function
// which exposes the URL path as <args.__ow_path>
var path = args.__ow_path;
if (path[0] == '/')
path = path.substring(1);
const pathElements = path.split("/");
// Support for /ping endpoint
if (pathElements.length >= 1 && pathElements[0] === "ping") {
return sdk.getSDKVersion();
}
const namespace = pathElements[0].trim();
const schemaId = pathElements[1].trim();
const methodName = pathElements[2].trim();
// The scopeName is the name of the property of the NLWS object which corresponds
// to the schema being called. For instance xtk:session => NLWS.xtkSession
const scopeName = `${namespace}${schemaId[0].toUpperCase()}${schemaId.substring(1)}`;
const scope = NLWS[scopeName];
const method = scope[methodName];
// Dynamically call SOAP method
console.log(`About to call method '${methodName}' of scope '${scopeName}'`);
// Call the method with a hook to decode parameters. The hook will extract the method
// parameters values from the action arguments and pass them as an array, as expected
// by the SDK. It will also set the "this" object for non static methods and fill the
// "outName" array will be filled with the names of the output parameters of the method
const outNames = [];
const result = await method.call(scope, (method, callContext) => {
// Non-static methods require a "this" parameter. This parameter can be passed as
// a "this" property of the action parameters, or, if this propery is not set, as
// the action parameters directly (this is just to simplify the REST API callls by
// allowing to omit the "this" property if the call is non-static with no arguments)
const isStatic = DomUtil.getAttributeAsBoolean(method, "static");
if (!isStatic) {
const object = args["this"] || args;
callContext.object = object;
}
// Compute parameters array by extracting each parameter by name
// from the action arguments
const parameters = [];
const params = DomUtil.getFirstChildElement(method, "parameters");
if (params) {
var param = DomUtil.getFirstChildElement(params, "param");
while (param) {
const inout = DomUtil.getAttributeAsString(param, "inout");
const paramName = DomUtil.getAttributeAsString(param, "name");
if (!inout || inout=="in") {
parameters.push(args[paramName]);
}
else {
outNames.push(paramName);
}
param = DomUtil.getNextSiblingElement(param, "param");
}
}
return parameters;
});
// Process result. Again this is to simplify the API and return a valid JSON
var returnedValue = {};
if (outNames.length == 0) {
returnedValue = undefined;
}
// If the API returns one parameter which is an object, the return it directly.
// If not (return value is a literal), then use a JSON with the return parameter name
else if (outNames.length == 1) {
if (result && typeof result == "object")
returnedValue = result;
else
returnedValue[outNames[0]] = result;
}
// If the API returns multiple values, then build a JSON which each return value
else {
for (var i=0; i<outNames.length; i++) {
const name = outNames[i];
returnedValue[name] = result[i];
}
}
return returnedValue;