@adobe/acc-js-sdk 1.1.10 → 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2170
- package/docs/404.html +11 -0
- package/docs/Gemfile +35 -0
- package/docs/Gemfile.lock +270 -0
- package/docs/_config.yml +55 -0
- package/docs/_data/navigation.yml +119 -0
- package/docs/_includes/navigation.html +33 -0
- package/docs/_layouts/default.html +21 -0
- package/docs/_layouts/home.html +4 -0
- package/docs/_layouts/page.html +5 -0
- package/docs/_layouts/post.html +7 -0
- package/docs/_posts/2022-10-14-welcome.html +149 -0
- package/docs/application.html +367 -0
- package/docs/architecture.html +24 -0
- package/docs/assets/css/styles.css +362 -0
- package/docs/assets/images/adobe-campaign-256.png +0 -0
- package/docs/assets/images/architecture.png +0 -0
- package/docs/assets/images/ref.svg +6 -0
- package/docs/badgerFish.html +14 -0
- package/docs/bestPractices.html +189 -0
- package/docs/blog.html +18 -0
- package/docs/buildAndRun.html +96 -0
- package/docs/caches.html +68 -0
- package/docs/changeLog.html +263 -0
- package/docs/checkList.html +168 -0
- package/docs/concepts.html +130 -0
- package/docs/connecting.html +210 -0
- package/docs/connectionParameters.html +109 -0
- package/docs/contribute.html +54 -0
- package/docs/dataTypes.html +124 -0
- package/docs/differences.html +4 -0
- package/docs/documentation.html +21 -0
- package/docs/domHelper.html +88 -0
- package/docs/dynamicInvoke.html +36 -0
- package/docs/entityAccessor.html +22 -0
- package/docs/errors.html +47 -0
- package/docs/escaping.html +76 -0
- package/docs/favicon.png +0 -0
- package/docs/healthCheck.html +66 -0
- package/docs/httpHeaders.html +78 -0
- package/docs/index.html +64 -0
- package/docs/installation.html +34 -0
- package/docs/license.html +208 -0
- package/docs/messageCenter.html +80 -0
- package/docs/methodLevelRepresentation.html +12 -0
- package/docs/midSourcing.html +19 -0
- package/docs/observability.html +169 -0
- package/docs/passwords.html +27 -0
- package/docs/profiles.html +103 -0
- package/docs/pushDown.html +13 -0
- package/docs/quickstart.html +69 -0
- package/docs/release.html +52 -0
- package/docs/samples.html +82 -0
- package/docs/simpleJson.html +88 -0
- package/docs/soapAPIs.html +234 -0
- package/docs/timeouts.html +23 -0
- package/docs/transport.html +45 -0
- package/docs/troubleshooting.html +17 -0
- package/docs/writeDoc.html +208 -0
- package/docs/xml2json.html +96 -0
- package/docs/xtkCaster.html +67 -0
- package/docs/xtkInterface.html +20 -0
- package/docs/xtkOption.html +54 -0
- package/docs/xtkPackage.html +16 -0
- package/docs/xtkPersist.html +213 -0
- package/docs/xtkQueryDef.html +245 -0
- package/docs/xtkSchema.html +39 -0
- package/docs/xtkSession.html +29 -0
- package/docs/xtkWorkflow.html +28 -0
- package/docs/xtkWrite.html +51 -0
- package/package-lock.json +1 -1
- package/package.json +1 -1
- package/src/application.js +15 -5
- package/src/campaign.js +1 -1
- package/src/soap.js +6 -6
- package/test/application.test.js +21 -6
- package/test/soap.test.js +13 -0
- package/CHANGELOG.md +0 -252
package/README.md
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
# Adobe Campaign Classic (ACC) SDK in JavaScript
|
|
2
|
-
|
|
3
|
-
This is a node.js SDK for Campaign API. It exposes the Campaign API exactly like it is used inside Campaign using the NLWS notation.
|
|
1
|
+
# Adobe Campaign Classic (ACC) SDK in JavaScript
|
|
4
2
|
|
|
3
|
+
The ACC JavaScript SDK is a JavaScript SDK which allows you to call Campaign APIs in a simple, expressive and JavaScript idiomatic way. It hides away the Campaign complexities associated with having to make SOAP calls, XML to JSON conversion, type formatting, etc.
|
|
5
4
|
|
|
5
|
+
The API is fully asynchronous using promises and works as well on the server side than on the client side in the browser.
|
|
6
6
|
|
|
7
|
-
# Change log
|
|
8
7
|
|
|
9
|
-
See the [Change log](./CHANGELOG.md) for more information about the different versions, changes, etc.
|
|
10
8
|
|
|
9
|
+
> **Extensive documentation is available**: https://opensource.adobe.com/acc-js-sdk/
|
|
11
10
|
|
|
12
|
-
# Overview
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
# QuickStart
|
|
15
13
|
|
|
16
|
-
The API is fully asynchronous using promises and works as well on the server side than on the client side in the browser.
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
To install the SDK, use your favorite node command
|
|
19
16
|
```js
|
|
20
17
|
npm install --save @adobe/acc-js-sdk
|
|
21
18
|
```
|
|
22
19
|
|
|
20
|
+
|
|
23
21
|
The SDK entrypoint is the `sdk` object from which everything else can be created.
|
|
24
22
|
|
|
25
23
|
```js
|
|
@@ -41,7 +39,7 @@ which will return the SDK name and version (the actual name and version number w
|
|
|
41
39
|
```
|
|
42
40
|
|
|
43
41
|
|
|
44
|
-
#
|
|
42
|
+
# An example
|
|
45
43
|
Here's a small node.js application which displays all the target mappings in Campaign.
|
|
46
44
|
|
|
47
45
|
Create a new node.js application
|
|
@@ -102,2166 +100,6 @@ Target mappings: {"deliveryMapping":[{"id":"1747","label":"Recipients","name":"m
|
|
|
102
100
|
|
|
103
101
|
|
|
104
102
|
|
|
105
|
-
# API Basics
|
|
106
|
-
|
|
107
|
-
In order to call any Campaign API, you need to create a `Client` object first. You pass it the Campaign URL, as well as your credentials.
|
|
108
|
-
|
|
109
|
-
```js
|
|
110
|
-
const sdk = require('@adobe/acc-js-sdk');
|
|
111
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
112
|
-
"https://myInstance.campaign.adobe.com",
|
|
113
|
-
"admin", "admin");
|
|
114
|
-
const client = await sdk.init(connectionParameters);
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Connection options
|
|
118
|
-
|
|
119
|
-
Connection parameters can also be passed an option object with the following attributes
|
|
120
|
-
Attribute|Default|Description
|
|
121
|
-
---|---|---
|
|
122
|
-
representation|"SimpleJson"| See below. Will determine if the SDK works with xml of json object. Default is JSON
|
|
123
|
-
rememberMe|false| The Campaign `rememberMe` attribute which can be used to extend the lifetime of session tokens
|
|
124
|
-
entityCacheTTL|300000| The TTL (in milliseconds) for the xtk entity cache
|
|
125
|
-
methodCacheTTL|300000| The TTL (in milliseconds) for the xtk method cache
|
|
126
|
-
optionCacheTTL|300000| The TTL (in milliseconds) for the xtk option cache
|
|
127
|
-
traceAPICalls|false| Activates tracing of API calls or not
|
|
128
|
-
transport|axios|Overrides the transport layer
|
|
129
|
-
noStorage|false|De-activate using of local storage
|
|
130
|
-
storage|localStorage|Overrides the local storage for caches
|
|
131
|
-
refreshClient|undefined|Async callback to run when the session token is expired
|
|
132
|
-
charset|UTF-8|The charset encoding used for http requests. In version 1.1.1 and above, the default will be UTF-8. It's possible to override (including setting an empty character set) with this option.
|
|
133
|
-
extraHttpHeaders|[string]:string|An optional dictionary (key/value pairs) of extra HTTP headers to pass to all API calls.
|
|
134
|
-
clientApp|string|An optional string describing the name and version of the SDK client application. It will be passed to the server in the ACC-SDK-Client-App HTTP header
|
|
135
|
-
noSDKHeaders|boolean|Can be set to disable passing ACC-SDK-* HTTP headers to the server
|
|
136
|
-
noMethodInURL|boolean|Can be set to true to remove the method name from the URL
|
|
137
|
-
timeout|number|Can be used to set the APIs call timeout (in ms)
|
|
138
|
-
```js
|
|
139
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
140
|
-
"https://myInstance.campaign.adobe.com",
|
|
141
|
-
"admin", "admin",
|
|
142
|
-
{ representation: "xml", rememberMe: true });
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Login with IMS
|
|
146
|
-
|
|
147
|
-
The SDK also supports IMS service token with the `ofUserAndServiceToken` function. Pass it a user to impersonate and the IMS service token.
|
|
148
|
-
|
|
149
|
-
In that context, the IMS service token grants admin-level privileges, and the user indicates which Campaign user to impersonate.
|
|
150
|
-
```js
|
|
151
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
152
|
-
"https://myInstance.campaign.adobe.com",
|
|
153
|
-
"admin", "==ims_service_token_here");
|
|
154
|
-
```
|
|
155
|
-
## Login with IMS access token
|
|
156
|
-
The SDK supports IMS access token of an IMS user with the `ofBearerToken` function. Pass it a bearer token.
|
|
157
|
-
```js
|
|
158
|
-
const connectionParameters = sdk.ConnectionParameters.ofBearerToken(
|
|
159
|
-
"https://myInstance.campaign.adobe.com",
|
|
160
|
-
"ims_bearer_token");
|
|
161
|
-
````
|
|
162
|
-
|
|
163
|
-
## Login with Session token
|
|
164
|
-
|
|
165
|
-
Campaign supports authenticating with a session token in some contexts. This is usually used for Message Center API calls (see the "Message Center" section below).
|
|
166
|
-
|
|
167
|
-
In this example, the session token is a string composed of the user name, a slash sign, and the password (often empty)
|
|
168
|
-
|
|
169
|
-
```js
|
|
170
|
-
const connectionParameters = sdk.ConnectionParameters.ofSessionToken(url, "mc/mc");
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Note that this authentication mode is very specific and does not actually performs a Logon: the session token will be passed to each API calls as-is (with an empty security token) and requires proper setup of the security zones for access to be granted.
|
|
174
|
-
|
|
175
|
-
Another consequence is that the Application object will not be available (client.application will be undefined) when using this authentication mode. The reason is that the application object requires an actual login call to be made to be populated.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
## Anonymous logon
|
|
179
|
-
|
|
180
|
-
Several Campaign APIs are anonymous, i.e. do not require to actually logon to be used. For instance the "/r/test" API is anonymous. The SDK supports anonymous APIs but still need to be initialized with anonymous credentials as follows. Of course, anonymous APIs also work if you are logged on with a different method.
|
|
181
|
-
|
|
182
|
-
```js
|
|
183
|
-
const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser(url);
|
|
184
|
-
const client = await sdk.init(connectionParameters);
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## Logon with Security token
|
|
188
|
-
|
|
189
|
-
If you want to use the SDK client-side in a web page returned by Campaign, you cannot use the previous authentication functions because you do not know the user and password, and because you cannot read the session token cookie.
|
|
190
|
-
|
|
191
|
-
For this scenario, the `ofSecurityToken` function can be used. Pass it a security token (usually available as document.__securitytoken), and the SDK will let the browser handle the session token (cookie) for you.
|
|
192
|
-
|
|
193
|
-
```html
|
|
194
|
-
<script src="acc-sdk.js"></script>
|
|
195
|
-
<script>
|
|
196
|
-
(async () => {
|
|
197
|
-
try {
|
|
198
|
-
const sdk = document.accSDK;
|
|
199
|
-
var securityToken = "@UyAN...";
|
|
200
|
-
const connectionParameters = sdk.ConnectionParameters.ofSecurityToken(url, securityToken);
|
|
201
|
-
const client = await sdk.init(connectionParameters);
|
|
202
|
-
await client.logon();
|
|
203
|
-
const option = await client.getOption("XtkDatabaseId");
|
|
204
|
-
console.log(option);
|
|
205
|
-
} catch(ex) {
|
|
206
|
-
console.error(ex);
|
|
207
|
-
}
|
|
208
|
-
})();
|
|
209
|
-
</script>
|
|
210
|
-
</body>
|
|
211
|
-
</html>
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Note: if the HTML page is served by the Campaign server (which is normally the case in this situation), you can pass an empty url to the `ofSecurityToken` API call.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
## LogOn / LogOff
|
|
218
|
-
|
|
219
|
-
The `sdk.init` call will not actually connect to Campaign, you can call the `logon` method for this. Logon does not need to be called when using session-token authentication or anonymous authentication.
|
|
220
|
-
|
|
221
|
-
```js
|
|
222
|
-
await client.logon();
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
```js
|
|
226
|
-
await client.logoff();
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## refreshClient callback
|
|
230
|
-
The refreshClient is an async callback function with the SDK client as parameter, it is called when the ACC session is expired.
|
|
231
|
-
The callback must refresh the client session and return it. if a SOAP query fails with session expiration error then it will be retried when the callback is defined.
|
|
232
|
-
|
|
233
|
-
```js
|
|
234
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
235
|
-
url, "admin", "admin",
|
|
236
|
-
{ refreshClient: async (client) => {
|
|
237
|
-
await client.logon();
|
|
238
|
-
return client;
|
|
239
|
-
}});
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## IP Whitelisting
|
|
243
|
-
|
|
244
|
-
Campaign includes an IP whitelisting component which prevents connections from unauthorized IP addresses. This is a common source of authentication errors.
|
|
245
|
-
|
|
246
|
-
A node application using the SDK must be whitelisted to be able to access Campaign. The SDK `ip` function is a helper function that can help you find the IP or IPs which need to be whitelisted.
|
|
247
|
-
|
|
248
|
-
This API is only meant for troubleshooting purposes and uses the `https://api.db-ip.com/v2/free/self` service.
|
|
249
|
-
|
|
250
|
-
```js
|
|
251
|
-
const ip = await sdk.ip();
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Will return something like
|
|
255
|
-
|
|
256
|
-
```json
|
|
257
|
-
{ "ipAddress":"AAA.BBB.CCC.DDD","continentCode":"EU","continentName":"Europe","countryCode":"FR","countryName":"France","stateProv":"Centre-Val de Loire","city":"Bourges" }
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## Calling static SOAP methods
|
|
261
|
-
|
|
262
|
-
The NLWS object allows to dynamically perform SOAP calls on the targetted Campaign instance.
|
|
263
|
-
```js
|
|
264
|
-
const NLWS = client.NLWS;
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
Static SOAP methods are the easiest to call. Once you have a `NLWS` object and have logged on to the server, call a static mathod as followed. This example will use the `xtk:session#GetServerTime` method to displayt the current timestamp on the server.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
```js
|
|
271
|
-
const NLWS = client.NLWS;
|
|
272
|
-
result = await NLWS.xtkSession.getServerTime();
|
|
273
|
-
console.log(result);
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
where
|
|
277
|
-
* `xtkSession` is made of the namespace and entity to which the API applies. For instance `xtk:session` -> `xtkSession`
|
|
278
|
-
* `getServerTime` is the method name. In ACC, method names start with an upper case letter, but in JS SDK you can put it in lower case too (which is preferred for JavaScript code).
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
## Parameter types
|
|
282
|
-
|
|
283
|
-
In Campaign, many method attributes are XML elements or documents, as well as many return types. It's not very easy to use in JavaScript, so the SDK supports automatic XML<=> JSON conversion. Of yourse, you can still use XML if you want.
|
|
284
|
-
|
|
285
|
-
We're supporting 2 flavors of JSON in addition to XML.
|
|
286
|
-
* `SimpleJson` which is the recommeded and default representation
|
|
287
|
-
* `BadgerFish` which was the only and default before 1.0.0, and is now a legacy flavor of JSON. It's a little bit complex and was deprecated in favor of `SimpleJson` (http://www.sklar.com/badgerfish/)
|
|
288
|
-
* `xml` which can be use to perform no transformation: Campaign XML is returned directly without any transformations.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
The representation can set when creating a client. It's recommended to keep it to `SimpleJson`.
|
|
292
|
-
```js
|
|
293
|
-
const client = await sdk.init("https://myInstance.campaign.adobe.com", "admin", "admin", { representation: "SimpleJson" });
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
Here's an example of a queryDef in SimpleJson). This query will return an array containing one item for each external account in the Campaign database. Each item will contain the account id and name.
|
|
297
|
-
|
|
298
|
-
```
|
|
299
|
-
const queryDef = {
|
|
300
|
-
schema: "nms:extAccount",
|
|
301
|
-
operation: "select",
|
|
302
|
-
select: {
|
|
303
|
-
node: [
|
|
304
|
-
{ expr: "@id" },
|
|
305
|
-
{ expr: "@name" }
|
|
306
|
-
]
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
## Method-level representation
|
|
312
|
-
|
|
313
|
-
The client object is created with a default representation which is used for all API calls in the context of this client. Since version 1.1.2, it is also possible to set the representation at the method level, i.e. use a particular representation for a particular API call.
|
|
314
|
-
|
|
315
|
-
* `client.NLWS`: use the default representation set at the client level
|
|
316
|
-
* `client.NLWS.xml`: use the XML reresentation
|
|
317
|
-
* `client.NLWS.json`: use the SimpleJson representation
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
## SimpleJson format
|
|
321
|
-
The Simple JSON format works like this:
|
|
322
|
-
|
|
323
|
-
The XML root element tag is determined by the SDK as it's generating the XML, usually from the current schema name.
|
|
324
|
-
|
|
325
|
-
* XML: `<root/>
|
|
326
|
-
`
|
|
327
|
-
* JSON: `{}`
|
|
328
|
-
|
|
329
|
-
XML attributes are mapped to JSON attributes with the same name, whose litteral value can be a string, number, or boolean. There's no "@" sign in the JSON attribute name.
|
|
330
|
-
Values in JSON attributes can be indifferently typed (ex: number, boolean), or strings (ex: "3" instead of just 3) depending if the conversion could determine the attribute type or not.
|
|
331
|
-
API users should expect and handle both value and use the `XtkCaster` object to ensure proper conversion when using.
|
|
332
|
-
|
|
333
|
-
* XML: `<root hello="world" count=3 ok=true/>`
|
|
334
|
-
* JSON: `{ hello:"world", count:3, ok:true }`
|
|
335
|
-
|
|
336
|
-
XML elements are mapped to JSON objects
|
|
337
|
-
|
|
338
|
-
* XML: `<root><item id=1/></root>`
|
|
339
|
-
* JSON: `{ item: { id:1 } }`
|
|
340
|
-
|
|
341
|
-
If the parent element tag ends with `-collection` children are always an array, even if there are no children, or if there is just one child. The rationale is that XML/JSON conversion is ambigous : XML can have multiple elements with the same tag and when there's only one such element, it's not possible to determine if it should be represented as a JSON object or JSON array unless we have additional metadata.
|
|
342
|
-
|
|
343
|
-
* XML: `<root-collection><item id=1/></root>`
|
|
344
|
-
* JSON: `{ item: [ { id:1 } ] }`
|
|
345
|
-
|
|
346
|
-
When an XML element is repeated, an JSON array is used
|
|
347
|
-
|
|
348
|
-
* XML: `<root><item id=1/><item id=2/></root>`
|
|
349
|
-
* JSON: `{ item: [ { id:1 }, { id:2 } ] }`
|
|
350
|
-
|
|
351
|
-
Text of XML element is handle with the `$` sign in the JSON attribute name, or with a child JSON object name `$`
|
|
352
|
-
|
|
353
|
-
Text of the root element
|
|
354
|
-
* XML: `<root>Hello</root>`
|
|
355
|
-
* JSON: `{ $: "Hello" }`
|
|
356
|
-
|
|
357
|
-
Text of a child element
|
|
358
|
-
* XML: `<root><item>Hello</item></root>`
|
|
359
|
-
* JSON: `{ $item: "Hello" }`
|
|
360
|
-
* Alternative JSON: `{ item: { $: "Hello" } }`
|
|
361
|
-
|
|
362
|
-
If an element contains both text, and children, you need to use the alternative `$` syntax
|
|
363
|
-
* XML: `<root><item>Hello<child id="1"/>
|
|
364
|
-
</item>
|
|
365
|
-
</root>`
|
|
366
|
-
* JSON: `{ item: { $: "Hello", child: { id:1 } }`
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
## BadgerFish format
|
|
370
|
-
|
|
371
|
-
To distinguish between BadgerFish and SimpleJson format, all BadgerFish objects will have the BadgerFishObject class, that includes the top-level object, but also all children objects. A badgerfish object can be created as follows. It will automatically convert all the object literals into BadgerFishObjet class.
|
|
372
|
-
|
|
373
|
-
```
|
|
374
|
-
const obj = new DomuUtil.BadgerFishObject({ "@att":"value });
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
## Returning multiple values
|
|
379
|
-
Campaign APIs can return one or multiple values. The SDK uses the following convention:
|
|
380
|
-
* no return value -> returns `null`
|
|
381
|
-
* one return value -> returns the value directly
|
|
382
|
-
* more that one return value -> returns an array of values
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
## Calling non-static APIs
|
|
386
|
-
|
|
387
|
-
To call a non-static API, you need an object to call the API on. You create an object with the `create` method.
|
|
388
|
-
For instance, here's how one creates a QueryDef object.
|
|
389
|
-
|
|
390
|
-
```js
|
|
391
|
-
const queryDef = {
|
|
392
|
-
schema: "nms:extAccount",
|
|
393
|
-
operation: "select",
|
|
394
|
-
select: {
|
|
395
|
-
node: [
|
|
396
|
-
{ expr: "@id" },
|
|
397
|
-
{ expr: "@name" }
|
|
398
|
-
]
|
|
399
|
-
}
|
|
400
|
-
};
|
|
401
|
-
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
Note: the returned object is opaque and private, it should not be directly manipulated.
|
|
405
|
-
|
|
406
|
-
The method can then be called directly on the object
|
|
407
|
-
```js
|
|
408
|
-
const extAccounts = await query.executeQuery();
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
In this example, the result is as follows
|
|
412
|
-
|
|
413
|
-
```js
|
|
414
|
-
{ extAccount:[
|
|
415
|
-
{ id: "2523379", name: "cda_snowflake_extaccount" },
|
|
416
|
-
{ id: "1782", name: "defaultPopAccount" },
|
|
417
|
-
{ id: "3643548", name: "v8" }
|
|
418
|
-
]}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
Some methods can mutate the object on which they apply. This is for instance the case of the xtk:queryDef#SelectAll method. You call it on a queryDef, and it internally returns a new query definition which contain select nodes for all the nodes of the schema. When such a method is called, the SDK will know how to "mutate" the corresponding object.
|
|
422
|
-
|
|
423
|
-
```js
|
|
424
|
-
const queryDef = {
|
|
425
|
-
schema: "xtk:option",
|
|
426
|
-
operation: "get",
|
|
427
|
-
where: { condition: [ { expr:`@name='XtkDatabaseId'` } ] }
|
|
428
|
-
};
|
|
429
|
-
const query = client.NLWS.xtkQueryDef.create(queryDef);
|
|
430
|
-
await query.selectAll(false);
|
|
431
|
-
var result = await query.executeQuery();
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
In the previous example, a queryDef is created without any select nodes. Then the selectAll method is called. After the call, the JavaScript queryDef object will contain a select elements with all the nodes corresponding to attributes of the xtk:option schema.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
## XTK interfaces
|
|
438
|
-
|
|
439
|
-
Campaign schemas are following an object model. An interface is a set of methods. For instance, the "xtk:persist" interface, defined in the "xtk:session" schema, has a NewInstance method.
|
|
440
|
-
Schemas can implement interface, which means they inherit and implement the methods of the interface. Such methods are internally called using a particular SOAP call URN, which is formed of the interface name, followed by a pipe character, followed by the implementation schema id. For instance "xtk:persist|nms:delivery" is used to indicate that we're calling a method of the xtk:persist on a nms:delivery object which implements the xtk:persist interface.
|
|
441
|
-
|
|
442
|
-
The version 1.1.9 of the SDK properly implement this type of calls and will deal with this complexity for you. For instance, you can simply call the NewInstance method as follows:
|
|
443
|
-
|
|
444
|
-
```js
|
|
445
|
-
// Create a proxy delivery object
|
|
446
|
-
const delivery = client.NLWS.nmsDelivery.create({ label: "Hello" });
|
|
447
|
-
// Call the xtk:persist|nms:delivery#NewInstance method to retreive the default
|
|
448
|
-
// values of a delivery object before actually saving the delivery
|
|
449
|
-
await delivery.newInstance();
|
|
450
|
-
```
|
|
451
|
-
There are 2 common interfaces: xtk:persist and xtk:jobInterface which are documented below.
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
## Campaign data types
|
|
455
|
-
|
|
456
|
-
Campaign uses a typed system with some specificities:
|
|
457
|
-
* for strings, "", null, or undefined are equivalent
|
|
458
|
-
* numerical values cannot be null or undefined (0 is used instead)
|
|
459
|
-
* boolean values cannot be null or undefined (false is used instead)
|
|
460
|
-
* conversion between types is automatic based on their ISO representation
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
| Xtk type | | JS type | Comment |
|
|
464
|
-
| ------------ |----|-------- | --- |
|
|
465
|
-
| string | 6 | string | never null, defaults to "" |
|
|
466
|
-
| memo | 12 | string |
|
|
467
|
-
| CDATA | 13 | string |
|
|
468
|
-
| byte | 1 | number | signed integer in the [-128, 128[ range. Never null, defaults to 0 |
|
|
469
|
-
| short | 2 | number | signed 16 bits integer in the [-32768, 32768[ range. Never null, defaults to 0 |
|
|
470
|
-
| long | 3 | number | signed 32 bits integer. Never null, defaults to 0 |
|
|
471
|
-
| int64 | | string | signed 64 bits integer. As JavaScript handles all numbers as doubles, it's not possible to properly represent an int64 as a number, and it's therefore represented as a string.
|
|
472
|
-
| float | 4 | number | single-percision numeric value. Never null, defaults to 0 |
|
|
473
|
-
| double | 5 | number | single-percision numeric value. Never null, defaults to 0 |
|
|
474
|
-
| datetime | 7 | Date | UTC timestamp with second precision. Can be null |
|
|
475
|
-
| datetimetz | | | |
|
|
476
|
-
| datetimenotz | | | |
|
|
477
|
-
| date | 10 | Date | UTC timestamp with day precision. Can be null |
|
|
478
|
-
| boolean | 15 | boolean | boolean value, defaultint to false. Cannot be null |
|
|
479
|
-
| timespan | | | |
|
|
480
|
-
| primarykey | | string | A primary key is serialized with format <schemaId>|<keyField>[|<keyField>[...]]
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
The SDK user does not have to handle this, but outside of the Campaign ecosystem, those rules may not apply and you probably do not want to use a number for a string, etc. The `XtkCaster` class is here to help.
|
|
484
|
-
|
|
485
|
-
You get a static `XtkCaster` object like this
|
|
486
|
-
```js
|
|
487
|
-
const XtkCaster = sdk.XtkCaster;
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
or directly from the client for convenience
|
|
491
|
-
```js
|
|
492
|
-
const XtkCaster = client.XtkCaster;
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
To convert a Campaign value into a given type, use one of the following.
|
|
496
|
-
```js
|
|
497
|
-
stringValue = XtkCaster.asString(anyValue);
|
|
498
|
-
booleanValue = XtkCaster.asBoolean(anyValue);
|
|
499
|
-
byteValue = XtkCaster.asByte(anyValue);
|
|
500
|
-
shortValue = XtkCaster.asShort(anyValue);
|
|
501
|
-
int32Value = XtkCaster.asLong(anyValue);
|
|
502
|
-
numberValue = XtkCaster.asNumber(anyValue);
|
|
503
|
-
timestampValue = XtkCaster.asTimestamp(anyValue);
|
|
504
|
-
dateValue = XtkCaster.asDate(anyValue);
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
More dynamic conversions can be achieved using the `as` function. See the types table above for details.
|
|
508
|
-
|
|
509
|
-
```js
|
|
510
|
-
stringValue = XtkCaster.as(anyValue, 6);
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
In addition, the following helpers are available
|
|
514
|
-
* `XtkCaster.isTimeType` to test if a data type is a date, time or timestamp
|
|
515
|
-
* `XtkCaster.isStringType` to test if a data type is a string type (string, memo, etc.)
|
|
516
|
-
* `XtkCaster.isNumericType` to test if a data type is a numeric type
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
## DOM helpers
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
DOM manipulation is sometimes a bit painful. The `DomUtil` helper provides a few convenience functions
|
|
523
|
-
|
|
524
|
-
```js
|
|
525
|
-
const DomUtil = sdk.DomUtil;
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
or
|
|
529
|
-
|
|
530
|
-
```js
|
|
531
|
-
const DomUtil = client.DomUtil;
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
Create DOM from XML string:
|
|
536
|
-
```js
|
|
537
|
-
const doc = DomUtil.parse(`<root>
|
|
538
|
-
<one/>
|
|
539
|
-
</root>`);
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
Writes a DOM document or element as a string:
|
|
543
|
-
```js
|
|
544
|
-
const s = DomUtil.toXMLString(docOrElement);
|
|
545
|
-
```
|
|
546
|
-
|
|
547
|
-
Creates a new document
|
|
548
|
-
```js
|
|
549
|
-
const queryDoc = DomUtil.newDocument("queryDef");
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
Escape text value
|
|
553
|
-
```js
|
|
554
|
-
const escaped = DomUtil.escapeXmlString(value);
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
Find element by name (finds the first element with given tag). This is a very common operation when manipulating Campaign XML documents
|
|
558
|
-
```js
|
|
559
|
-
const el = DomUtil.findElement(parentElement, elementName, shouldThrow);
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
Get the text value of an elemennt. This will accomodate text elements, cdata elements, as well has having multiple text child element (which is ususally not the case in Campaign)
|
|
563
|
-
```js
|
|
564
|
-
const text = DomUtil.elementValue(element);
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
Iterates over child elements
|
|
568
|
-
```js
|
|
569
|
-
var child = DomUtil.getFirstChildElement(parentElement);
|
|
570
|
-
while (child) {
|
|
571
|
-
...
|
|
572
|
-
child = DomUtil.getNextSiblingElement(child);
|
|
573
|
-
}
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
Iterates over child elements of a given type
|
|
577
|
-
```js
|
|
578
|
-
var methodChild = DomUtil.getFirstChildElement(parentElement, "method");
|
|
579
|
-
while (methodChild) {
|
|
580
|
-
...
|
|
581
|
-
methodChild = DomUtil.getNextSiblingElement(methodChild, "method");
|
|
582
|
-
}
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
Get typed attribute values, with automatic conversion to the corresponding xtk type, and handling default values
|
|
586
|
-
```js
|
|
587
|
-
const stringValue = DomUtil.getAttributeAsString(element, attributeName)
|
|
588
|
-
const byteValue = DomUtil.getAttributeAsByte(element, attributeName)
|
|
589
|
-
const booleanValue = DomUtil.getAttributeAsBoolean(element, attributeName)
|
|
590
|
-
const shortValue = DomUtil.getAttributeAsShort(element, attributeName)
|
|
591
|
-
const longValue = DomUtil.getAttributeAsLong(element, attributeName)
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
JSON to XML conversion (SimpleJson by default)
|
|
595
|
-
```js
|
|
596
|
-
const document = DomUtil.fromJSON(json);
|
|
597
|
-
const json = DomUtil.toJSON(documentOrElement);
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
BadgerFish can be forced as well
|
|
601
|
-
```js
|
|
602
|
-
const document = DomUtil.fromJSON(json, "BadgerFish");
|
|
603
|
-
const json = DomUtil.toJSON(documentOrElement, "BadgerFish");
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
## Passing XML parameters
|
|
607
|
-
Many Campaign APIs take arguments which are DOM documents or DOM elements. For example, the nms:delivery#DeployTriggerMessages first argument is a DOMElement which is supposed to be a `<where>` clause used as a condition to select Message Center deliveries to publish.
|
|
608
|
-
|
|
609
|
-
```xml
|
|
610
|
-
<method name="DeployTriggerMessages" static="true">
|
|
611
|
-
<parameters>
|
|
612
|
-
<param inout="in" name="deliveries" type="DOMElement"/>
|
|
613
|
-
<param inout="in" name="localPublish" type="boolean"/>
|
|
614
|
-
</parameters>
|
|
615
|
-
</method>
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
For example, one would want to use the following condition to republish a particular delivery
|
|
619
|
-
|
|
620
|
-
```js
|
|
621
|
-
await client.NLWS.nmsDelivery.DeployTriggerMessages({
|
|
622
|
-
condition: [ {
|
|
623
|
-
expr: "@internalName='DM23'"
|
|
624
|
-
}]
|
|
625
|
-
}, false);
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
The JSON object corresponds to the following XML
|
|
629
|
-
```xml
|
|
630
|
-
<where>
|
|
631
|
-
<condition expr="@internalName='DM23'"/>
|
|
632
|
-
</where>
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
Note that in XML, unlike JSON, the root element `<where>` is explicitely named "where". When converting JSON to XML, there is no way for the SDK to know which tag name to used for the root XML element. The SDK contains some code to set it for the most common situation, but will rely on the user to specify, when necessary, the name of the root elment. This can be done using the `xtkschema` (all case insensitive) attribute as follows:
|
|
636
|
-
```js
|
|
637
|
-
await client.NLWS.nmsDelivery.DeployTriggerMessages({
|
|
638
|
-
xtkschema: 'xtk:where',
|
|
639
|
-
condition: [ {
|
|
640
|
-
expr: "@internalName='DM23'"
|
|
641
|
-
}]
|
|
642
|
-
}, false);
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
When the `xtkschema` attribute is set, the part after the colon (i.e. "where" in this example) will be used as the root element, effectively generating the right XML.
|
|
646
|
-
|
|
647
|
-
In our example, the `DeployTriggerMessages` will work properly regardless of the XML root of its `deliveries` parameter, so it's not needed to actually set the `xtkschema` attribute, but it's a best practice to do so, because some APIs will actually depend on receiving the right tag name.
|
|
648
|
-
|
|
649
|
-
## Error Management
|
|
650
|
-
|
|
651
|
-
If an API call fails (SOAP fault or HTTP error), a `CampaignException` object is thrown. This object contains the following attributes
|
|
652
|
-
|
|
653
|
-
* `message` a message describing the error
|
|
654
|
-
* `statusCode` a HTTP status code. In case of a SOAP fault, the status code will be 500
|
|
655
|
-
* `errorCode` the Campaign error code if one is available (ex: XSV-350013)
|
|
656
|
-
* `methodCall` the SOAP call which caused the error. It will contain the following attributes
|
|
657
|
-
* `type` the type of the API call ("SOAP" or "HTTP")
|
|
658
|
-
* `urn` the SOAP call URN, i.e. the schema id. Will be empty for HTTP methods
|
|
659
|
-
* `url` the HTTP URL
|
|
660
|
-
* `methodName` the name of the SOAP method. For HTTP methods, the query path
|
|
661
|
-
* `request` the raw SOAP request, as text. For HTTP requests, this is an option object containing details about the request
|
|
662
|
-
* `response` the raw SOAP/HTTP response, as text
|
|
663
|
-
* `faultCode` for SOAP faults, the Campaign error code
|
|
664
|
-
* `faultString` the error message
|
|
665
|
-
* `detail` optional additional details about the error
|
|
666
|
-
|
|
667
|
-
In general all errors are mapped to a CampaignException and we try to keep the semantic of errors: for instance a call with an incorrect parameter will return an HTTP stauts of 400 even if it's not actually a, HTTP call. SDK specific errors will have an errorCode with the "SDK-######" format, using "SDK" as a prefix.
|
|
668
|
-
|
|
669
|
-
```js
|
|
670
|
-
try {
|
|
671
|
-
await client.logon();
|
|
672
|
-
result = await NLWS.xtkSession.getServerTime();
|
|
673
|
-
} catch (ex) {
|
|
674
|
-
console.log(ex.message);
|
|
675
|
-
}
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
It's also noteworthy that all the data returned in a CampaignException is trimmed, i.e. session and security token values are hidden, so that the exception object can be safely logged.
|
|
679
|
-
|
|
680
|
-
## Caches
|
|
681
|
-
|
|
682
|
-
The following caches are managed by the SDK and active by default. They are in-memory caches.
|
|
683
|
-
|
|
684
|
-
* Options cache. Stores typed option values, by option name.
|
|
685
|
-
* Entity cache. Caches schemas and other entities
|
|
686
|
-
* Method cache. Cahces SOAP method definitions.
|
|
687
|
-
|
|
688
|
-
Caches can be cleared at any time
|
|
689
|
-
```js
|
|
690
|
-
client.clearOptionCache();
|
|
691
|
-
client.clearMethodCache();
|
|
692
|
-
client.clearEntityCache();
|
|
693
|
-
```
|
|
694
|
-
|
|
695
|
-
or
|
|
696
|
-
```js
|
|
697
|
-
client.clearAllCaches();
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
Caches have a TTL of 5 minutes by default. The TTL can be changed at connection time using connection options `entityCacheTTL`, `methodCacheTTL`, and `optionCacheTTL`.
|
|
701
|
-
|
|
702
|
-
Caches can be de-activated by setting a TTL of -1 which will have the effect of making all cached data always invalid.
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
## Persistent caches
|
|
707
|
-
In addition to memory caches, it is possible to use persistent caches as well. This was introduced in version 1.0.5 and is active by default as well when using the SDK in a browser. The browser local storage is used (if allowed).
|
|
708
|
-
|
|
709
|
-
Cached data is stored in local storage with keys prefixed with `acc.js.sdk.{{version}}.{{server}}.cache.` where `version` is the SDK version and `server` is the Campaign server name. This means that the cached data is lost when upgrading the SDK.
|
|
710
|
-
|
|
711
|
-
It's possible to disable persistent caches using the `noStorage` connection option.
|
|
712
|
-
|
|
713
|
-
It is also possible to setup one's own persistent cache, by passing a `storage` object as a connection option. This object should implement 3 methods: `getItem`, `setItem`, and `removeItem` (synchronous)
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
## Auto-refresh caches
|
|
717
|
-
|
|
718
|
-
The SDK includes a mechnism to maintain the schemas and options caches up-to-date by polling the Campaign server on a regular basis (10 seconds by default). The server returns the list of entities (schemas or options) which have changed since they were cached, and the client removes them from the cache. When a schema changes, the corresponding methods are also removed from the method cache.
|
|
719
|
-
|
|
720
|
-
This mechanism is not activate by default but can be activated or deactivated by the following functions
|
|
721
|
-
|
|
722
|
-
```js
|
|
723
|
-
client.startRefreshCaches(30000); // activate cache auto-refresh mechanism every 30s
|
|
724
|
-
client.stopRefreshCaches(); // de-activate cache auto-refresh
|
|
725
|
-
```
|
|
726
|
-
|
|
727
|
-
This mechanism is based on the `xtk:session#GetModifiedEntities` SOAP method which is only available in Campaign 8.4 and above only. For other builds of Campaign, the auto-refresh mechanism will not do anything.
|
|
728
|
-
|
|
729
|
-
The following changes are handled:
|
|
730
|
-
* If the build number has changed, the whole cache is cleared
|
|
731
|
-
* If more than 10 schemas or options have changed, the whole cache is cleared
|
|
732
|
-
* if less than 10 schemas or options have changed, only those entities are removed from the cache
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
The refresh mechanism includes the following guardrails
|
|
736
|
-
* Both xtk:option and xtk:schema caches are refreshed every n seconds. To avoid issuing two API calls at the same time to the server, the schema cache refresh call is delayed by a few seconds. In the future this delay may change.
|
|
737
|
-
* If the xtk:session#GetModifiedEntities API is not available, the auto refresh mechanism will silently stop automatically
|
|
738
|
-
* If an error occurs while trying to refresh, a warning will be logged to the JavaScript console but the auto refresh will not be stopped.
|
|
739
|
-
|
|
740
|
-
## Passwords
|
|
741
|
-
|
|
742
|
-
External account passwords can be decrypted using a Cipher. This function is deprecated since version 1.0.0 since it's not guaranteed to work in future versions of Campaign (V8 and above)
|
|
743
|
-
|
|
744
|
-
```js
|
|
745
|
-
const cipher = await client.getSecretKeyCipher();
|
|
746
|
-
const password = cipher.decryptPassword(encryptedPassword);
|
|
747
|
-
````
|
|
748
|
-
|
|
749
|
-
> **warning** This function is deprecated in version 1.0.0 of the SDK because it may break as we deploy Vault.
|
|
750
|
-
|
|
751
|
-
In order to set the password of an external account, you can use the `encryptPassword` API as follow
|
|
752
|
-
|
|
753
|
-
```js
|
|
754
|
-
const password = await this._client.NLWS.xtkSession.encryptPassword('password');
|
|
755
|
-
const account = {
|
|
756
|
-
xtkschema: "nms:extAccount",
|
|
757
|
-
name: name,
|
|
758
|
-
account: 'admin',
|
|
759
|
-
server: server,
|
|
760
|
-
password: password,
|
|
761
|
-
};
|
|
762
|
-
await this._client.NLWS.xtkSession.Write(account);
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
## HTTP Headers
|
|
767
|
-
|
|
768
|
-
### Out-of-the-box headers
|
|
769
|
-
In version 1.1.3 and above, the SDK will pass additional HTTP headers automatically
|
|
770
|
-
|
|
771
|
-
Header | Description
|
|
772
|
-
-------|------------
|
|
773
|
-
SOAPAction| name of the schema and SOAP method (ex: xtk:query#ExecuteQuery)
|
|
774
|
-
ACC-SDK-Version| Version of the SDK making the scores
|
|
775
|
-
ACC-SDK-Auth| Authentification type and ACC user
|
|
776
|
-
ACC-SDK-Client-App| Name of the application calling the client SDK
|
|
777
|
-
ACC-SDK-Call-RetryCount| In case an API call is retried, indicates the number of retries
|
|
778
|
-
ACC-SDK-Call-Internal| Indicates that an API call is performed byt the SDK for its own purpose
|
|
779
|
-
|
|
780
|
-
The `ACC-SDK` headers can be removed using the connection parameter `noSDKHeaders`.
|
|
781
|
-
|
|
782
|
-
### Custom HTTP headers
|
|
783
|
-
In version 1.1.3 and above, it is possible to pass additional HTTP headers or override HTTP headers set by the SDK. This can be done globally (i.e. for all API calls), or locally, i.e. just for a particular call, or both.
|
|
784
|
-
|
|
785
|
-
Http headers are passed through an object whose keys represent the header name and values the corresponding header value. Nothing particular is done in term of case sensitivity, headers will be passed as passed.
|
|
786
|
-
|
|
787
|
-
To set global HTTP headers for all API calls of a client, pass an http headers array in the connection parameters
|
|
788
|
-
```js
|
|
789
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
790
|
-
"https://myInstance.campaign.adobe.com",
|
|
791
|
-
"admin", "admin",
|
|
792
|
-
{ extraHttpHeaders: {
|
|
793
|
-
"X-ACC-JS-SDK-LBSAFE": "1",
|
|
794
|
-
"X-ACC-WEBUI-VERSION: "1.2"
|
|
795
|
-
} });
|
|
796
|
-
```
|
|
797
|
-
|
|
798
|
-
Subsequent API calls will have the corresponding headers set.
|
|
799
|
-
|
|
800
|
-
To set more HTTP headers for a particular API call, use the "headers" method of the NLWS object.
|
|
801
|
-
|
|
802
|
-
```js
|
|
803
|
-
const query = client.NLWS
|
|
804
|
-
.headers({'X-Test': 'hello'})
|
|
805
|
-
.xtkQueryDef.create(queryDef);
|
|
806
|
-
await query.executeQuery();
|
|
807
|
-
```
|
|
808
|
-
|
|
809
|
-
## Timeouts
|
|
810
|
-
|
|
811
|
-
By default, the SDK has a timeout of 5s when running in a node.js environment, and uses the browser defaults when run inside a browser (using the fetch API).
|
|
812
|
-
|
|
813
|
-
It is possible to overwrite the transport layer (see `The Transport Protocol` and use your own code to make and configure HTTP requests) to tune the timeout value. It is a bit cumbersome though.
|
|
814
|
-
|
|
815
|
-
Instead, you can use the `timeout` parameter, and set it either globally, as a connection parameter, or even at the API call level but using the `PushDown` mechanism described below.
|
|
816
|
-
|
|
817
|
-
Sets a timeout of 10s gloally
|
|
818
|
-
```js
|
|
819
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
820
|
-
"https://myInstance.campaign.adobe.com",
|
|
821
|
-
"admin", "admin",
|
|
822
|
-
{ timeout: 10000 });
|
|
823
|
-
```
|
|
824
|
-
|
|
825
|
-
Override the timeout to 1 min for a particular API call
|
|
826
|
-
```js
|
|
827
|
-
NLWS.xml.pushDown({ timeout: 60000 }).xtkBuilder.installPackage(dom);
|
|
828
|
-
```
|
|
829
|
-
|
|
830
|
-
## Pushdown mechanism
|
|
831
|
-
The Pushdown mechanism can be used to push down variables to the transport layer. A common use case it to pass a custom timeout value down to the transport layer.
|
|
832
|
-
|
|
833
|
-
The pushed down parameters are passed as a second parameter to the transport function. This parameter will contain all the connection parameters as well as any parameter that you can push down at the API call level. API call pushdowns can override default pushdowns.
|
|
834
|
-
|
|
835
|
-
Any key/value pairs can be pushed down. This example pushes down the timeout and foo variables to the transport layer.
|
|
836
|
-
```js
|
|
837
|
-
NLWS.xml.pushDown({ timeout: 60000, foo: 'bar' }).xtkBuilder.installPackage(dom);
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
## Troubleshooting
|
|
841
|
-
In the version 1.1.5 of the SDK, we are automatically adding the SOAP method name in the URL in order to simplify troubleshooting. Normally, all SOAP method calls are make to the soaprouter.jsp endpoint, which makes it difficult to understand which actual API call is being made.
|
|
842
|
-
In fact the SOAP call name is available via the SOAPAction HTTP header, but it's usually not immediatelly visible.
|
|
843
|
-
|
|
844
|
-
The SOAP calls URLs are now formed like this: `http://acc-sdk:8080/nl/jsp/soaprouter.jsp?xtk:queryDef:ExecuteQuery` where the SOAP method name is added as a query parameter. Campaign server ignores this parameter.
|
|
845
|
-
|
|
846
|
-
This can be disabled using the `noMethodInURL` connection parameter
|
|
847
|
-
|
|
848
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
849
|
-
"https://myInstance.campaign.adobe.com",
|
|
850
|
-
"admin", "admin",
|
|
851
|
-
{ noMethodInURL: true });
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
# Samples
|
|
855
|
-
|
|
856
|
-
The `samples` folder contains several samples illustrating how to use the various Campaing APIs.
|
|
857
|
-
|
|
858
|
-
A sample file looks like this
|
|
859
|
-
* It includes the `utils` library which contains a few helper functions.s
|
|
860
|
-
* It starts with an asynchronous auto-execute function that is used to run the sample from the command line
|
|
861
|
-
* This function contains one or more calls to the `utils.sample` function. Each such call describes and execute a sample.
|
|
862
|
-
* A sample file should not do anything else or have any side effect: all the actual sample code should be inside calls to `utils.sample`
|
|
863
|
-
|
|
864
|
-
| Note the use of `await` when calling `utils.sample`
|
|
865
|
-
|
|
866
|
-
```js
|
|
867
|
-
const utils = require("./utils.js");
|
|
868
|
-
( async () => {
|
|
869
|
-
await utils.sample({
|
|
870
|
-
title: "The Sample title",
|
|
871
|
-
labels: [ "xtk:queryDef", "Basics", "Query", "QueryDef", "Get" ],
|
|
872
|
-
description: `A description of the sample`,
|
|
873
|
-
code: async() => {
|
|
874
|
-
//... Sample code goes there
|
|
875
|
-
}
|
|
876
|
-
});
|
|
877
|
-
|
|
878
|
-
await utils.sample({
|
|
879
|
-
title: "A Second sample",
|
|
880
|
-
labels: [ "xtk:queryDef", "Basics", "Query", "QueryDef", "Get" ],
|
|
881
|
-
description: `A description of the sample`,
|
|
882
|
-
code: async() => {
|
|
883
|
-
//... Sample code goes there
|
|
884
|
-
}
|
|
885
|
-
});
|
|
886
|
-
})();
|
|
887
|
-
```
|
|
888
|
-
|
|
889
|
-
The `utils.sample` function takes 1 parameters describing the sample:
|
|
890
|
-
* `title` is the sample title, a short, human friendly name for the sample
|
|
891
|
-
* `labels` is a list of keywords that can be used to retreive the samples in a large list
|
|
892
|
-
* `description` is a longer, multi-line description of the sample
|
|
893
|
-
* `code` is an async function, the code of the sample
|
|
894
|
-
|
|
895
|
-
Most of the samples - actually all of them except some specific samples needing specific logon - will also use the `utils.logon` function. This is a helper function which will perform the Campaign Logon and Logoff for you, and call your callback function with pre-initialized `client` and `NLWS` objects
|
|
896
|
-
|
|
897
|
-
| Note the use of `await` when calling `utils.logon`
|
|
898
|
-
|
|
899
|
-
```js
|
|
900
|
-
await utils.sample({
|
|
901
|
-
title: "The Sample title",
|
|
902
|
-
labels: [ "xtk:queryDef", "Basics", "Query", "QueryDef", "Get" ],
|
|
903
|
-
description: `A description of the sample`,
|
|
904
|
-
code: async() => {
|
|
905
|
-
return await utils.logon(async (client, NLWS) => {
|
|
906
|
-
//... Sample code goes there
|
|
907
|
-
});
|
|
908
|
-
}
|
|
909
|
-
});
|
|
910
|
-
```
|
|
911
|
-
|
|
912
|
-
### Running samples
|
|
913
|
-
Samples can be run from the command line. First, set 3 environment variables with your instance credentials:
|
|
914
|
-
```sh
|
|
915
|
-
export ACC_URL=https://myInstance.campaign.adobe.com
|
|
916
|
-
export ACC_USERadmin
|
|
917
|
-
export ACC_PASSWORD=...
|
|
918
|
-
```
|
|
919
|
-
|
|
920
|
-
and then run the samples
|
|
921
|
-
```sh
|
|
922
|
-
node samples/000\ -\ basics\ -\ logon.js
|
|
923
|
-
````
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
# Core API
|
|
929
|
-
|
|
930
|
-
## Get option value
|
|
931
|
-
|
|
932
|
-
A convenience function is provided, which returns a typed option value.
|
|
933
|
-
```js
|
|
934
|
-
var value = await client.getOption("XtkDatabaseId");
|
|
935
|
-
```
|
|
936
|
-
|
|
937
|
-
Options are cached because they are often used. It's possible to force the reload of an option:
|
|
938
|
-
```js
|
|
939
|
-
var value = await client.getOption("XtkDatabaseId", false);
|
|
940
|
-
```
|
|
941
|
-
|
|
942
|
-
It's also possible to call the API directly.
|
|
943
|
-
Use the `xtk:session:GetOption` method to return an option value and it's type. This call will not use the option cache for returning the option value, but will still cache the result.
|
|
944
|
-
|
|
945
|
-
```js
|
|
946
|
-
const optionValueAndType = await NLWS.xtkSession.getOption("XtkDatabaseId");
|
|
947
|
-
console.log("Marketing datbaseId: " + optionValueAndType);
|
|
948
|
-
|
|
949
|
-
Marketing datbaseId: u7F00010100B52BDE,6
|
|
950
|
-
```
|
|
951
|
-
|
|
952
|
-
If the option does not exist, it will return [ "", 0 ]
|
|
953
|
-
|
|
954
|
-
```js
|
|
955
|
-
var datbaseId = await client.getOption("XtkDatabaseId");
|
|
956
|
-
console.log(datbaseId);
|
|
957
|
-
```
|
|
958
|
-
|
|
959
|
-
The cache can be cleared
|
|
960
|
-
```js
|
|
961
|
-
client.clearOptionCache();
|
|
962
|
-
```
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
## Setting options
|
|
966
|
-
|
|
967
|
-
It's also possible to set options with the `setOption` function.
|
|
968
|
-
* It will create the option if necessary
|
|
969
|
-
* If the option already exists, it will use the existing value to infer the data type of the option
|
|
970
|
-
|
|
971
|
-
```js
|
|
972
|
-
await client.setOption("MyOption", "My value");
|
|
973
|
-
```
|
|
974
|
-
|
|
975
|
-
This is really a convenience function. You can always force an option type by using a writer on the xtk:option table, and using getOption to read back and cache the result.
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
## Test if a package exists
|
|
979
|
-
* Since: 0.1.20
|
|
980
|
-
* Test if a package is installed. Expects to be connected to an instance
|
|
981
|
-
|
|
982
|
-
```js
|
|
983
|
-
var hasAmp = client.hasPackage("nms:amp");
|
|
984
|
-
```
|
|
985
|
-
|
|
986
|
-
or
|
|
987
|
-
```js
|
|
988
|
-
var hasAmp = client.hasPackage("nms", "amp");
|
|
989
|
-
```
|
|
990
|
-
|
|
991
|
-
## Creating and updating entities in Campaign
|
|
992
|
-
|
|
993
|
-
There are several possibillities to create objects in Campaign.
|
|
994
|
-
|
|
995
|
-
### Create from scratch
|
|
996
|
-
|
|
997
|
-
This first method is to create an object from scratch. It's a multi-step operation which contains the following steps
|
|
998
|
-
|
|
999
|
-
* Create an object with the "create" function. This function takes an optional parameter with the attributes you know you're going to set
|
|
1000
|
-
* Call the xtk:persist#NewInstance API which will generate a unique id, and complete your object with default values (such as default folder, etc.) depending on your role
|
|
1001
|
-
* Optionally set more attributes to override any defaults
|
|
1002
|
-
* Call save() or xtk:session#Write to create the object in the database
|
|
1003
|
-
|
|
1004
|
-
```js
|
|
1005
|
-
const delivery = client.NLWS.nmsDelivery.create({ label: "Test #1", messageType: "0" });
|
|
1006
|
-
await delivery.newInstance();
|
|
1007
|
-
delivery.$desc = "My description";
|
|
1008
|
-
await client.NLWS.xtkSession.write(delivery); // or await delivery.save();
|
|
1009
|
-
```
|
|
1010
|
-
|
|
1011
|
-
You'll notice that this method does not return anything. You may have expected this method to return the created object or some id of this object,
|
|
1012
|
-
but Campaign does not. Campaign works the other way round. You first get call NewInstance which will give the id before the object is actually saved
|
|
1013
|
-
in the database.
|
|
1014
|
-
|
|
1015
|
-
```js
|
|
1016
|
-
const delivery = client.NLWS.nmsDelivery.create({ label: "Test #1", messageType: "0" });
|
|
1017
|
-
await delivery.newInstance();
|
|
1018
|
-
// delivery.entity.id is the future id of the object in the database
|
|
1019
|
-
```
|
|
1020
|
-
|
|
1021
|
-
If you need to modify the object again after it's been created, you can use xtk:session#Write or save again, but you must tell Campaign to perform an update operation instead of an insert, or the call will probably fail or create a duplicate in the database.
|
|
1022
|
-
Make sure to read the section about the "xtk:session#Write" method below to understand how exactly objects are updated
|
|
1023
|
-
|
|
1024
|
-
```js
|
|
1025
|
-
delivery._operation = "update";
|
|
1026
|
-
delivery.$desc = "My updated description";
|
|
1027
|
-
await delivery.save();
|
|
1028
|
-
```
|
|
1029
|
-
|
|
1030
|
-
Finally, to delete the object, use xtk:session#Write or save again, this time passing it the "_operation=delete" attribute
|
|
1031
|
-
```js
|
|
1032
|
-
delivery._operation = "delete";
|
|
1033
|
-
await delivery.save();
|
|
1034
|
-
```
|
|
1035
|
-
|
|
1036
|
-
### Create by duplicating an existing object
|
|
1037
|
-
|
|
1038
|
-
Sometimes, you do not want to create objects from scratch. Instead you can copy an existing object. Campaign has a sophisticated mechanism to duplicate object and ensures that only the relevant attributes are actually set. For instance, when you dupliate a delivery which is finished, you probably want the new delivery to be in the edition state rather than in the finished state. Schema attributes having the "defOnDuplicate" property will be reset to their defaults in the duplicated object.
|
|
1039
|
-
|
|
1040
|
-
Just like the "NewInstance" API, the "xtk:persist#Duplicate" will automatically set the primary key for you. And again, it is a multi-step process.
|
|
1041
|
-
|
|
1042
|
-
* Create an object with the "create" function. This time, do no pass any parameters
|
|
1043
|
-
* Call the duplicate method, passing it the primary key of the entity you want to duplicate
|
|
1044
|
-
* Optionally set more attributes to override any defaults
|
|
1045
|
-
* Call save() or xtk:session#Write to create the object in the database
|
|
1046
|
-
|
|
1047
|
-
```js
|
|
1048
|
-
const operator = client.NLWS.xtkOperator.create();
|
|
1049
|
-
await operator.duplicate("xtk:operator|1610");
|
|
1050
|
-
operator.name = "Alex";
|
|
1051
|
-
await operator.save();
|
|
1052
|
-
```
|
|
1053
|
-
|
|
1054
|
-
The primary key format is described in the data types section of this document.
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
### Updating entities
|
|
1058
|
-
|
|
1059
|
-
Entities can be updated using the `xtk:session#Write` API. This API is very flexible and also can be used to create or delete entities or to modify multiple entites at once.
|
|
1060
|
-
|
|
1061
|
-
This method takes an unique argument which is a patch to apply. A patch has the same structure as an entity, but only contains the attributes or elements that need to be modified, created, or deleted. In addition to the value, the patch can also use the _operation property to indicate if a particular set of data needs to be inserted, updated or deleted.
|
|
1062
|
-
The patch object also must have the `xtkschema` property set to the schema id of the entity to modify.
|
|
1063
|
-
|
|
1064
|
-
For instance, one can update the email of a recipient with the following code which clearly shows the xtkschema property, the id and _operation properties to indicate that it is an update and which entity to update, and finally, the email attribute which is the only modified attribute.
|
|
1065
|
-
|
|
1066
|
-
```js
|
|
1067
|
-
client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
|
|
1068
|
-
id: "1234", _operation:"update",
|
|
1069
|
-
email: "amorin@adobe.com"
|
|
1070
|
-
});
|
|
1071
|
-
```
|
|
1072
|
-
|
|
1073
|
-
It's of course possible to pass the whole entity to an update, but this is strongly discouraged as it can have unwanted side effects in complex scenario when passed nested documents with linked objects. It's also less performant, and may overwrite data.
|
|
1074
|
-
Passing a patch (sometimes called a diff) containing only the actually modified attributes is the best practice. It also has the benefit to allow some sort of concurrent modifications as each update will onlly update the attributes actually changed.
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
### Setting foreign keys
|
|
1078
|
-
|
|
1079
|
-
It's pretty common to have to set foreign keys. For instance one want to set the folder in which a recipient is stored. The first possibility is to set the folder-id attribute directly. It's also the most efficient, but it assumes you know the foreign key in the first place.
|
|
1080
|
-
|
|
1081
|
-
```js
|
|
1082
|
-
client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
|
|
1083
|
-
xtkschema:"nms:recipient",
|
|
1084
|
-
id: 2020, _operation:"update",
|
|
1085
|
-
"folder-id": 6040
|
|
1086
|
-
});
|
|
1087
|
-
```
|
|
1088
|
-
|
|
1089
|
-
If you do not know the primary key of the folder but know its name, you can use the following syntax. It works for all collections, where items can be identified with their keys (as defined in the schemas).
|
|
1090
|
-
```js
|
|
1091
|
-
client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
|
|
1092
|
-
xtkschema:"nms:recipient",
|
|
1093
|
-
id: 1990, _operation:"update",
|
|
1094
|
-
folder: {
|
|
1095
|
-
_operation: "none",
|
|
1096
|
-
name: "test"
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
1099
|
-
```
|
|
1100
|
-
|
|
1101
|
-
Note the `operation="none"` attribute on the folder element which tells Campaign that we should not actually update the folder object itself, but to set the recipient folder instead. If you omit the _operation: "none" property, Campaign will modify both the recipient, but also the folder. It is useful in some cases, but does not make sense in this scenario.
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
### Identifying entities
|
|
1105
|
-
|
|
1106
|
-
We've had a glimpse of it but the xtk:session#Write API has several strategies to identify entities, both the top level entity but also linked entities as we've seen with the recipient folder example above.
|
|
1107
|
-
|
|
1108
|
-
* If the entity is an "autopk" entity, i.e. has autopk=true set defined in its schema, then it will have an internal primary key using the @id attribute. If the corresponding id is set in the patch document, it will be used to identify the object.
|
|
1109
|
-
* Otherwise, it will use the entity keys, as defined in the schema.
|
|
1110
|
-
|
|
1111
|
-
For instance, folders are an autopk entity and have the id attribute. They also have 2 keys: name and fullName. All 3 can be used as identifiers to update a folder label as the 3 examples below show
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
```js
|
|
1115
|
-
// Update folder by id
|
|
1116
|
-
await client.NLWS.xtkSession.write({
|
|
1117
|
-
xtkschema: "xtk:folder",
|
|
1118
|
-
_operation: "update", id: 1234,
|
|
1119
|
-
label: "Hello World",
|
|
1120
|
-
});
|
|
1121
|
-
});
|
|
1122
|
-
|
|
1123
|
-
// Update folder by name
|
|
1124
|
-
await client.NLWS.xtkSession.write({
|
|
1125
|
-
xtkschema: "xtk:folder",
|
|
1126
|
-
_operation: "update", name: "test",
|
|
1127
|
-
label: "Hello World",
|
|
1128
|
-
});
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
// Update folder by full name
|
|
1132
|
-
// This is just for example, do not use this method as the folder full name is the concatenation
|
|
1133
|
-
// of the folder label and it's parent folders labels. Changing the label will create an
|
|
1134
|
-
// inconsistency between the folder full name and its label. You can update other attributes though.
|
|
1135
|
-
await client.NLWS.xtkSession.write({
|
|
1136
|
-
xtkschema: "xtk:folder",
|
|
1137
|
-
_operation: "update", fullName: "/Profiles and Targets/Recipients/Hello/",
|
|
1138
|
-
label: "Hello World",
|
|
1139
|
-
});
|
|
1140
|
-
});
|
|
1141
|
-
```
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
### Deleting data
|
|
1145
|
-
|
|
1146
|
-
The `xtkSession#write` API can also be used to delete data using the "_operation=delete" attribute. For a delete operation, the patch should contain the xtkschema attribute, the _operation=delete attribute and an identifier of the entity.
|
|
1147
|
-
|
|
1148
|
-
For insance, a folder can be delete with
|
|
1149
|
-
|
|
1150
|
-
```js
|
|
1151
|
-
await client.NLWS.xtkSession.write({
|
|
1152
|
-
xtkschema: "xtk:folder",
|
|
1153
|
-
_operation: "delete", name: "test",
|
|
1154
|
-
});
|
|
1155
|
-
});
|
|
1156
|
-
```
|
|
1157
|
-
|
|
1158
|
-
Owned entities which are also autopk will also be deleted
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
### Setting ids
|
|
1162
|
-
|
|
1163
|
-
In the previous examples we showed how to create or update object and let Campaign generate the ids. In some cases, you'll want to explictiely set the ids upfront. To ensure uniqueness of the ids, Campaign provides an API to "reserve" ids in advane that you can use afterwards: xtk:session#GetNewIdsEx.
|
|
1164
|
-
|
|
1165
|
-
In this example, we're getting an id and creating a recipient. The id can be re-used in subsequent calls as a foreign key
|
|
1166
|
-
```js
|
|
1167
|
-
const idList = XtkCaster.asArray(await client.NLWS.xtkSession.GetNewIdsEx(1, "XtkNewId"));
|
|
1168
|
-
await client.NLWS.xtkSession.write({ xtkschema:"nms:recipient", id: idList[0], email: 'amorin@adobe.com' });
|
|
1169
|
-
```
|
|
1170
|
-
|
|
1171
|
-
Note that:
|
|
1172
|
-
* Calling GetNewIdsEx for individual ids is not efficient. It's usually better to reserve a large range of ids and insert multiple rows using those ids
|
|
1173
|
-
* Inserting data in unitary fashion with API calls is not efficient. Use data management workflows for large imports
|
|
1174
|
-
* Make sure that the NLWS.xtkSession.GetNewIdsEx returns an array by using XtkCaster.asArray(...)
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
## The xtk:jobInterface interface
|
|
1180
|
-
|
|
1181
|
-
## Connect to mid-sourcing
|
|
1182
|
-
From a marketing client connection, one can get a client to a mid server
|
|
1183
|
-
|
|
1184
|
-
```js
|
|
1185
|
-
console.log("Connecting to mid server...");
|
|
1186
|
-
const credentials = await sdk.Credentials.ofExternalAccount(client, "defaultEmailMid");
|
|
1187
|
-
const midClient = await sdk.init(credentials);
|
|
1188
|
-
|
|
1189
|
-
await midClient.client.logon();
|
|
1190
|
-
const datbaseId = await midClient.getOption("XtkDatabaseId");
|
|
1191
|
-
console.log("Mid datbaseId: " + datbaseId);
|
|
1192
|
-
await midClient.NLWS.xtkSession.testCnx();
|
|
1193
|
-
console.log("Disconnecting from mid");
|
|
1194
|
-
await midClient.client.logoff();
|
|
1195
|
-
```
|
|
1196
|
-
|
|
1197
|
-
## Health check
|
|
1198
|
-
Campaign proposes several APIs for health check. Just like all APIs in the SDK, it's been wrapped into a function and will return a XML or JSON object depending on the current representation
|
|
1199
|
-
|
|
1200
|
-
### /r/test
|
|
1201
|
-
This API is anonymous and run directly on the Apache front server. Note that this API will failed if called on a tomcat endpoint (port 8080)
|
|
1202
|
-
```js
|
|
1203
|
-
const test = await client.test();
|
|
1204
|
-
```
|
|
1205
|
-
|
|
1206
|
-
will return
|
|
1207
|
-
```json
|
|
1208
|
-
{
|
|
1209
|
-
"status":"OK",
|
|
1210
|
-
"date":"2021-08-27 03:06:02.941-07",
|
|
1211
|
-
"build":"9236",
|
|
1212
|
-
"sha1":"cc45440",
|
|
1213
|
-
"instance":"xxx_mkt_prod1",
|
|
1214
|
-
"sourceIP":"193.104.215.11",
|
|
1215
|
-
"host":"xxx.campaign.adobe.com",
|
|
1216
|
-
"localHost":"xxx-mkt-prod1-1"
|
|
1217
|
-
}
|
|
1218
|
-
```
|
|
1219
|
-
|
|
1220
|
-
Note: as this API is anonymous, one does not need to actually log on to Campaign to call it. Here's a full example. See the authentication section for more details about anonymous logon.
|
|
1221
|
-
```js
|
|
1222
|
-
const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("https://...");
|
|
1223
|
-
const client = await sdk.init(connectionParameters);
|
|
1224
|
-
const test = await client.test();
|
|
1225
|
-
```
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
### ping
|
|
1229
|
-
The ping API is authenticated and will return a simple status code indicating the the Campaign server is running. It will also return the current database timestamp. The API itself will return plain text, but for convenience this has been wrapped into JSON / XML in the SDK
|
|
1230
|
-
```js
|
|
1231
|
-
const ping = await client.ping();
|
|
1232
|
-
```
|
|
1233
|
-
|
|
1234
|
-
will return
|
|
1235
|
-
```json
|
|
1236
|
-
{
|
|
1237
|
-
"status":"Ok",
|
|
1238
|
-
"timestamp":"2021-08-27 12:51:56.088Z"
|
|
1239
|
-
}
|
|
1240
|
-
```
|
|
1241
|
-
|
|
1242
|
-
### mcPing
|
|
1243
|
-
Message Center instances have a dedicated ping API which also returns the Message Center queue size and the maximum expected size (threshold). The API itself will return plain text, but for convenience this has been wrapped into JSON / XML in the SDK
|
|
1244
|
-
```js
|
|
1245
|
-
const ping = await client.mcPing();
|
|
1246
|
-
```
|
|
1247
|
-
|
|
1248
|
-
will return
|
|
1249
|
-
```json
|
|
1250
|
-
{
|
|
1251
|
-
"status":"Ok",
|
|
1252
|
-
"timestamp":"2021-08-27 12:51:56.088Z",
|
|
1253
|
-
"eventQueueSize":"7",
|
|
1254
|
-
"eventQueueMaxSize":"400"
|
|
1255
|
-
}
|
|
1256
|
-
```
|
|
1257
|
-
|
|
1258
|
-
## The Transport Protocol
|
|
1259
|
-
|
|
1260
|
-
The SDK uses `axios` library internally to perform HTTP calls. This can be customized and one can use any other (async) protocol, which is implemented in the `transport.js` file.
|
|
1261
|
-
The transport protocol defines
|
|
1262
|
-
- What is an HTTP request
|
|
1263
|
-
- What is the corresponding response
|
|
1264
|
-
- How errors are handled
|
|
1265
|
-
|
|
1266
|
-
The transport protocol exports a single asynchronous function `request` which takes two parameters.
|
|
1267
|
-
|
|
1268
|
-
The first parameter is the request object with the following attributes. Note that it matches axios requests.
|
|
1269
|
-
* `method` is the HTTP verb
|
|
1270
|
-
* `url` is the URL to call
|
|
1271
|
-
* `headers` is an object containing key value pairs with http headers and their values
|
|
1272
|
-
* `data` is the request payload
|
|
1273
|
-
|
|
1274
|
-
The second parameter is an set of additional parameters that have been pushed down to the transport layer (see the `Pushdown` paragraph for more details). In particular, the `timeout` parameter should be honored by the transport layer.
|
|
1275
|
-
|
|
1276
|
-
If the request is successful, a promise is returned with the result payload, as a string.
|
|
1277
|
-
|
|
1278
|
-
If the request fails, the promise is rejected with an error object with class `HttpError`, a litteral with the following attributes:
|
|
1279
|
-
* `statusCode` is the HTTP status code, such as 404, 500, etc.
|
|
1280
|
-
* `statusText` is the HTTP status text coming with the error
|
|
1281
|
-
* `data` is the response data, if any
|
|
1282
|
-
|
|
1283
|
-
For proper error handling by the ACC SDK, it's important that the actual class of returned objects is named "HttpError"
|
|
1284
|
-
|
|
1285
|
-
The transport can be overriden by using the `client.setTransport` call and passing it a transport function, i.e. an async function which
|
|
1286
|
-
* Takes a `Request` object litteral as a parameter
|
|
1287
|
-
* Returns a the request result in a promise
|
|
1288
|
-
* Returns a rejected promise containing an `HttpError` in case of failure
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
## Observers
|
|
1292
|
-
|
|
1293
|
-
The Campaign client implements an observer mechanism that you can use to hook into what's hapenning internally.
|
|
1294
|
-
|
|
1295
|
-
An `Observer` is an object having any of the following methods:
|
|
1296
|
-
|
|
1297
|
-
For SOAP calls
|
|
1298
|
-
* onSOAPCall(soapCall, safeCallData)
|
|
1299
|
-
* onSOAPCallSuccess(soapCall, safeCallResponse) {}
|
|
1300
|
-
* onSOAPCallFailure(soapCall, exception) {}
|
|
1301
|
-
|
|
1302
|
-
For HTTP calls (such as JSP, JSSP...). Note that despite SOAP calls are also HTTP calls, the following callbacks will not be called for SOAP calls.
|
|
1303
|
-
* onHTTPCall(request, safeCallData)
|
|
1304
|
-
* onHTTPCallSuccess(request, safeCallResponse) {}
|
|
1305
|
-
* onHTTPCallFailure(request, exception) {}
|
|
1306
|
-
|
|
1307
|
-
The `soapCall` parameter is the SOAP call which is being observed. In the `onSOAPCall` callback, the SOAP call has not been executed yet.
|
|
1308
|
-
|
|
1309
|
-
The `request` parameter is the HTTP request (as defined in the transport protocol above)
|
|
1310
|
-
|
|
1311
|
-
The `safeCallData` and `safeCallResponse` represent the text XML of the SOAP request and response, but in which all session and security tokens have been replaced with "***" string. Hence the name "safe". You should use those parameters for any logging purpose to avoid leaking credentials.
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
The `soapCall` parameter is a `SoapMethodCall` object which describes the SOAP call. It has the following public attributes.
|
|
1315
|
-
|
|
1316
|
-
* `urn` is the SOAP URN which corresponds to the Campaign schema id. For instance "xtk:session"
|
|
1317
|
-
* `methodName` is the name of the method to call. For instance "Logon"
|
|
1318
|
-
* `internal` is true or false, depending if the SOAP call is an internal SOAP call performed by the framework itself, or if it's a SOAP call issued by a SDK user
|
|
1319
|
-
* `request` is a literal corresponding to the HTTP request. It's compatible with the `transport` protocol. It may be undefined if the SOAP call has need been completely built
|
|
1320
|
-
* `response` is a string containing the XML result of the SOAP call if the call was successful. It may be undefined if the call was not executed yet or if the call failed
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
In version 1.1.7, the observer interface is extended to listen for internal events of the SDK. The `event` function of the observer, if it exist will be call for each SDK event with 2 parameters: the event itself, and for some events, a parent event. For instance a SOAP response event will have the SOAP request for a parent event.
|
|
1324
|
-
```js
|
|
1325
|
-
client.registerObserver({
|
|
1326
|
-
event: (event, parentEvent) => { ... },
|
|
1327
|
-
});
|
|
1328
|
-
```
|
|
1329
|
-
|
|
1330
|
-
The following events are available
|
|
1331
|
-
|
|
1332
|
-
| event name | comment / description |
|
|
1333
|
-
|----|----|
|
|
1334
|
-
| SDK//logon | A client logs on |
|
|
1335
|
-
| SDK//logoff | A client logs off |
|
|
1336
|
-
| CACHE//stats | Regularly sends stats about internal caches |
|
|
1337
|
-
| SOAP//request | The SDK executes a SOAP request |
|
|
1338
|
-
| SOAP//response | The SDK processes the successful response of a SOAP request |
|
|
1339
|
-
| SOAP//failure | A SOAP request failed |
|
|
1340
|
-
| HTTP//request | The SDK executes an HTTP request |
|
|
1341
|
-
| HTTP//response | The SDK processes the successful response of an HTTP request |
|
|
1342
|
-
| HTTP//failure | An HTTP request failed |
|
|
1343
|
-
| CACHE_REFRESHER//start | A cache auto-refresher starts |
|
|
1344
|
-
| CACHE_REFRESHER//stop | A cache auto-refresher stops |
|
|
1345
|
-
| CACHE_REFRESHER//tick | A cache auto-refresh occurs |
|
|
1346
|
-
| CACHE_REFRESHER//loggedOff | The cache auto-refresh was triggered whereas the client was logged off |
|
|
1347
|
-
| CACHE_REFRESHER//error | The cache auto-refresh failed. Auto-refresh will continue. |
|
|
1348
|
-
| CACHE_REFRESHER//abort | The cache auto-refresh failed because the server does not support it. Auto-refresh will stop. |
|
|
1349
|
-
| CACHE_REFRESHER//response | The server responded to an auto-refresh request |
|
|
1350
|
-
|
|
1351
|
-
# Configuration
|
|
1352
|
-
|
|
1353
|
-
## Tracking all SOAP calls
|
|
1354
|
-
|
|
1355
|
-
SOAP calls can be logged by setting the `traceAPICalls` attribute on the client at any time. For security reasons, the security and session tokens values will be replaced by "***" to avoid leaking them
|
|
1356
|
-
|
|
1357
|
-
```js
|
|
1358
|
-
client.traceAPICalls(true);
|
|
1359
|
-
```
|
|
1360
|
-
|
|
1361
|
-
This is an example of the logs
|
|
1362
|
-
````
|
|
1363
|
-
SOAP//request xtk:session#GetOption <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
|
1364
|
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
1365
|
-
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
|
|
1366
|
-
xmlns:ns="http://xml.apache.org/xml-soap">
|
|
1367
|
-
<SOAP-ENV:Header>
|
|
1368
|
-
<Cookie>__sessiontoken=***</Cookie>
|
|
1369
|
-
<X-Security-Token>***</X-Security-Token>
|
|
1370
|
-
</SOAP-ENV:Header>
|
|
1371
|
-
<SOAP-ENV:Body>
|
|
1372
|
-
<m:GetOption xmlns:m="urn:xtk:session" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
|
1373
|
-
<sessiontoken xsi:type="xsd:string">***</sessiontoken>
|
|
1374
|
-
<name xsi:type="xsd:string">XtkDatabaseId</name>
|
|
1375
|
-
</m:GetOption>
|
|
1376
|
-
</SOAP-ENV:Body>
|
|
1377
|
-
</SOAP-ENV:Envelope>
|
|
1378
|
-
|
|
1379
|
-
SOAP//response xtk:session#GetOption <?xml version='1.0'?>
|
|
1380
|
-
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema'
|
|
1381
|
-
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
|
|
1382
|
-
xmlns:ns='urn:xtk:session'
|
|
1383
|
-
xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
1384
|
-
<SOAP-ENV:Body>
|
|
1385
|
-
<GetOptionResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
|
|
1386
|
-
<pstrValue xsi:type='xsd:string'>uFE80000000000000F1FA913DD7CC7C4804BA419F</pstrValue>
|
|
1387
|
-
<pbtType xsi:type='xsd:byte'>6</pbtType>
|
|
1388
|
-
</GetOptionResponse>
|
|
1389
|
-
</SOAP-ENV:Body>
|
|
1390
|
-
</SOAP-ENV:Envelope>
|
|
1391
|
-
`````
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
# Query API
|
|
1395
|
-
|
|
1396
|
-
List all accounts
|
|
1397
|
-
````
|
|
1398
|
-
const queryDef = {
|
|
1399
|
-
schema: "nms:extAccount",
|
|
1400
|
-
operation: "select",
|
|
1401
|
-
select: {
|
|
1402
|
-
node: [
|
|
1403
|
-
{ expr: "@id" },
|
|
1404
|
-
{ expr: "@name" }
|
|
1405
|
-
]
|
|
1406
|
-
}
|
|
1407
|
-
};
|
|
1408
|
-
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
1409
|
-
|
|
1410
|
-
console.log(query);
|
|
1411
|
-
const extAccounts = await query.executeQuery();
|
|
1412
|
-
console.log(JSON.stringify(extAccounts));
|
|
1413
|
-
````
|
|
1414
|
-
|
|
1415
|
-
Get a single record
|
|
1416
|
-
```js
|
|
1417
|
-
var queryDef = {
|
|
1418
|
-
schema: "nms:extAccount",
|
|
1419
|
-
operation: "get",
|
|
1420
|
-
select: {
|
|
1421
|
-
node: [
|
|
1422
|
-
{ expr: "@id" },
|
|
1423
|
-
{ expr: "@name" },
|
|
1424
|
-
{ expr: "@label" },
|
|
1425
|
-
{ expr: "@type" },
|
|
1426
|
-
{ expr: "@account" },
|
|
1427
|
-
{ expr: "@password" },
|
|
1428
|
-
{ expr: "@server" },
|
|
1429
|
-
{ expr: "@provider" },
|
|
1430
|
-
]
|
|
1431
|
-
},
|
|
1432
|
-
where: {
|
|
1433
|
-
condition: [
|
|
1434
|
-
{ expr: "@name='ffda'" }
|
|
1435
|
-
]
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
1439
|
-
const extAccount = await query.executeQuery();
|
|
1440
|
-
```
|
|
1441
|
-
|
|
1442
|
-
## Escaping
|
|
1443
|
-
It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded "ffda" name. The `expr` attribute takes an XTK expression as a parameter, and 'ffda' is a string litteral in an xtk expression.
|
|
1444
|
-
|
|
1445
|
-
To prevent xtk ingestions vulnerabilities, you should not concatenate strings and write code such as expr: "@name = '" + name + "'": if the value of the name
|
|
1446
|
-
parameter contains single quotes, your code will not work, but could also cause vulnerabilities.
|
|
1447
|
-
|
|
1448
|
-
### sdk.escapeXtk
|
|
1449
|
-
|
|
1450
|
-
The `sdk.escapeXtk` can be used to properly escape string litterals in xtk expressions. The function will also surround the escaped value with single quotes.
|
|
1451
|
-
|
|
1452
|
-
You can use string concatenation like this. Note the lack of single quotes around the value.
|
|
1453
|
-
```
|
|
1454
|
-
{ expr: "@name=" + sdk.escapeXtk(name) }
|
|
1455
|
-
```
|
|
1456
|
-
|
|
1457
|
-
or a template litteral
|
|
1458
|
-
```
|
|
1459
|
-
`{ expr: "@name=${sdk.escapeXtk(name)}" }`
|
|
1460
|
-
```
|
|
1461
|
-
|
|
1462
|
-
The `escapeXtk` function can also be used to create tagged string litterals. This leads to a much shorter syntax. Note that with this syntax, only the parameter values of the template litteral are escaped
|
|
1463
|
-
```
|
|
1464
|
-
sdk.escapeXtk`{ expr: "@name=${name}" }`
|
|
1465
|
-
```
|
|
1466
|
-
|
|
1467
|
-
This can also be used to escape other data types such as timestamps
|
|
1468
|
-
|
|
1469
|
-
```
|
|
1470
|
-
sdk.escapeXtk`{ expr: "@lastModified > = ${yesterday}" }`
|
|
1471
|
-
```
|
|
1472
|
-
|
|
1473
|
-
will return `{ expr: "@lastModified > = #2021-07-07T10:03:33.332Z# }`
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
### sdk.escapeForLike
|
|
1477
|
-
|
|
1478
|
-
This function escapes values so that they can be used in SQL or XTK like conditions. For example a search term "term" can be escaped as follows to implement a search conditions
|
|
1479
|
-
|
|
1480
|
-
```
|
|
1481
|
-
expr: `Lower([${xpath}]) LIKE '%${sdk.escapeForLike(term)}%'`,
|
|
1482
|
-
```
|
|
1483
|
-
|
|
1484
|
-
### sdk.expandXPath & sdk.unexpandXPath
|
|
1485
|
-
|
|
1486
|
-
In Campaign, xpaths are used to access attributes of entities. When XPaths are used in XTK expressions, there can be ambiguities, for instance, in the expression "country/@name", is "country/@name" a xpath or are we dividing the variable country by the value of the attribute @name?
|
|
1487
|
-
|
|
1488
|
-
Amibiguity can be resolved by "expanding" the xpath from "country/@name" to "[country/@name]". The square brackets indicate an xpath.
|
|
1489
|
-
|
|
1490
|
-
```
|
|
1491
|
-
const expandedXPath = sdk.expandXPath(xpath);
|
|
1492
|
-
const unexpandedXPath = sdk.unexpandXPath(expandedXPath);
|
|
1493
|
-
```
|
|
1494
|
-
|
|
1495
|
-
### xtkConstText
|
|
1496
|
-
|
|
1497
|
-
This function allows to convert literal values to xtk text constants, providing correct serialization. For instance, text constants will be quoted with single quotes, timestamps with the "#" character, etc.
|
|
1498
|
-
|
|
1499
|
-
```
|
|
1500
|
-
expect(sdk.xtkConstText("Hello", "string")).toBe("'Hello'");
|
|
1501
|
-
expect(sdk.xtkConstText(-42.3, "double")).toBe("-42.3");
|
|
1502
|
-
expect(sdk.xtkConstText("2022-02-15T09:49:04.000Z", "datetime")).toBe("#2022-02-15T09:49:04.000Z#");
|
|
1503
|
-
```
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
## Pagination
|
|
1507
|
-
Results can be retrieved in different pages, using the `@lineCount` and `@startLine` attributes. For instance, retrieves profiles 3 and 4 (skip 1 and 2)
|
|
1508
|
-
|
|
1509
|
-
```js
|
|
1510
|
-
var queryDef = {
|
|
1511
|
-
schema: "nms:recipient",
|
|
1512
|
-
operation: "select",
|
|
1513
|
-
lineCount: 2,
|
|
1514
|
-
startLine: 2,
|
|
1515
|
-
select: {
|
|
1516
|
-
node: [
|
|
1517
|
-
{ expr: "@id" },
|
|
1518
|
-
{ expr: "@email" }
|
|
1519
|
-
]
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
var query = NLWS.xtkQueryDef.create(queryDef);
|
|
1523
|
-
var recipients = await query.executeQuery();
|
|
1524
|
-
console.log(JSON.stringify(recipients));
|
|
1525
|
-
```
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
# Writer API
|
|
1530
|
-
|
|
1531
|
-
Creates an image (data is base64 encoded)
|
|
1532
|
-
```js
|
|
1533
|
-
var data = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA9ElEQVQ4jaXTIUsFQRSG4eeKiBjEIBeDYDGoSUwGm81s8SdYtIhFhPMDbEaz/SIIZkGbWg1Gg0GwiIgYZPZuWBxn8bJvWXb2O+/scM70lAhjuMO1sF9IVaES61jFnjBbyLQKjurnJz6yr62CsI2t+m0gRhGERZw1Vk6zTFEQ+rjETOP3b7OqBr1G8SRusPYrc4I3LGCeapN37AqP443g8R/FiYNsZcgGSRCmq1ZxmEXa6Yt0hKh6/dAaLbOcd+H/XOGpi2AFU10EqWsTXQQ7wmsSPNdzP8DXCII0D41BSgxvXboHm1jCXDpnPbHfeME9znEh+AFoTyfEnWJgLQAAAABJRU5ErkJggg==";
|
|
1534
|
-
var doc = {
|
|
1535
|
-
xtkschema: "xtk:image",
|
|
1536
|
-
_operation: "insert",
|
|
1537
|
-
namespace: "cus",
|
|
1538
|
-
name: "test.png",
|
|
1539
|
-
label: "Self test",
|
|
1540
|
-
type: "png",
|
|
1541
|
-
$data: data
|
|
1542
|
-
};
|
|
1543
|
-
await NLWS.xtkSession.write(doc);
|
|
1544
|
-
````
|
|
1545
|
-
|
|
1546
|
-
Creates a folder (with image previously created)
|
|
1547
|
-
```js
|
|
1548
|
-
const folder = {
|
|
1549
|
-
xtkschema: "xtk:folder",
|
|
1550
|
-
_operation: "insert",
|
|
1551
|
-
parent-id: 1167,
|
|
1552
|
-
name: "testSDK",
|
|
1553
|
-
label: "Test SDK",
|
|
1554
|
-
entity: "xtk:folder",
|
|
1555
|
-
schema: "xtk:folder",
|
|
1556
|
-
model: "xtkFolder",
|
|
1557
|
-
"image-namespace": "cus",
|
|
1558
|
-
"image-name": "test.png"
|
|
1559
|
-
};
|
|
1560
|
-
await NLWS.xtkSession.write(folder);
|
|
1561
|
-
````
|
|
1562
|
-
|
|
1563
|
-
Some objects, such as deliveries are created from templates. The `createFromModel` API is preferred in this case. Given a template name, and a patch object, it will return an object created from the template and the patch, applying all sort of business rules and default values. This object can be inserted using a writer.
|
|
1564
|
-
|
|
1565
|
-
In this example, an email delivery is created from the "mail" delivery template and it's label is set to "Hello".
|
|
1566
|
-
|
|
1567
|
-
Note the xtkschema attribute in the second parameter of the `createFromModel` API call which is needed for the SDK to perform the proper JSON to XML transformation.
|
|
1568
|
-
|
|
1569
|
-
```js
|
|
1570
|
-
const mail = await client.NLWS.nmsDelivery.createFromModel('mail', { xtkschema:'nms:delivery', label:'Hello'});
|
|
1571
|
-
await client.NLWS.xtkSession.write(mail);
|
|
1572
|
-
````
|
|
1573
|
-
|
|
1574
|
-
# Workflow API
|
|
1575
|
-
|
|
1576
|
-
Start and stop wotkflows, passing either an id or workflow internal name
|
|
1577
|
-
```js
|
|
1578
|
-
await NLWS.xtkWorkflow.stop(4900);
|
|
1579
|
-
await NLWS.xtkWorkflow.start(4900);
|
|
1580
|
-
```
|
|
1581
|
-
|
|
1582
|
-
A workflow can be started with parameters. Variables, are passed as attributes of the parameters document.
|
|
1583
|
-
```js
|
|
1584
|
-
await NLWS.xtkWorkflow.startWithParameters(4900, { hello: "world" });
|
|
1585
|
-
```
|
|
1586
|
-
|
|
1587
|
-
The variables can be used in the workflow as attributes of the `instance.vars` variable.
|
|
1588
|
-
|
|
1589
|
-
```js
|
|
1590
|
-
logInfo(instance.vars.hello);
|
|
1591
|
-
```
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
# Profiles and subscriptions
|
|
1596
|
-
|
|
1597
|
-
Create a recipient
|
|
1598
|
-
```js
|
|
1599
|
-
var recipient = {
|
|
1600
|
-
xtkschema: "nms:recipient",
|
|
1601
|
-
_operation: "insert",
|
|
1602
|
-
firstName: "Thomas",
|
|
1603
|
-
lastName: "Jordy",
|
|
1604
|
-
email: "jordy@adobe.com"
|
|
1605
|
-
};
|
|
1606
|
-
await NLWS.xtkSession.write(recipient);
|
|
1607
|
-
```
|
|
1608
|
-
|
|
1609
|
-
Create multiple recipients
|
|
1610
|
-
```js
|
|
1611
|
-
var recipients = {
|
|
1612
|
-
xtkschema: "nms:recipient",
|
|
1613
|
-
recipient: [
|
|
1614
|
-
{
|
|
1615
|
-
_operation: "insert",
|
|
1616
|
-
firstName: "Christophe",
|
|
1617
|
-
lastName: "Protat",
|
|
1618
|
-
email: "protat@adobe.com"
|
|
1619
|
-
},
|
|
1620
|
-
{
|
|
1621
|
-
_operation: "insert",
|
|
1622
|
-
firstName: "Eric",
|
|
1623
|
-
lastName: "Perrin",
|
|
1624
|
-
email: "perrin@adobe.com"
|
|
1625
|
-
}
|
|
1626
|
-
]
|
|
1627
|
-
};
|
|
1628
|
-
await NLWS.xtkSession.writeCollection(recipients);
|
|
1629
|
-
```
|
|
1630
|
-
|
|
1631
|
-
List all recipients in Adobe
|
|
1632
|
-
```js
|
|
1633
|
-
var queryDef = {
|
|
1634
|
-
schema: "nms:recipient",
|
|
1635
|
-
operation: "select",
|
|
1636
|
-
select: {
|
|
1637
|
-
node: [
|
|
1638
|
-
{ expr: "@id" },
|
|
1639
|
-
{ expr: "@firstName" },
|
|
1640
|
-
{ expr: "@lastName" },
|
|
1641
|
-
{ expr: "@email" }
|
|
1642
|
-
]
|
|
1643
|
-
},
|
|
1644
|
-
where: {
|
|
1645
|
-
condition: [
|
|
1646
|
-
{ expr: "GetEmailDomain(@email)='adobe.com'" }
|
|
1647
|
-
]
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
1651
|
-
var recipients = await query.executeQuery();
|
|
1652
|
-
console.log(JSON.stringify(recipients));
|
|
1653
|
-
```
|
|
1654
|
-
|
|
1655
|
-
Count total number of profiles
|
|
1656
|
-
```js
|
|
1657
|
-
var queryDef = {
|
|
1658
|
-
schema: "nms:recipient",
|
|
1659
|
-
operation: "count"
|
|
1660
|
-
}
|
|
1661
|
-
var query = NLWS.xtkQueryDef.create(queryDef);
|
|
1662
|
-
var count = await query.executeQuery();
|
|
1663
|
-
count = XtkCaster.asLong(count.count);
|
|
1664
|
-
console.log(count);
|
|
1665
|
-
```
|
|
1666
|
-
|
|
1667
|
-
Update a profile. In this case, use the "@email" attribute as a key. If the `@_key` attribute is not specified, the primary key will be used.
|
|
1668
|
-
```js
|
|
1669
|
-
var recipient = {
|
|
1670
|
-
xtkschema: "nms:recipient",
|
|
1671
|
-
_key: "@email",
|
|
1672
|
-
_operation: "update",
|
|
1673
|
-
firstName: "Alexandre",
|
|
1674
|
-
email: "amorin@adobe.com"
|
|
1675
|
-
};
|
|
1676
|
-
await NLWS.xtkSession.write(recipient);
|
|
1677
|
-
```
|
|
1678
|
-
|
|
1679
|
-
Deletes a profile
|
|
1680
|
-
```js
|
|
1681
|
-
var recipient = {
|
|
1682
|
-
xtkschema: "nms:recipient",
|
|
1683
|
-
_key: "@email",
|
|
1684
|
-
_operation: "delete",
|
|
1685
|
-
email: "amorin@adobe.com"
|
|
1686
|
-
};
|
|
1687
|
-
await NLWS.xtkSession.write(recipient);
|
|
1688
|
-
```
|
|
1689
|
-
|
|
1690
|
-
Deletes a set of profiles, based on condition. For instance delete everyone having an email address in adobe.com domain
|
|
1691
|
-
```js
|
|
1692
|
-
await NLWS.xtkSession.deleteCollection("nms:recipient", { condition: { expr: "GetEmailDomain(@email)='adobe.com'"} });
|
|
1693
|
-
```
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
# Message Center
|
|
1697
|
-
|
|
1698
|
-
The Message Center API (`nms:rtEvent#PushEvent`) can be used to send transactional messages. It should be called on the Message Center execution instances, not on the marketing instances.
|
|
1699
|
-
|
|
1700
|
-
## Authentication
|
|
1701
|
-
Two authentication mechanism are possible for Message Center. It is possible to use a user/password authentication and call the Logon method to get a session and security token, as all other APIs. When using this authentication mechanism, the caller is responsible to handle token expiration and must explicitely handle the case when the Message Center API call fails because of an expired token.
|
|
1702
|
-
|
|
1703
|
-
Another common authentication strategy is to define a trusted Security Zone for message center clients and setup this security zone to use the "user/password" as a session token.
|
|
1704
|
-
|
|
1705
|
-
Here's an example of authentication with this method
|
|
1706
|
-
```js
|
|
1707
|
-
const connectionParameters = sdk.ConnectionParameters.ofSessionToken(url, "mc/mc");
|
|
1708
|
-
const client = await sdk.init(connectionParameters);
|
|
1709
|
-
```
|
|
1710
|
-
|
|
1711
|
-
## Pushing events
|
|
1712
|
-
|
|
1713
|
-
Events can be pushed using the `nms:rtEvent#PushEvent` API call. For instance
|
|
1714
|
-
```js
|
|
1715
|
-
var result = await NLWS.nmsRtEvent.pushEvent({
|
|
1716
|
-
wishedChannel: 0,
|
|
1717
|
-
type: "welcome",
|
|
1718
|
-
email: "aggmorin@gmail.com",
|
|
1719
|
-
ctx: {
|
|
1720
|
-
$title: "Alex"
|
|
1721
|
-
}
|
|
1722
|
-
});
|
|
1723
|
-
console.log(`>> Result: ${result}`);
|
|
1724
|
-
```
|
|
1725
|
-
|
|
1726
|
-
There are a couple of noteworthy things to say about this API when using SimpleJson serialization.
|
|
1727
|
-
|
|
1728
|
-
* The payload passed to the pushEvent API call is actuall a nms:rtEvent entity. Hence the wishedChannel, etc. are actually XML attributes. The default SimpleJson conversion works fine here, no need to prefix the attributes with the "@" sign.
|
|
1729
|
-
* However, the `ctx` section is not structured. We do not have a schema to validate or guide the conversion. It is common to use XML elements instead of attributes in the ctx context. In the message center template, you'll find things like `<%= rtEvent.ctx.title %>`. The fact that "title" is used (in stead of "@title") implied that the ctx node will contain a title element, not a title attribute. For the SimpleJson conversion to work, it's therefore important to indicate "$title" as the JSON attribute name. This will guide the SimpleJson converted to use an XML element instead of an XML attribute
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
## Getting event status
|
|
1733
|
-
|
|
1734
|
-
There's no scalable API to get the status of a message center event. One can use the QueryDef API to query the nms:rtEvent table for testing purpose though.
|
|
1735
|
-
|
|
1736
|
-
To do so, the first step is to decode the event id returned by PushEvent. It is a 64 bit number, whose high byte is the message center cell (instance) id which handled the event. It's a number between 0 and 255. The lower bytes represent the primary key of the event. Note that this is subject to change in future versions of Campaign and should not be considered stable.
|
|
1737
|
-
|
|
1738
|
-
Clear high byte
|
|
1739
|
-
```js
|
|
1740
|
-
eventId = Number(BigInt(eventId) & BigInt("0xFFFFFFFFFFFFFF"));
|
|
1741
|
-
```
|
|
1742
|
-
|
|
1743
|
-
Get event status
|
|
1744
|
-
```js
|
|
1745
|
-
var queryDef = {
|
|
1746
|
-
schema: "nms:rtEvent",
|
|
1747
|
-
operation: "get",
|
|
1748
|
-
select: {
|
|
1749
|
-
node: [
|
|
1750
|
-
{ expr: "@id" },
|
|
1751
|
-
{ expr: "@status" },
|
|
1752
|
-
{ expr: "@created" },
|
|
1753
|
-
{ expr: "@processing" },
|
|
1754
|
-
{ expr: "@processed" }
|
|
1755
|
-
]
|
|
1756
|
-
},
|
|
1757
|
-
where: {
|
|
1758
|
-
condition: [
|
|
1759
|
-
{ expr:`@id=${eventId}` }
|
|
1760
|
-
]
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
query = NLWS.xtkQueryDef.create(queryDef);
|
|
1764
|
-
var event = await query.executeQuery();
|
|
1765
|
-
console.log(`>> Event: ${JSON.stringify(event)}`);
|
|
1766
|
-
```
|
|
1767
|
-
|
|
1768
|
-
# Application
|
|
1769
|
-
|
|
1770
|
-
The `application` object can be obtained from a client, and will mimmic the Campaing `application` object (https://docs.adobe.com/content/help/en/campaign-classic/technicalresources/api/c-Application.html)
|
|
1771
|
-
|
|
1772
|
-
| Attribute/Method | Description |
|
|
1773
|
-
|---|---|
|
|
1774
|
-
| **buildNumber** | The server build number
|
|
1775
|
-
| **version** | In SDK version 1.1.4 and above, returns the server version formatted as major.minor.servicePack (ex: 8.2.10)
|
|
1776
|
-
| **instanceName** | The name of the Campaign instance
|
|
1777
|
-
| **operator** | Information about the current operator (i.e. logged user), of class `CurrentLogin`
|
|
1778
|
-
| **packages** | List of installed packages, as an array of strings
|
|
1779
|
-
| async **getSchema**(schemaId) | Get a schema by id (see the Schemas section below)
|
|
1780
|
-
| async **getEnumeration**(enumerationName, schemaOrSchemaId) | Get an enumeration
|
|
1781
|
-
| **hasPackage**(name) | Tests if a package is installed or not
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
The `CurrentLogin` object has the following attributes / functions
|
|
1785
|
-
|
|
1786
|
-
| Attribute/Method | Description |
|
|
1787
|
-
|---|---|
|
|
1788
|
-
| **id** | the internal id (int32) of the operator
|
|
1789
|
-
| **login** | the login name of the operator
|
|
1790
|
-
| **computeString** | A human readable name for the operator
|
|
1791
|
-
| **timezone** | The timezone of the operator
|
|
1792
|
-
| **rights** | An array of strings describing the rights of the operators
|
|
1793
|
-
|
|
1794
|
-
# Schemas
|
|
1795
|
-
|
|
1796
|
-
Reading schemas is a common operation in Campaign. The SDK provides a convenient functions as well as caching for efficient use of schemas.
|
|
1797
|
-
|
|
1798
|
-
```js
|
|
1799
|
-
const schema = await client.getSchema("nms:recipient");
|
|
1800
|
-
console.log(JSON.stringify(schema));
|
|
1801
|
-
```
|
|
1802
|
-
|
|
1803
|
-
A given representation can be forced
|
|
1804
|
-
```js
|
|
1805
|
-
const xmlSchema = await client.getSchema("nms:recipient", "xml");
|
|
1806
|
-
const jsonSchema = await client.getSchema("nms:recipient", "SimpleJson");
|
|
1807
|
-
```
|
|
1808
|
-
|
|
1809
|
-
System enumerations can also be retreived with the fully qualified enumeration name
|
|
1810
|
-
```js
|
|
1811
|
-
const sysEnum = await client.getSysEnum("nms:extAccount:encryptionType");
|
|
1812
|
-
```
|
|
1813
|
-
|
|
1814
|
-
or from a schema
|
|
1815
|
-
```js
|
|
1816
|
-
const schema = await client.getSchema("nms:extAccount");
|
|
1817
|
-
const sysEnum = await client.getSysEnum("encryptionType", schema);
|
|
1818
|
-
```
|
|
1819
|
-
|
|
1820
|
-
Get a source schema
|
|
1821
|
-
```js
|
|
1822
|
-
var srcSchema = await NLWS.xtkPersist.getEntityIfMoreRecent("xtk:srcSchema|nms:recipient", "", false);
|
|
1823
|
-
console.log(JSON.stringify(srcSchema));
|
|
1824
|
-
```
|
|
1825
|
-
|
|
1826
|
-
## Schema API (aka XtkNodeDef)
|
|
1827
|
-
The Schema API is the Campaign API which allows to access schemas and the corresponding node hierarchy in a programmatic way. It's simpler to use this API than to manipulate XML or JSON. The name XtkNodeDef comes from "Xtk Node Definition", where an XtkNode is a generic node in a schema definition.
|
|
1828
|
-
|
|
1829
|
-
The Schema API closely mimmics the Campaign server side API : https://docs.adobe.com/content/help/en/campaign-classic/technicalresources/api/c-Schema.html with the following differences:
|
|
1830
|
-
|
|
1831
|
-
* The `XtkSchema` and associated classes (`XtkSchemaNode`, `XtkSchemaKey`, `XtkEnumeration` and `XtkEnumerationValue`) are all immutable. There are currently no API to create schemas dynamically
|
|
1832
|
-
* Not all methods and functions are implemented
|
|
1833
|
-
* Several methods are asynchronous because they may require a server round trip to fetch schemas, etc.
|
|
1834
|
-
* There could be slight differences in usage due to Campaign server side JavaScript using some E4X specific constructs to iterate over collections (ex: for each(...)) which are not available in standard JavaScript environments
|
|
1835
|
-
|
|
1836
|
-
The entry point is the application object. Obtain a schema from its id:
|
|
1837
|
-
|
|
1838
|
-
```js
|
|
1839
|
-
const application = client.application;
|
|
1840
|
-
const schema = await application.getSchema("nms:recipient");
|
|
1841
|
-
```
|
|
1842
|
-
|
|
1843
|
-
This return a schema object of class `XtkSchema`
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
### Iterating over collections
|
|
1847
|
-
The metadata SDK closely mimmics the Campaign API, but provides convenience functions to access collections of objects, such as the children of a node, the values of an enumeration, etc. using an `ArrayMap` structure which allows access as both an array and a map.
|
|
1848
|
-
|
|
1849
|
-
Access as a map. Child elements can be accessed with their names, as if it was a JavaScript map. For instance, accessing the gender of a recipient. This method is kept as a compatibility layer with the legacy API and older versions of the SDK but is deprecated / discouraged. The reason is that there are schemas which have attribut names such as "length", or element names such as "forEach" which collide with JavaScript objects.
|
|
1850
|
-
```js
|
|
1851
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1852
|
-
const enumerations = schema.enumerations;
|
|
1853
|
-
// deprecated, discouraged
|
|
1854
|
-
expect(enumerations.gender.label).toBe("Gender");
|
|
1855
|
-
```
|
|
1856
|
-
|
|
1857
|
-
Instead, prefer the `get` function which can retreive any enumeration value
|
|
1858
|
-
```js
|
|
1859
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1860
|
-
const enumerations = schema.enumerations;
|
|
1861
|
-
expect(enumerations.get("gender").label).toBe("Gender");
|
|
1862
|
-
```
|
|
1863
|
-
|
|
1864
|
-
Elements can also be accessed as an array. In this example, we are iterating over the enumerations of a schema
|
|
1865
|
-
```js
|
|
1866
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1867
|
-
const enumerations = schema.enumerations;
|
|
1868
|
-
for (let i=0; i<enumerations.length; i++) {
|
|
1869
|
-
const enumeration = enumerations[i];
|
|
1870
|
-
}
|
|
1871
|
-
```
|
|
1872
|
-
|
|
1873
|
-
Note that this assumes that there is no enumeration called "length" which will override the "length" attribute. Schemas, schema elements, and sql schemas have attributes named "length", but they are attributes, and will therefore be named "@length" in the metadata API. There is no element named "length" in out-of-the-box schemas.
|
|
1874
|
-
|
|
1875
|
-
The ArrayMap also behaves like an iterator and works fine with the `for...of` syntax
|
|
1876
|
-
```js
|
|
1877
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1878
|
-
const enumerations = schema.enumerations;
|
|
1879
|
-
for (const enumeration of enumerations) {
|
|
1880
|
-
...
|
|
1881
|
-
}
|
|
1882
|
-
```
|
|
1883
|
-
|
|
1884
|
-
For convenience, the `map` and `forEach`, `find`, `filter`, `get`, and `flatMap` methods are also available and behave as expected:
|
|
1885
|
-
|
|
1886
|
-
```js
|
|
1887
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1888
|
-
// comma separated list of enumerations
|
|
1889
|
-
const enumerations = schema.enumerations.map(e => e.name).join(',');
|
|
1890
|
-
```
|
|
1891
|
-
|
|
1892
|
-
```js
|
|
1893
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1894
|
-
schema.enumerations.forEach(e => { ... });
|
|
1895
|
-
```
|
|
1896
|
-
|
|
1897
|
-
The `for...in` loop is also supported but deprecated/discouraged as it may return incorrect results for collections having items whose key collide with javaScript properties (such as length, map, forEach, etc.). Use a `for...of` construcr instead, or the `map` or `forEach` functions.
|
|
1898
|
-
```js
|
|
1899
|
-
const schema = await client.application.getSchema("nms:recipient");
|
|
1900
|
-
// deprecated, discouraged
|
|
1901
|
-
for (const key in schema.enumerations) {
|
|
1902
|
-
...
|
|
1903
|
-
}
|
|
1904
|
-
```
|
|
1905
|
-
|
|
1906
|
-
## Navigating schemas
|
|
1907
|
-
The schema API is useful to quickly navigate in the schema hierarchy. Here are a few examples
|
|
1908
|
-
|
|
1909
|
-
Get the label of the email attribute of the nms:recipient schema
|
|
1910
|
-
```js
|
|
1911
|
-
const schema = await application.getSchema("nms:recipient");
|
|
1912
|
-
const email = await schema.root.findNode("@email");
|
|
1913
|
-
console.log(email.label);
|
|
1914
|
-
```
|
|
1915
|
-
|
|
1916
|
-
The `findNode` function follows links and references
|
|
1917
|
-
* The function now supports `ref` nodes. Ref nodes are schema nodes having a `ref` property which is a reference to another node, possibly in a different schema.
|
|
1918
|
-
* If the xpath passed to the function ends with a ref node, the ref node itself will be returned. We're not following the reference. You can use the `refTarget` method to explicitely follow the reference
|
|
1919
|
-
* If the xpath traverse intermediate nodes which are ref nodes, the `findNode` method will follow the reference. For instance, the start activity in a workflow is a reference. Finding the xpath "start/@img" will follow the start reference and find the @img attribute from there
|
|
1920
|
-
|
|
1921
|
-
* Support for links. If the xpath parameter contains links, `findNode` will follow the link
|
|
1922
|
-
target with the same rules as for reference nodes. To get the target of a link, use the `linkTarget` method instead of `refTarget`.
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
For insance, you can get the country of a recipient who clicked in an email. This call follows the link from nms:broadLogRcp to nms:recipient and then from nms:recipient to nms:country, returning the country isoA3 attribute.
|
|
1926
|
-
```js
|
|
1927
|
-
const schema = await application.getSchema("nms:broadLogRcp");
|
|
1928
|
-
const node = await schema.root.findNode("recipient/country/@isoA3");
|
|
1929
|
-
```
|
|
1930
|
-
|
|
1931
|
-
The same syntax can be used for reference nodes. For instance, getting the attributes of the start activity of a workflow:
|
|
1932
|
-
```js
|
|
1933
|
-
const schema = await application.getSchema("xtk:workflow");
|
|
1934
|
-
const node = await schema.root.findNode("start/@name");
|
|
1935
|
-
```
|
|
1936
|
-
|
|
1937
|
-
In order to actually iterate over the children, things are a little bit more complicated
|
|
1938
|
-
```js
|
|
1939
|
-
const schema = await application.getSchema("xtk:workflow");
|
|
1940
|
-
const start = await schema.root.findNode("start");
|
|
1941
|
-
// start is the ref node, not the target of the ref. One need to explicitely
|
|
1942
|
-
// follow the ref in order to get the list of children
|
|
1943
|
-
const target = await start.refTarget();
|
|
1944
|
-
target.children.forEach(child => ... );
|
|
1945
|
-
```
|
|
1946
|
-
|
|
1947
|
-
To get the root node of the target of a link, use the `linkTarget` function
|
|
1948
|
-
```js
|
|
1949
|
-
const schema = await application.getSchema("nms:broadLogRcp");
|
|
1950
|
-
const node = await schema.root.findNode("recipient/country");
|
|
1951
|
-
// node is the country link, not the root node of the nms:country schema
|
|
1952
|
-
const root = await node.linkTarget();
|
|
1953
|
-
// root is the root node of the nms:country schema
|
|
1954
|
-
```
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
### XtkSchema
|
|
1958
|
-
|
|
1959
|
-
| Attribute | Description |
|
|
1960
|
-
|---|---|
|
|
1961
|
-
| **id** | The id of the schema. For instance "nms:recipient"
|
|
1962
|
-
| **namespace** | The namespace of the schema. For instance "nms"
|
|
1963
|
-
| **name** | The name of the schema (internal name)
|
|
1964
|
-
| **label** | The label (i.e. human readable, localised) name of the node.
|
|
1965
|
-
| **labelLocalizationId** | The translation id of the label of the node.
|
|
1966
|
-
| **labelSingular** | The singular label (i.e. human readable, localised) name of the schema. The label of a schema is typically a plural.
|
|
1967
|
-
| **labelSingularTranslationId** | The translation id of the label of the node of the singular label.
|
|
1968
|
-
| **isLibrary** | For schemas, indicates if the schema is a library
|
|
1969
|
-
| **mappingType** |Schema mapping type. Usually "sql"
|
|
1970
|
-
| **md5** | The MD5 code of the schema in the form of a hexadecimal string
|
|
1971
|
-
| **xml** | The XML (DOM) corresponding to this schema.<br>Note: this attribute is not available in the JS SDK.
|
|
1972
|
-
| **root** | The schema root node, if there is one. A reference to a `XtkSchemaNode`
|
|
1973
|
-
| **enumerations** | Map of enumerations in this schema, indexed by enumeration name. Values are of type `XtkEnumeration`
|
|
1974
|
-
| **userDescription** | The description of the schema in the form of a string.
|
|
1975
|
-
|
|
1976
|
-
A schema is also a `XtkSchemaNode` and the corresponding properties/methods are also availale.
|
|
1977
|
-
|
|
1978
|
-
### XtkSchemaNode
|
|
1979
|
-
|
|
1980
|
-
| Attribute | Description |
|
|
1981
|
-
|---|---|
|
|
1982
|
-
| **children** | A array/map of children of the node. See note on the ArrayMap structure below
|
|
1983
|
-
| **dataPolicy** | Returns a string of characters which provides the data policy of the current node.
|
|
1984
|
-
| **description** | A long, human readable, description of the node
|
|
1985
|
-
| **descriptionLocalizationId** | The translation id of the description of the node.
|
|
1986
|
-
| **editType** |Returns a string of characters which specifies the editing type of the current node.
|
|
1987
|
-
| **enum** | The name of the enumeration for the node, or an empty string if the node does node have an enumeration. See `enumeration()` method to get the corresponding `XtkSchemaNode`
|
|
1988
|
-
| **enumerationImage** | Returns the name of the image of the current node in the form of a string of characters.
|
|
1989
|
-
| **folderModel** |Only on the root node, returns a string which contains the folder template(s). On the other nodes, it returns undefined.
|
|
1990
|
-
| **image** | Returns the name of the image in the form of a string of characters.
|
|
1991
|
-
| **img** | Returns the name of the image in the form of a string of characters. (alias to `image` property)
|
|
1992
|
-
| **integrity** | Returns the link integrity type.
|
|
1993
|
-
| **keys** | A array/map of keys in this node, indexed by key name. Map values are of type `XtkSchemaKey`
|
|
1994
|
-
| **hasEnumeration** | Returns a boolean which indicates whether the value of the current node is linked to an enumeration.
|
|
1995
|
-
| **childrenCount** | Number of children nodes
|
|
1996
|
-
| **hasSQLTable** | Returns a boolean which indicates whether the current node is linked to an SQL table.
|
|
1997
|
-
| **hasUserEnumeration** | Returns a boolean which indicates whether the value of the current node is linked to a user enumeration.
|
|
1998
|
-
| **schema** | The schema (`XtkSchema`) to which this node belongs
|
|
1999
|
-
| **isAdvanced** | Returns a boolean which indicates whether the current node is advanced or not.
|
|
2000
|
-
| **isAnyType** | Returns a boolean which indicates whether the current node is ordinary.
|
|
2001
|
-
| **isAttribute** | Indicates if the node is an attribute (true) or an element (false)
|
|
2002
|
-
| **isAutoIncrement** | Returns a boolean which indicates whether the value of the current node is incremented automatically.
|
|
2003
|
-
| **isAutoPK** | Returns a boolean which indicates whether the current node is a primary key.
|
|
2004
|
-
| **isAutoUUID** | Yes | No | Returns a boolean which indicates whether the current node is an automatic UUID
|
|
2005
|
-
| **isAutoStg** | Yes | No | Returns a boolean which indicates whether the schema is a staging schema
|
|
2006
|
-
| **isBlob** | Returns a boolean which indicates whether the current node is a BLOB.
|
|
2007
|
-
| **isCalculated** | Returns a boolean which indicates whether the value of the current node is the result of a calculation. Note that compute strings are not considered as calculated attributes.
|
|
2008
|
-
| **isCDATA** | Returns a boolean which indicates whether the current node is mapped from CDATA type XML.
|
|
2009
|
-
| **isCollection** | Returns a boolean which indicates whether the current node is a collection of sub-elements and/or attributes. This is an alias to `unbound` and `isUnbound` properties.
|
|
2010
|
-
| **isDefaultOnDuplicate** | Returns a boolean. If the value added is vrai, during record deduplication, the default value (defined in defaultValue) is automatically reapplied during recording.
|
|
2011
|
-
| **isElementOnly** | Returns a boolean which indicates whether the current node is a logical sub-division of the schema.
|
|
2012
|
-
| **isExternalJoin** | True if the node is a link and if the join is external.
|
|
2013
|
-
| **isLink** | Returns a boolean which indicates whether the node is a link.
|
|
2014
|
-
| **isMappedAsXML** | Returns a boolean which indicates whether the node is an XML mapping.
|
|
2015
|
-
| **isMemo** | Returns a boolean which indicates whether the current node is mapped by a Memo.
|
|
2016
|
-
| **isMemoData** | Returns a boolean which indicates whether the current node is mapped by a MemoData.
|
|
2017
|
-
| **isNotNull** | Returns a boolean which indicates whether or not the current node can take the null value into account.
|
|
2018
|
-
| **isRequired** | Returns a boolean which indicates whether or not the value of the current node is mandatory.
|
|
2019
|
-
| **isRoot** | Indicates if the node is the root node of a schema, i.e. the first child of the schema node, whose name matches the schema name
|
|
2020
|
-
| **isSQL** | Returns a boolean which indicates whether the current node is mapped in SQL.
|
|
2021
|
-
| **isTemporaryTable** | Returns a boolean indicating whether the table is a temporary table. The table will not be created during database creation.
|
|
2022
|
-
| **unbound** | Returns a boolean which indicates whether the current node has an unlimited number of children of the same type.
|
|
2023
|
-
| **joins** | Element of type "link" has an array of XtkJoin. See `joinNodes` method.
|
|
2024
|
-
| **label** | The label (i.e. human readable, localised) name of the node.
|
|
2025
|
-
| **labelLocalizationId** | The translation id of the label of the node.
|
|
2026
|
-
| **name** | The name of the node (internal name)
|
|
2027
|
-
| **nodePath** | The xpath of the node
|
|
2028
|
-
| **parent** | The parent node (a `XtkSchemaNode` object). Will be null for schema nodes
|
|
2029
|
-
| **PKSequence** | Returns a character string that provides the name of the sequence to use for the primary key.
|
|
2030
|
-
| **packageStatus** | Returns a number that gives the package status.
|
|
2031
|
-
| **packageStatusString** | Returns a string that gives the package status ("never", "always", "default", or "preCreate").
|
|
2032
|
-
| **revLink** | Returns the name of the reverse link in the link target schema. See `reverseLink` method to get the actual reverse link object
|
|
2033
|
-
| **SQLName** | The SQL name of the field. The property is an empty string if the object isn't an SQL type field.
|
|
2034
|
-
| **SQLTable** | The SQL name of the table. The property is an empty string if the object isn't the main element or if schema mapping isn't of SQL type.
|
|
2035
|
-
| **size** | For string nodes, the maximum length of the node value. Alias to `length`.
|
|
2036
|
-
| **length** | For string nodes, the maximum length of the node value. Alias to `size`.
|
|
2037
|
-
| **target** | A string corresponding to the target of a link. Note that in the SDK, this is a string, whereas in the JS API, this is the actual target node. Because the SDK is async. Use `linkTarget` to get the target node of a link.
|
|
2038
|
-
| **type** | The data type of the node, for instance "string", "long", etc.
|
|
2039
|
-
| **userEnumeration** | Returns a string of characters which is the name of the user enumeration used by the current node.
|
|
2040
|
-
| **ref** | Some nodes are only references to other nodes. There are 2 kind of references. Local references are simply a xpath in the current schema (starting from the schema itself, and not the schema root). Fully qualified references are prefixed with a schema id. The target node can be accessed with the `refTarget` funtion.
|
|
2041
|
-
| **isMappedAsXml** | Is the field mapped as XML?
|
|
2042
|
-
| **visibleIf** | The visibility expression of the node (if any) since version 1.1.9 of the SDK
|
|
2043
|
-
| **belongsTo** | For attribute and elements, indicates the schema id in which they were defined. Since version 1.1.10 of the SDK
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
| Method | Description |
|
|
2047
|
-
|---|---|
|
|
2048
|
-
| async **findNode** | Find a child node using a xpath. This function follows links and references if necessary and will dynamically fetch/cache necessary schemas.
|
|
2049
|
-
| async **refTarget** | Get the target node of a reference
|
|
2050
|
-
| async **linkTarget** | Get the target node of a link. See `target`
|
|
2051
|
-
| async **joinNodes** | Get the schema nodes corresponding to link. The function returns nodes for both the source and the destination of the link. See `joins`.
|
|
2052
|
-
| async **reverseLink** | Returns the node corresponding to the reverse link of a link. See `revLink` to get the reverse link name rather than the actual node
|
|
2053
|
-
| async **computeString** | Returns the compute string of a node, following references if necessary
|
|
2054
|
-
| async **enumeration** | For nodes whose value is an enumeration, return the `XtkEnumeration` object corresponding to the enumeration definition. See `enum` property to get the enumeration name instead of the object
|
|
2055
|
-
| **firstInternalKeyDef** |
|
|
2056
|
-
| **firstExternalKeyDef** |
|
|
2057
|
-
| **firstKeyDef** |
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
### XtkSchemaKey
|
|
2062
|
-
|
|
2063
|
-
| Attribute/Method | Description |
|
|
2064
|
-
|---|---|
|
|
2065
|
-
| **schema** | The schema to which this key belongs
|
|
2066
|
-
| **name** | The name of the key (internal name)
|
|
2067
|
-
| **label** | The label (i.e. human readable, localised) name of the key
|
|
2068
|
-
| **description** | A long, human readable, description of the key
|
|
2069
|
-
| **isInternal** | Indicates if the key is an internal key (as opposed to an external key)
|
|
2070
|
-
| **allowEmptyPart** |
|
|
2071
|
-
| **fields** | A ArrayMap of key fields making up the key. Each value is a reference to a `XtkSchemaNode`
|
|
2072
|
-
|
|
2073
|
-
### XtkEnumeration
|
|
2074
|
-
|
|
2075
|
-
| Attribute/Method | Description |
|
|
2076
|
-
|---|---|
|
|
2077
|
-
| **name** | The name of the enumeration, fully qualified, i.e. prefixed with the schema id
|
|
2078
|
-
| **label** | The label (i.e. human readable, localised) name of the key
|
|
2079
|
-
| **labelLocalizationId** | The translation id of the label of the key.
|
|
2080
|
-
| **description** | A long, human readable, description of the key
|
|
2081
|
-
| **descriptionLocalizationId** | The translation id of the description of the key.
|
|
2082
|
-
| **baseType** | The base type of the enumeration, usually "string" or "byte"
|
|
2083
|
-
| **default** | The default value of the enumeration, casted to the enumeration type
|
|
2084
|
-
| **hasImage** | If the enumeration has an image
|
|
2085
|
-
| **values** | A ArrayMap of enumeration values, of type `XtkEnumerationValue`
|
|
2086
|
-
|
|
2087
|
-
### XtkEnumerationValue
|
|
2088
|
-
|
|
2089
|
-
| Attribute/Method | Description |
|
|
2090
|
-
|---|---|
|
|
2091
|
-
| **name** | The name of the key (internal name)
|
|
2092
|
-
| **label** | The label (i.e. human readable, localised) name of the key
|
|
2093
|
-
| **labelLocalizationId** | The translation id of the label of the key.
|
|
2094
|
-
| **description** | A long, human readable, description of the key
|
|
2095
|
-
| **descriptionLocalizationId** | The translation id of the description of the key.
|
|
2096
|
-
| **image** |
|
|
2097
|
-
| **enabledIf** |
|
|
2098
|
-
| **applicableIf** |
|
|
2099
|
-
| **value** | The value of the enumeration (casted to the proper Javascript type)
|
|
2100
|
-
|
|
2101
|
-
# Advanced Topics
|
|
2102
|
-
|
|
2103
|
-
## The EntityAccessor
|
|
2104
|
-
|
|
2105
|
-
An `EntityAccessor` provides a simple interface to access entity objects regardless of their representation. For instance, a query result may be a DOM Element, or a object literal, or a BadgerFish objet. Accessing attribute values and sub elements requires to know which representation is used and which representation specific API to call. For instance, to get the "name" attribute of an entity, you'll write:
|
|
2106
|
-
|
|
2107
|
-
* for Simple Json representation, access as JavaScript properties: entity.name or entity["name"]
|
|
2108
|
-
* for the XML representation, use the DOM API: entity.DomUtil.getAttribute("name)"
|
|
2109
|
-
* for Badget fish, access as JavaScript properties, but do not forget the "@" sign; entity["@name"]
|
|
2110
|
-
|
|
2111
|
-
Once done, you'll probably want to cast the value to an XTK type using the XtkCaster.
|
|
2112
|
-
|
|
2113
|
-
If you need to access entity attributes (or child elements) in a generic way, you can use the `EntityAccessor`. It has the following static methods:
|
|
2114
|
-
|
|
2115
|
-
* `getAttributeAsString`, `getAttributeAsLong`, `getAttributeAsBoolean` to get typed attribute values
|
|
2116
|
-
* `getChildElements` to get the child elements. The result can be iterated on with a `for...of...` loop
|
|
2117
|
-
* `getElement` to get a child element whose attributes and child elements can also be accessed by the EntityAccessor API
|
|
2118
|
-
|
|
2119
|
-
## Invoking SOAP calls dynamically
|
|
2120
|
-
Soap calls can be invoked dynamically as follows
|
|
2121
|
-
|
|
2122
|
-
```js
|
|
2123
|
-
const namespace = client.NLWS["xtkSession"];
|
|
2124
|
-
const method = namespace["getOption"];
|
|
2125
|
-
const result = await method.call(namespace, parameters);
|
|
2126
|
-
```
|
|
2127
|
-
|
|
2128
|
-
where parameters is the list of parameters to the SOAP call.
|
|
2129
|
-
Parameters can be a function which can compute and return the list of parameters as the function is being called:
|
|
2130
|
-
|
|
2131
|
-
```js
|
|
2132
|
-
const result = await method.call(namespace, (method, callContext) => {
|
|
2133
|
-
return parameters;
|
|
2134
|
-
});
|
|
2135
|
-
```
|
|
2136
|
-
The `method` parameter is the XML definition of the SOAP method call. The `callContext` is an object which contains the following attributes:
|
|
2137
|
-
* `schemaId` is the id of the schema containing the SOAP method
|
|
2138
|
-
* `namespace` is the call namespace
|
|
2139
|
-
* `object` is only used for non-static call and contains the "this" of the call.
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
# Build & Run
|
|
2144
|
-
|
|
2145
|
-
To build this project, you need node and npm
|
|
2146
|
-
|
|
2147
|
-
```sh
|
|
2148
|
-
npm install
|
|
2149
|
-
```
|
|
2150
|
-
|
|
2151
|
-
## Check and resolve any security issues
|
|
2152
|
-
```sh
|
|
2153
|
-
npm audit
|
|
2154
|
-
npm audit fix --force
|
|
2155
|
-
```
|
|
2156
|
-
|
|
2157
|
-
## Check if there are any code warnings
|
|
2158
|
-
```sh
|
|
2159
|
-
node_modules/jshint/bin/jshint src/
|
|
2160
|
-
```
|
|
2161
|
-
|
|
2162
|
-
## Run tests
|
|
2163
|
-
```sh
|
|
2164
|
-
npm run unit-tests
|
|
2165
|
-
```
|
|
2166
|
-
|
|
2167
|
-
## Build JavaScript documentation
|
|
2168
|
-
```sh
|
|
2169
|
-
npm run jsdoc
|
|
2170
|
-
open ./docs/jsdoc/index.html
|
|
2171
|
-
```
|
|
2172
|
-
|
|
2173
|
-
The HTML doc will be generated in the docs/ folder
|
|
2174
|
-
|
|
2175
|
-
## Deploy to npm
|
|
2176
|
-
|
|
2177
|
-
To deploy to npm
|
|
2178
|
-
* Build and run tests locally
|
|
2179
|
-
* Increase version in `package.json`
|
|
2180
|
-
* Push a commit with message `Release 1.2.3` in master
|
|
2181
|
-
|
|
2182
|
-
| There's a publication action that will publish released automatically when there's a commit named "Release ..." in master AND the version matches the one in package.json
|
|
2183
|
-
| Do not create a git tag for this version, the publication hook will take care of it. If you have created a tag with the release name, the publication will fail
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
# Client-side SDK
|
|
2187
|
-
The SDK can also be used client side.
|
|
2188
|
-
|
|
2189
|
-
## Compile the client-side SDK
|
|
2190
|
-
Go to the root folder of the SDK and compile the SDK
|
|
2191
|
-
````sh
|
|
2192
|
-
node ./compile.js
|
|
2193
|
-
````
|
|
2194
|
-
|
|
2195
|
-
It generates a file named `dist/bundle.js`
|
|
2196
|
-
````
|
|
2197
|
-
ACC client-side SDK compiler version 0.1.0
|
|
2198
|
-
Bundling ../package.json
|
|
2199
|
-
Bundling ./web/jsdom.js
|
|
2200
|
-
Bundling ./web/crypto.js
|
|
2201
|
-
Bundling ./web/request.js
|
|
2202
|
-
Bundling ./xtkCaster.js
|
|
2203
|
-
Bundling ./domUtil.js
|
|
2204
|
-
Bundling ./xtkEntityCache.js
|
|
2205
|
-
Bundling ./methodCache.js
|
|
2206
|
-
Bundling ./optionCache.js
|
|
2207
|
-
Bundling ./soap.js
|
|
2208
|
-
Bundling ./crypto.js
|
|
2209
|
-
Bundling ./client.js
|
|
2210
|
-
Bundling ./index.js
|
|
2211
|
-
Client-side SDK generated in ./dist/bundle.js
|
|
2212
|
-
````
|
|
2213
|
-
|
|
2214
|
-
## Use a proxy
|
|
2215
|
-
Using the client side SDK cannot be done directly because the Campaign server has CORS configured to reject HTTP requests from resources not served by Campaign.
|
|
2216
|
-
Therefore a server-side proxy is need to relay the calls to Campaign, or you need to serve the SDK and corresponding web pages from Campaign itself
|
|
2217
|
-
|
|
2218
|
-
## Deploy the SDK to a Campaign server
|
|
2219
|
-
Once compiled, copy it to the Campaign server (here on a dev environment).
|
|
2220
|
-
````sh
|
|
2221
|
-
cd /c/cygwin64/home/neolane/ac
|
|
2222
|
-
cp "Z:\amorin On My Mac\Documents\dev\git\ac7\acc-js-sdk\dist/bundle.js" nl/web/accSDK.js
|
|
2223
|
-
````
|
|
2224
|
-
|
|
2225
|
-
This makes them available on the following endpoint
|
|
2226
|
-
````
|
|
2227
|
-
/nl/accSDK.js
|
|
2228
|
-
````
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
## Usage
|
|
2234
|
-
|
|
2235
|
-
Include the SDK
|
|
2236
|
-
```
|
|
2237
|
-
<script src="accSDK.js"></script>
|
|
2238
|
-
````
|
|
2239
|
-
|
|
2240
|
-
Use the SDK. Note that the SDK variable is now called `document.accSDK` to avoid potential name collision with the common name "sdk".
|
|
2241
|
-
````
|
|
2242
|
-
<script>
|
|
2243
|
-
|
|
2244
|
-
(async () => {
|
|
2245
|
-
const sdk = document.accSDK;
|
|
2246
|
-
|
|
2247
|
-
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
2248
|
-
"http://ffdamid:8080", "admin", "admin");
|
|
2249
|
-
const client = await sdk.init(connectionParameters);
|
|
2250
|
-
|
|
2251
|
-
console.log(sdk.getSDKVersion());
|
|
2252
|
-
await client.logon();
|
|
2253
|
-
|
|
2254
|
-
var databaseId = await client.getOption("XtkDatabaseId");
|
|
2255
|
-
console.log(databaseId);
|
|
2256
|
-
document.getElementById("hello").textContent = databaseId;
|
|
2257
|
-
|
|
2258
|
-
await client.logoff();
|
|
2259
|
-
})();
|
|
2260
|
-
|
|
2261
|
-
</script>
|
|
2262
|
-
````
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
103
|
|
|
2266
104
|
# Contributing
|
|
2267
105
|
|