@itentialopensource/adapter-utils 5.1.6 → 5.2.0
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/CHANGELOG.md +20 -0
- package/lib/cacheHandler.js +9 -115
- package/lib/genericHandler.js +146 -1
- package/lib/requestHandler.js +123 -61
- package/lib/restHandler.js +6 -2
- package/package.json +1 -1
- package/refs?service=git-upload-pack +0 -0
- package/schemas/propertiesSchema.json +71 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
|
|
2
|
+
## 5.2.0 [10-04-2023]
|
|
3
|
+
|
|
4
|
+
* Broker Changes
|
|
5
|
+
|
|
6
|
+
Closes ADAPT-2848
|
|
7
|
+
|
|
8
|
+
See merge request itentialopensource/adapter-utils!277
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 5.1.7 [09-09-2023]
|
|
13
|
+
|
|
14
|
+
* Added pagination to expanded generic handler
|
|
15
|
+
|
|
16
|
+
Closes ADAPT-2849
|
|
17
|
+
|
|
18
|
+
See merge request itentialopensource/adapter-utils!276
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
2
22
|
## 5.1.6 [09-06-2023]
|
|
3
23
|
|
|
4
24
|
* add fixes to connector that are missing
|
package/lib/cacheHandler.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
const AsyncLockCl = require('async-lock');
|
|
9
9
|
const path = require('path');
|
|
10
|
-
const jsonQuery = require('json-query');
|
|
11
10
|
|
|
12
11
|
const lock = new AsyncLockCl();
|
|
13
12
|
let id = null;
|
|
@@ -32,16 +31,6 @@ function createCacheEntity(entityName, entityList, interval, sortEntities = true
|
|
|
32
31
|
});
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
/**
|
|
36
|
-
* @summary Generates name for data object. Currently non-unique
|
|
37
|
-
* @function generateName
|
|
38
|
-
* @returns {String} - generated name
|
|
39
|
-
*/
|
|
40
|
-
function generateName() {
|
|
41
|
-
log.warn('Name for entity not found, generated name placeholder');
|
|
42
|
-
return 'GeneratedName';
|
|
43
|
-
}
|
|
44
|
-
|
|
45
34
|
/**
|
|
46
35
|
* @summary Deletes cache data and properties. Data deletion
|
|
47
36
|
* saves considerable memory.
|
|
@@ -358,98 +347,6 @@ function removeCacheEntry(cache, entityType) {
|
|
|
358
347
|
log.error(`${origin}: Did not find cache type ${entityType} to remove!`);
|
|
359
348
|
}
|
|
360
349
|
|
|
361
|
-
/**
|
|
362
|
-
* @function getDataFromSources
|
|
363
|
-
* @summary INTERNAL FUNCTION: get data from source(s) - nested
|
|
364
|
-
* @param {*} loopField - fields
|
|
365
|
-
* @param {Array} sources - sources to look into
|
|
366
|
-
* @returns {*} - nested field value
|
|
367
|
-
*/
|
|
368
|
-
function getDataFromSources(loopField, sources) {
|
|
369
|
-
let fieldValue = loopField;
|
|
370
|
-
|
|
371
|
-
// go through the sources to find the field
|
|
372
|
-
for (let s = 0; s < sources.length; s += 1) {
|
|
373
|
-
// find the field value using jsonquery
|
|
374
|
-
const nestedValue = jsonQuery(loopField, { data: sources[s] }).value;
|
|
375
|
-
|
|
376
|
-
// if we found in source - set and no need to check other sources
|
|
377
|
-
if (nestedValue) {
|
|
378
|
-
fieldValue = nestedValue;
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return fieldValue;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* @summary Manipulates data from call to only represent the specified fields and id and name if they do not have one
|
|
388
|
-
*
|
|
389
|
-
* @function parseResponseFields
|
|
390
|
-
* @param {Boolean} responseFull - whether or not to take in all fields
|
|
391
|
-
* @param {Object of output to call result} responseFields - fields to take in
|
|
392
|
-
* - ie response field of "name": "id" will give the iap call output a name field
|
|
393
|
-
* with the value being the id
|
|
394
|
-
* @param {Array of Objects} allData - data returned from IAP Call
|
|
395
|
-
* @return {Array of Objects} - modified data
|
|
396
|
-
*/
|
|
397
|
-
function parseResponseFields(responseFields, allData, end, requestFields) {
|
|
398
|
-
const origin = `${id}-cacheHandler-createCacheData`;
|
|
399
|
-
log.trace(origin);
|
|
400
|
-
|
|
401
|
-
const parsedData = [];
|
|
402
|
-
const rfKeys = Object.keys(responseFields);
|
|
403
|
-
log.debug(rfKeys);
|
|
404
|
-
|
|
405
|
-
let ostypePrefix = '';
|
|
406
|
-
if (responseFields.ostypePrefix) {
|
|
407
|
-
ostypePrefix = responseFields.ostypePrefix;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
let statusValue = true;
|
|
411
|
-
if (responseFields.statusValue) {
|
|
412
|
-
statusValue = responseFields.statusValue;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
allData.response.forEach((currData) => {
|
|
416
|
-
const newObj = currData;
|
|
417
|
-
|
|
418
|
-
for (let rf = 0; rf < rfKeys.length; rf += 1) {
|
|
419
|
-
if (rfKeys[rf] !== 'ostypePrefix') {
|
|
420
|
-
let fieldValue = getDataFromSources(responseFields[rfKeys[rf]], [currData, { fake: 'fakedata' }, requestFields]);
|
|
421
|
-
|
|
422
|
-
// if the field is ostype - need to add prefix
|
|
423
|
-
if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
|
|
424
|
-
fieldValue = ostypePrefix + fieldValue;
|
|
425
|
-
}
|
|
426
|
-
// if there is a status to set, set it
|
|
427
|
-
if (rfKeys[rf] === 'status') {
|
|
428
|
-
// if really looking for just a good response
|
|
429
|
-
if (responseFields[rfKeys[rf]] === 'return2xx' && allData.icode === statusValue.toString()) {
|
|
430
|
-
newObj.isAlive = true;
|
|
431
|
-
} else if (fieldValue.toString() === statusValue.toString()) {
|
|
432
|
-
newObj.isAlive = true;
|
|
433
|
-
} else {
|
|
434
|
-
newObj.isAlive = false;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
// if we found a good value
|
|
438
|
-
newObj[rfKeys[rf]] = fieldValue;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if (!Object.prototype.hasOwnProperty.call(currData, 'name')) {
|
|
443
|
-
newObj.name = generateName();
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// no longer requiring id field
|
|
447
|
-
|
|
448
|
-
parsedData.push(newObj);
|
|
449
|
-
});
|
|
450
|
-
return parsedData;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
350
|
/**
|
|
454
351
|
* @summary makes IAP Calls through Generic Handler
|
|
455
352
|
*
|
|
@@ -458,13 +355,18 @@ function parseResponseFields(responseFields, allData, end, requestFields) {
|
|
|
458
355
|
* @param requestHandler - instance of requestHandler to make call
|
|
459
356
|
* @param callback - data or error
|
|
460
357
|
*/
|
|
461
|
-
function makeIAPCall(calls, requestHandler, callback) {
|
|
358
|
+
function makeIAPCall(calls, requestHandler, callback) {
|
|
462
359
|
const callPromises = [];
|
|
463
|
-
|
|
360
|
+
|
|
464
361
|
for (let i = 0; i < calls.length; i += 1) {
|
|
465
362
|
log.debug('Response :', calls[i].responseFields);
|
|
466
363
|
callPromises.push(new Promise((resolve, reject) => {
|
|
467
|
-
|
|
364
|
+
const metadata = {};
|
|
365
|
+
if (calls[i].pagination) {
|
|
366
|
+
metadata.pagination = calls[i].pagination;
|
|
367
|
+
metadata.pagination.responseDatakey = calls[i].responseDatakey || '';
|
|
368
|
+
}
|
|
369
|
+
requestHandler.iapMakeGenericCall(metadata, calls[i].path, calls[i], [{ fake: 'fakedata' }], [], (callRet, callErr) => {
|
|
468
370
|
if (callErr) {
|
|
469
371
|
log.error('Make iap call failed with error');
|
|
470
372
|
log.error(callErr);
|
|
@@ -472,21 +374,13 @@ function makeIAPCall(calls, requestHandler, callback) { // todo pass in properti
|
|
|
472
374
|
log.error(callErr.IAPerror.displayString);
|
|
473
375
|
return reject(callErr);
|
|
474
376
|
}
|
|
475
|
-
if (calls[i].handleFailure === 'ignore') {
|
|
476
|
-
log.info(`Call failed for path ${calls[i].path} with error code ${callErr.icode}. Ignoring.`);
|
|
477
|
-
return resolve([]);
|
|
478
|
-
}
|
|
479
377
|
log.warn(`Call failed for path ${calls[i].path} with error code ${callErr.icode}. Rejecting.`);
|
|
480
378
|
return reject(callErr);
|
|
481
379
|
}
|
|
482
380
|
|
|
483
381
|
// callRet is the object returned from that call
|
|
484
382
|
log.info(`Sucessful Call. Adding to cache from path ${calls[i].path}`);
|
|
485
|
-
|
|
486
|
-
if (calls[i].responseDatakey) {
|
|
487
|
-
result.response = jsonQuery(calls[i].responseDatakey, { data: result.response }).value;
|
|
488
|
-
}
|
|
489
|
-
return resolve(parseResponseFields(calls[i].responseFields, result, i, calls[i].requestFields));
|
|
383
|
+
return resolve(callRet);
|
|
490
384
|
});
|
|
491
385
|
}));
|
|
492
386
|
}
|
package/lib/genericHandler.js
CHANGED
|
@@ -5,6 +5,54 @@
|
|
|
5
5
|
/* eslint consistent-return: warn */
|
|
6
6
|
|
|
7
7
|
/* NodeJS internal utilities */
|
|
8
|
+
const jsonQuery = require('json-query');
|
|
9
|
+
|
|
10
|
+
// INTERNAL FUNCTIONS
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @summary Update the offset for paginated call.
|
|
14
|
+
* @function incrementOffset
|
|
15
|
+
* @param {String} offsetType - type of offset (page or limit)
|
|
16
|
+
* @param {Number} data - previous offset
|
|
17
|
+
* @param {Number} limit - call limit
|
|
18
|
+
* @returns {Number} - new offset
|
|
19
|
+
*/
|
|
20
|
+
function incrementOffset(offsetType, previousOffset, limit) {
|
|
21
|
+
let newOffset;
|
|
22
|
+
if (offsetType === 'limit') {
|
|
23
|
+
newOffset = previousOffset + limit;
|
|
24
|
+
} else if (offsetType === 'page') {
|
|
25
|
+
newOffset = previousOffset + 1;
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error(`Offset Type : ${offsetType} not supported or insufficient data was provided`);
|
|
28
|
+
}
|
|
29
|
+
return newOffset;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @summary Function to set the value at a specified property path
|
|
34
|
+
* @function setNestedProperty
|
|
35
|
+
* @param {Object} oldValue - Object to update
|
|
36
|
+
* @param {String} responseDataKey - path to property to update in . separated string
|
|
37
|
+
* @param {Object} newValue - Object with data to use in update
|
|
38
|
+
*/
|
|
39
|
+
function setNestedProperty(oldValue, responseDatakey, newValue) {
|
|
40
|
+
const newRes = jsonQuery(responseDatakey, { data: newValue.response }).value;
|
|
41
|
+
const oldRes = jsonQuery(responseDatakey, { data: oldValue.response }).value;
|
|
42
|
+
const path = responseDatakey.split('.');
|
|
43
|
+
let currentObj = oldValue.response;
|
|
44
|
+
for (let i = 0; i < path.length - 1; i += 1) {
|
|
45
|
+
const segment = path[i];
|
|
46
|
+
if (Object.hasOwnProperty.call(currentObj, segment)) {
|
|
47
|
+
currentObj = currentObj[segment];
|
|
48
|
+
} else {
|
|
49
|
+
currentObj[segment] = {};
|
|
50
|
+
currentObj = currentObj[segment];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Modifies value at path and updates original object
|
|
54
|
+
currentObj[path[path.length - 1]] = oldRes.concat(newRes);
|
|
55
|
+
}
|
|
8
56
|
|
|
9
57
|
class GenericHandler {
|
|
10
58
|
/**
|
|
@@ -156,7 +204,7 @@ class GenericHandler {
|
|
|
156
204
|
}
|
|
157
205
|
reqObj.addlHeaders = { ...reqObj.addlHeaders, ...signature };
|
|
158
206
|
this.requestHandlerInst.identifyRequest('.generic', action, reqObj, returnF, (irReturnData, irReturnError) => {
|
|
159
|
-
// if we received an error or
|
|
207
|
+
// if we received an error or there is no response on the results
|
|
160
208
|
// return an error
|
|
161
209
|
if (irReturnError) {
|
|
162
210
|
/* HERE IS WHERE YOU CAN ALTER THE ERROR MESSAGE */
|
|
@@ -174,6 +222,24 @@ class GenericHandler {
|
|
|
174
222
|
});
|
|
175
223
|
});
|
|
176
224
|
}
|
|
225
|
+
|
|
226
|
+
// Does not support AWS adapters due to the auth call above
|
|
227
|
+
if (metadata && metadata.pagination) {
|
|
228
|
+
return this.expandedGenericAdapterRequestPaginated(metadata.pagination, action, reqObj, returnF, meth, (returnData, returnError) => {
|
|
229
|
+
if (returnError) {
|
|
230
|
+
/* HERE IS WHERE YOU CAN ALTER THE ERROR MESSAGE */
|
|
231
|
+
return callback(null, returnError);
|
|
232
|
+
}
|
|
233
|
+
if (!Object.hasOwnProperty.call(returnData, 'response')) {
|
|
234
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Invalid Response', ['genericAdapterRequest'], null, null, null);
|
|
235
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
236
|
+
return callback(null, errorObj);
|
|
237
|
+
}
|
|
238
|
+
/* HERE IS WHERE YOU CAN ALTER THE RETURN DATA */
|
|
239
|
+
// return the response
|
|
240
|
+
return callback(returnData, null);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
177
243
|
return this.requestHandlerInst.identifyRequest('.generic', action, reqObj, returnF, (irReturnData, irReturnError) => {
|
|
178
244
|
// if we received an error or their is no response on the results
|
|
179
245
|
// return an error
|
|
@@ -198,6 +264,85 @@ class GenericHandler {
|
|
|
198
264
|
}
|
|
199
265
|
}
|
|
200
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Makes the requested generic call
|
|
269
|
+
*
|
|
270
|
+
* @function expandedGenericAdapterRequestPaginated
|
|
271
|
+
* @param {Object} metadata - metadata for the call (optional).
|
|
272
|
+
* Can be a stringified Object.
|
|
273
|
+
* @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (optional)
|
|
274
|
+
* @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (optional)
|
|
275
|
+
* @param {Object} pathVars - the parameters to be put within the url path (optional).
|
|
276
|
+
* Can be a stringified Object.
|
|
277
|
+
* @param {Object} queryData - the parameters to be put on the url (optional).
|
|
278
|
+
* Can be a stringified Object.
|
|
279
|
+
* @param {Object} requestBody - the body to add to the request (optional).
|
|
280
|
+
* Can be a stringified Object.
|
|
281
|
+
* @param {Object} addlHeaders - additional headers to be put on the call (optional).
|
|
282
|
+
* Can be a stringified Object.
|
|
283
|
+
* @param {Object} paginationObject - object specifying pagination variables and increment method
|
|
284
|
+
* @param {getCallback} callback - a callback function to return the result (Generics)
|
|
285
|
+
* or the error
|
|
286
|
+
*/
|
|
287
|
+
expandedGenericAdapterRequestPaginated(paginationObject, action, reqObj, returnF, meth, callback) {
|
|
288
|
+
const origin = `${this.myid}-requestHandler-expandedGenericAdapterRequestPaginated`;
|
|
289
|
+
log.trace(origin);
|
|
290
|
+
let results;
|
|
291
|
+
// Set up variables for calls
|
|
292
|
+
const { offsetVar } = paginationObject;
|
|
293
|
+
const pagType = paginationObject.requestLocation; // Body or query supported
|
|
294
|
+
let pagLocation;
|
|
295
|
+
if (pagType === 'body') {
|
|
296
|
+
pagLocation = 'payload';
|
|
297
|
+
} else if (pagType === 'query') {
|
|
298
|
+
pagLocation = 'uriQuery';
|
|
299
|
+
} else {
|
|
300
|
+
const err = new Error(`Pagination Type : ${pagType} not supported or insufficient data was provided`);
|
|
301
|
+
return callback(null, err);
|
|
302
|
+
}
|
|
303
|
+
const limit = reqObj[pagLocation][paginationObject.limitVar];
|
|
304
|
+
const recursiveCall = (currentOffset) => {
|
|
305
|
+
try {
|
|
306
|
+
const myReqObj = {
|
|
307
|
+
...reqObj
|
|
308
|
+
};
|
|
309
|
+
myReqObj[pagLocation][offsetVar] = currentOffset;
|
|
310
|
+
this.requestHandlerInst.identifyRequest('.generic', action, myReqObj, returnF, (result, error) => {
|
|
311
|
+
if (error) {
|
|
312
|
+
return callback(null, error);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!Object.hasOwnProperty.call(result, 'response')) {
|
|
316
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Invalid Response', ['genericAdapterRequestPaginated'], null, null, null);
|
|
317
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
318
|
+
return callback(null, errorObj);
|
|
319
|
+
}
|
|
320
|
+
// Results hasn't been populated yet
|
|
321
|
+
if (!results) {
|
|
322
|
+
results = { ...result };
|
|
323
|
+
} else if (paginationObject.responseDatakey) {
|
|
324
|
+
setNestedProperty(results, paginationObject.responseDatakey, result);
|
|
325
|
+
} else {
|
|
326
|
+
results.response = results.response.concat(result.response);
|
|
327
|
+
}
|
|
328
|
+
if (result.response.length === limit) {
|
|
329
|
+
const newOffset = incrementOffset(paginationObject.incrementBy, currentOffset, limit);
|
|
330
|
+
// Rescurse
|
|
331
|
+
recursiveCall(newOffset);
|
|
332
|
+
} else {
|
|
333
|
+
return callback(results, null);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
} catch (e) {
|
|
337
|
+
// handle any exception
|
|
338
|
+
const errorObj = this.transUtil.checkAndReturn(e, origin, 'Expanded Generic Adapter Request with Pagination Failed');
|
|
339
|
+
return callback(null, errorObj);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
recursiveCall(reqObj[pagLocation][offsetVar]);
|
|
344
|
+
}
|
|
345
|
+
|
|
201
346
|
/**
|
|
202
347
|
* Makes the requested generic call
|
|
203
348
|
*
|
package/lib/requestHandler.js
CHANGED
|
@@ -329,24 +329,109 @@ function dbCalls(collectionName, entity, action, data, callback) {
|
|
|
329
329
|
/*
|
|
330
330
|
* INTERNAL FUNCTION: get data from source(s) - nested
|
|
331
331
|
*/
|
|
332
|
-
function getDataFromSources(loopField, sources) {
|
|
332
|
+
function getDataFromSources(loopField, sources, props) {
|
|
333
333
|
let fieldValue = loopField;
|
|
334
|
-
|
|
334
|
+
let foundProp = false;
|
|
335
335
|
// go through the sources to find the field
|
|
336
336
|
for (let s = 0; s < sources.length; s += 1) {
|
|
337
337
|
// find the field value using jsonquery
|
|
338
338
|
const nestedValue = jsonQuery(loopField, { data: sources[s] }).value;
|
|
339
339
|
|
|
340
340
|
// if we found in source - set and no need to check other sources
|
|
341
|
-
if (nestedValue) {
|
|
341
|
+
if (nestedValue && Object.keys(nestedValue).length !== 0) {
|
|
342
342
|
fieldValue = nestedValue;
|
|
343
|
+
foundProp = true;
|
|
343
344
|
break;
|
|
344
345
|
}
|
|
345
346
|
}
|
|
346
347
|
|
|
348
|
+
// Check for field in adapter properties
|
|
349
|
+
if (!foundProp && props && props[loopField]) {
|
|
350
|
+
fieldValue = props[loopField];
|
|
351
|
+
}
|
|
352
|
+
|
|
347
353
|
return fieldValue;
|
|
348
354
|
}
|
|
349
355
|
|
|
356
|
+
/**
|
|
357
|
+
* @summary Extracts the keys to be replaced in request fields or response fields.
|
|
358
|
+
*
|
|
359
|
+
* @function extractKeysFromBraces
|
|
360
|
+
* @param {String} value - String in which to look for {} and extract values
|
|
361
|
+
*
|
|
362
|
+
* @return {Array} Array containing 0 or more keys found in input String
|
|
363
|
+
*/
|
|
364
|
+
function extractKeysFromBraces(value) {
|
|
365
|
+
const regex = /\{(.*?)\}/g;
|
|
366
|
+
const matches = value.match(regex);
|
|
367
|
+
if (matches) {
|
|
368
|
+
return matches.map((key) => key.replace(/{|}/g, ''));
|
|
369
|
+
}
|
|
370
|
+
return [];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @summary Given a string containing a logical OR in braces {||}, return the LHS if value is found
|
|
375
|
+
* in sources, otherwise return the RHS
|
|
376
|
+
*
|
|
377
|
+
* @function setConditionalValue
|
|
378
|
+
* @param {String} valueField - String containing operands
|
|
379
|
+
* @param {Array} source - Array containing sources to search for operand values
|
|
380
|
+
* @param {Object} props - Object containing Adapter props as secondary source
|
|
381
|
+
*
|
|
382
|
+
* @return {String} Final value with data replaced in found keys.
|
|
383
|
+
*/
|
|
384
|
+
function setConditionalValue(valueField, sources, props) {
|
|
385
|
+
if (!valueField.includes('{||}')) {
|
|
386
|
+
throw new Error('This method is only to be used with Strings containing a logical OR in braces {||}');
|
|
387
|
+
}
|
|
388
|
+
const operands = valueField.split('{||}'); // Array of left side and right side
|
|
389
|
+
const operandA = extractKeysFromBraces(operands[0]); // [name]
|
|
390
|
+
const operandB = extractKeysFromBraces(operands[1]); // [serial]
|
|
391
|
+
let finalValue = operands[0]; // {name}
|
|
392
|
+
for (let i = 0; i < operandA.length; i += 1) {
|
|
393
|
+
const fieldValue = getDataFromSources(operandA[i], sources, props);
|
|
394
|
+
if (fieldValue === operandA[i]) {
|
|
395
|
+
// did not find value - break here to try second part of conditional
|
|
396
|
+
[, finalValue] = operands;
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
finalValue = finalValue.replace(`{${operandA[i]}}`, fieldValue);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Check if broke out of loop due to missing value
|
|
403
|
+
if (finalValue !== operands[1]) {
|
|
404
|
+
return finalValue;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Look for values for keys to the right of {||}
|
|
408
|
+
for (let j = 0; j < operandB.length; j += 1) {
|
|
409
|
+
const fieldValue = getDataFromSources(operandB[j], sources, props);
|
|
410
|
+
if (fieldValue === operandB[j]) {
|
|
411
|
+
throw new Error(`Could not find value in sources for ${operandA} or ${operandB}`);
|
|
412
|
+
}
|
|
413
|
+
finalValue = finalValue.replace(`{${operandB[j]}}`, fieldValue);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return finalValue;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function setResponseDataFromSources(loopField, sources, props) {
|
|
420
|
+
if (loopField.includes('{||}')) {
|
|
421
|
+
return setConditionalValue(loopField, sources, props);
|
|
422
|
+
}
|
|
423
|
+
let myField = loopField;
|
|
424
|
+
const keys = extractKeysFromBraces(loopField);
|
|
425
|
+
// Handle if val not found ?
|
|
426
|
+
for (let k = 0; k < keys.length; k += 1) {
|
|
427
|
+
const responseKey = keys[k];
|
|
428
|
+
const fieldValue = getDataFromSources(responseKey, sources, props);
|
|
429
|
+
myField = myField.replace(`{${responseKey}}`, fieldValue);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return myField;
|
|
433
|
+
}
|
|
434
|
+
|
|
350
435
|
class RequestHandler {
|
|
351
436
|
/**
|
|
352
437
|
* Request Handler
|
|
@@ -553,19 +638,16 @@ class RequestHandler {
|
|
|
553
638
|
let handleFail = 'fail';
|
|
554
639
|
let ostypePrefix = '';
|
|
555
640
|
let statusValue = 'true';
|
|
641
|
+
const sources = devResp.concat([callProps.requestFields]);
|
|
556
642
|
if (callProps.path) {
|
|
557
643
|
uriPath = `${callProps.path}`;
|
|
558
|
-
|
|
559
644
|
// make any necessary changes to the path
|
|
560
|
-
if (devResp !== null
|
|
561
|
-
const rqKeys = Object.keys(callProps.requestFields);
|
|
562
|
-
|
|
645
|
+
if (devResp !== null) {
|
|
563
646
|
// get the field from the provided device
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
uriPath = uriPath.replace(`{${rqKeys[rq]}}`, fieldValue);
|
|
647
|
+
const pathKeys = extractKeysFromBraces(uriPath);
|
|
648
|
+
for (let pathKey = 0; pathKey < pathKeys.length; pathKey += 1) {
|
|
649
|
+
const fieldValue = getDataFromSources(pathKeys[pathKey], sources, this.props);
|
|
650
|
+
uriPath = uriPath.replace(`{${pathKeys[pathKey]}}`, fieldValue);
|
|
569
651
|
}
|
|
570
652
|
}
|
|
571
653
|
}
|
|
@@ -577,69 +659,41 @@ class RequestHandler {
|
|
|
577
659
|
// go through the query params to check for variable values
|
|
578
660
|
const cpKeys = Object.keys(callQuery);
|
|
579
661
|
for (let cp = 0; cp < cpKeys.length; cp += 1) {
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
for (let rq = 0; rq < rqKeys.length; rq += 1) {
|
|
587
|
-
if (callQuery[cpKeys[cp]] === rqKeys[rq]) {
|
|
588
|
-
const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
|
|
589
|
-
// put the value into the query - if it has been specified in the query
|
|
590
|
-
callQuery[cpKeys[cp]] = fieldValue;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
662
|
+
// get array of values to replace
|
|
663
|
+
const matches = extractKeysFromBraces(callQuery[cpKeys[cp]]);
|
|
664
|
+
for (let m = 0; m < matches.length; m += 1) {
|
|
665
|
+
const queryKey = matches[m];
|
|
666
|
+
const fieldValue = getDataFromSources(queryKey, sources, this.props);
|
|
667
|
+
callQuery[cpKeys[cp]] = callQuery[cpKeys[cp]].replace(`{${queryKey}}`, fieldValue);
|
|
593
668
|
}
|
|
594
|
-
// }
|
|
595
669
|
}
|
|
596
670
|
}
|
|
597
671
|
if (callProps.body) {
|
|
598
672
|
callBody = { ...callProps.body };
|
|
599
|
-
|
|
600
673
|
// go through the body fields to check for variable values
|
|
601
674
|
const cbKeys = Object.keys(callBody);
|
|
602
675
|
for (let cb = 0; cb < cbKeys.length; cb += 1) {
|
|
603
|
-
|
|
676
|
+
const matches = extractKeysFromBraces(callBody[cbKeys[cb]]);
|
|
677
|
+
for (let m = 0; m < matches.length; m += 1) {
|
|
604
678
|
// make any necessary changes to the query params
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
// get the field from the provided device
|
|
609
|
-
for (let rq = 0; rq < rqKeys.length; rq += 1) {
|
|
610
|
-
if (callBody[cbKeys[cb]] === rqKeys[rq]) {
|
|
611
|
-
const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
|
|
612
|
-
|
|
613
|
-
// put the value into the query - if it has been specified in the query
|
|
614
|
-
callBody[cbKeys[cb]] = fieldValue;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
679
|
+
const bodyKey = matches[m];
|
|
680
|
+
const fieldValue = getDataFromSources(bodyKey, sources, this.props);
|
|
681
|
+
callBody[cbKeys[cb]] = callBody[cbKeys[cb]].replace(`{${bodyKey}}`, fieldValue);
|
|
617
682
|
}
|
|
618
|
-
// }
|
|
619
683
|
}
|
|
620
684
|
}
|
|
621
685
|
if (callProps.headers) {
|
|
622
686
|
callHeaders = { ...callProps.headers };
|
|
623
|
-
|
|
624
|
-
// go through the body fields to check for variable values
|
|
687
|
+
// go through the header fields to check for variable values
|
|
625
688
|
const chKeys = Object.keys(callHeaders);
|
|
626
689
|
for (let ch = 0; ch < chKeys.length; ch += 1) {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
for (let rq = 0; rq < rqKeys.length; rq += 1) {
|
|
634
|
-
if (callHeaders[chKeys[ch]] === rqKeys[rq]) {
|
|
635
|
-
const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
|
|
636
|
-
|
|
637
|
-
// put the value into the query - if it has been specified in the query
|
|
638
|
-
callHeaders[chKeys[ch]] = fieldValue;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
690
|
+
const matches = extractKeysFromBraces(callHeaders[chKeys[ch]]);
|
|
691
|
+
for (let m = 0; m < matches.length; m += 1) {
|
|
692
|
+
const headerKey = matches[m];
|
|
693
|
+
// make any necessary changes to the query params
|
|
694
|
+
const fieldValue = getDataFromSources(headerKey, sources, this.props);
|
|
695
|
+
callHeaders[chKeys[ch]] = callQuery[chKeys[ch]].replace(`{${headerKey}}`, fieldValue);
|
|
641
696
|
}
|
|
642
|
-
// }
|
|
643
697
|
}
|
|
644
698
|
}
|
|
645
699
|
if (callProps.handleFailure) {
|
|
@@ -654,9 +708,16 @@ class RequestHandler {
|
|
|
654
708
|
|
|
655
709
|
// !! using Generic makes it easier on the Adapter Builder (just need to change the path)
|
|
656
710
|
// !! you can also replace with a specific call if that is easier
|
|
711
|
+
if (callProps.pagination) {
|
|
712
|
+
metadata.pagination = callProps.pagination;
|
|
713
|
+
metadata.pagination.responseDatakey = callProps.responseDatakey || '';
|
|
714
|
+
}
|
|
657
715
|
return this.expandedGenericAdapterRequest(metadata, uriPath, uriMethod, null, callQuery, callBody, callHeaders, (result, error) => {
|
|
658
716
|
// if we received an error or their is no response on the results return an error
|
|
659
717
|
if (error) {
|
|
718
|
+
if (this.props.stub && error.icode === 'AD.301') {
|
|
719
|
+
return callback(null, error);
|
|
720
|
+
}
|
|
660
721
|
if (handleFail === 'fail') {
|
|
661
722
|
return callback(null, error);
|
|
662
723
|
}
|
|
@@ -690,7 +751,8 @@ class RequestHandler {
|
|
|
690
751
|
const thisDevice = myResult.response[a];
|
|
691
752
|
for (let rf = 0; rf < rfKeys.length; rf += 1) {
|
|
692
753
|
if (rfKeys[rf] !== 'ostypePrefix') {
|
|
693
|
-
|
|
754
|
+
// devResp removed due to conditional issues
|
|
755
|
+
let fieldValue = setResponseDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, callProps.requestFields]);
|
|
694
756
|
|
|
695
757
|
// if the field is ostype - need to add prefix
|
|
696
758
|
if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
|
|
@@ -740,8 +802,7 @@ class RequestHandler {
|
|
|
740
802
|
for (let rf = 0; rf < rfKeys.length; rf += 1) {
|
|
741
803
|
// skip ostypePrefix since it is not a field
|
|
742
804
|
if (rfKeys[rf] !== 'ostypePrefix') {
|
|
743
|
-
let fieldValue =
|
|
744
|
-
|
|
805
|
+
let fieldValue = setResponseDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
|
|
745
806
|
// if the field is ostype - need to add prefix
|
|
746
807
|
if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
|
|
747
808
|
fieldValue = ostypePrefix + fieldValue;
|
|
@@ -781,6 +842,7 @@ class RequestHandler {
|
|
|
781
842
|
});
|
|
782
843
|
} catch (e) {
|
|
783
844
|
const errorObj = this.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, e);
|
|
845
|
+
log.debug(`actual error: ${JSON.stringify(e)}`);
|
|
784
846
|
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
785
847
|
return callback(null, errorObj);
|
|
786
848
|
}
|
package/lib/restHandler.js
CHANGED
|
@@ -1191,7 +1191,9 @@ class RestHandler {
|
|
|
1191
1191
|
const bodyString = buildPayload(entity, action, entitySchema, payload);
|
|
1192
1192
|
|
|
1193
1193
|
if ((callMeth !== 'GET' || entitySchema.sendGetBody) && bodyString !== '{}') {
|
|
1194
|
-
thisAHdata['Content-length']
|
|
1194
|
+
if (!thisAHdata['Content-length'] && !thisAHdata['Content-Length']) {
|
|
1195
|
+
thisAHdata['Content-length'] = Buffer.byteLength(bodyString);
|
|
1196
|
+
}
|
|
1195
1197
|
}
|
|
1196
1198
|
|
|
1197
1199
|
// set up the request to be sent
|
|
@@ -1319,7 +1321,9 @@ class RestHandler {
|
|
|
1319
1321
|
const bodyString = buildPayload('.system', 'healthcheck', healthSchema, payload);
|
|
1320
1322
|
|
|
1321
1323
|
if ((callMeth !== 'GET' || healthSchema.sendGetBody) && bodyString !== '{}') {
|
|
1322
|
-
thisAHdata['Content-length']
|
|
1324
|
+
if (!thisAHdata['Content-length'] && !thisAHdata['Content-Length']) {
|
|
1325
|
+
thisAHdata['Content-length'] = Buffer.byteLength(bodyString);
|
|
1326
|
+
}
|
|
1323
1327
|
}
|
|
1324
1328
|
|
|
1325
1329
|
// set up the request to be sent
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -1046,6 +1046,38 @@
|
|
|
1046
1046
|
"description": "The method of the call to getDevicesFiltered",
|
|
1047
1047
|
"default": "GET"
|
|
1048
1048
|
},
|
|
1049
|
+
"pagination": {
|
|
1050
|
+
"type": "object",
|
|
1051
|
+
"description": "todo",
|
|
1052
|
+
"properties": {
|
|
1053
|
+
"offsetVar": {
|
|
1054
|
+
"type": "string",
|
|
1055
|
+
"description": "Name of variable that defines how to go to next set of results"
|
|
1056
|
+
},
|
|
1057
|
+
"limitVar": {
|
|
1058
|
+
"type": "string",
|
|
1059
|
+
"description": "Name of variable that defines the max results returned in a request"
|
|
1060
|
+
},
|
|
1061
|
+
"incrementBy": {
|
|
1062
|
+
"type": "string",
|
|
1063
|
+
"enum": [
|
|
1064
|
+
"limit",
|
|
1065
|
+
"page"
|
|
1066
|
+
],
|
|
1067
|
+
"description": "How to incremenet offset. Default limit",
|
|
1068
|
+
"default": "limit"
|
|
1069
|
+
},
|
|
1070
|
+
"requestLocation": {
|
|
1071
|
+
"type": "string",
|
|
1072
|
+
"enum": [
|
|
1073
|
+
"query",
|
|
1074
|
+
"body"
|
|
1075
|
+
],
|
|
1076
|
+
"description": "Where in request the pagination data goes",
|
|
1077
|
+
"default": "query"
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1049
1081
|
"query": {
|
|
1050
1082
|
"type": "object",
|
|
1051
1083
|
"description": "The json object with query parameters of the call to getDevicesFiltered",
|
|
@@ -1402,31 +1434,63 @@
|
|
|
1402
1434
|
"properties": {
|
|
1403
1435
|
"path": {
|
|
1404
1436
|
"type": "string",
|
|
1405
|
-
"description": "The fully qualified path of the call to
|
|
1437
|
+
"description": "The fully qualified path of the call to populate the cache (e.g. /rest/api/devices)",
|
|
1406
1438
|
"default": ""
|
|
1407
1439
|
},
|
|
1408
1440
|
"method": {
|
|
1409
1441
|
"type": "string",
|
|
1410
|
-
"description": "The method of the call to
|
|
1442
|
+
"description": "The method of the call to populate the cache",
|
|
1411
1443
|
"default": "GET"
|
|
1412
1444
|
},
|
|
1445
|
+
"pagination": {
|
|
1446
|
+
"type": "object",
|
|
1447
|
+
"description": "todo",
|
|
1448
|
+
"properties": {
|
|
1449
|
+
"offsetVar": {
|
|
1450
|
+
"type": "string",
|
|
1451
|
+
"description": "Name of variable that defines how to go to next set of results"
|
|
1452
|
+
},
|
|
1453
|
+
"limitVar": {
|
|
1454
|
+
"type": "string",
|
|
1455
|
+
"description": "Name of variable that defines the max results returned in a request"
|
|
1456
|
+
},
|
|
1457
|
+
"incrementBy": {
|
|
1458
|
+
"type": "string",
|
|
1459
|
+
"enum": [
|
|
1460
|
+
"limit",
|
|
1461
|
+
"page"
|
|
1462
|
+
],
|
|
1463
|
+
"description": "How to incremenet offset. Default limit",
|
|
1464
|
+
"default": "limit"
|
|
1465
|
+
},
|
|
1466
|
+
"requestLocation": {
|
|
1467
|
+
"type": "string",
|
|
1468
|
+
"enum": [
|
|
1469
|
+
"query",
|
|
1470
|
+
"body"
|
|
1471
|
+
],
|
|
1472
|
+
"description": "Where in request the pagination data goes",
|
|
1473
|
+
"default": "query"
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
},
|
|
1413
1477
|
"query": {
|
|
1414
1478
|
"type": "object",
|
|
1415
|
-
"description": "The json object with query parameters of the call to
|
|
1479
|
+
"description": "The json object with query parameters of the call to populate the cache",
|
|
1416
1480
|
"additionalProperties": {
|
|
1417
1481
|
"type": ["string", "number"]
|
|
1418
1482
|
}
|
|
1419
1483
|
},
|
|
1420
1484
|
"body": {
|
|
1421
1485
|
"type": "object",
|
|
1422
|
-
"description": "The json object with body of the call to
|
|
1486
|
+
"description": "The json object with body of the call to populate the cache",
|
|
1423
1487
|
"additionalProperties": {
|
|
1424
1488
|
"type": ["string", "number"]
|
|
1425
1489
|
}
|
|
1426
1490
|
},
|
|
1427
1491
|
"headers": {
|
|
1428
1492
|
"type": "object",
|
|
1429
|
-
"description": "The json object with headers of the call to
|
|
1493
|
+
"description": "The json object with headers of the call to populate the cache",
|
|
1430
1494
|
"additionalProperties": {
|
|
1431
1495
|
"type": ["string", "number"]
|
|
1432
1496
|
}
|
|
@@ -1442,7 +1506,7 @@
|
|
|
1442
1506
|
},
|
|
1443
1507
|
"requestFields": {
|
|
1444
1508
|
"type": "object",
|
|
1445
|
-
"description": "The json object with response fields of the call to
|
|
1509
|
+
"description": "The json object with response fields of the call to populate the cache",
|
|
1446
1510
|
"additionalProperties": {
|
|
1447
1511
|
"type": ["string", "number"]
|
|
1448
1512
|
},
|
|
@@ -1455,7 +1519,7 @@
|
|
|
1455
1519
|
},
|
|
1456
1520
|
"responseFields": {
|
|
1457
1521
|
"type": "object",
|
|
1458
|
-
"description": "The json object with response fields of the call to
|
|
1522
|
+
"description": "The json object with response fields of the call to populate the cache",
|
|
1459
1523
|
"additionalProperties": {
|
|
1460
1524
|
"type": ["string", "number"]
|
|
1461
1525
|
}
|