@itentialopensource/adapter-utils 4.44.9

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.
@@ -0,0 +1,1309 @@
1
+ /* @copyright Itential, LLC 2018 */
2
+
3
+ // Set globals
4
+ /* global log */
5
+
6
+ /* NodeJS internal utilities */
7
+ const querystring = require('querystring');
8
+ const jsonQuery = require('json-query');
9
+ const jsonxml = require('jsontoxml');
10
+ const xml2js = require('xml2js');
11
+
12
+ let transUtilInst = null;
13
+ let connectorInst = null;
14
+
15
+ // Other global variables
16
+ let id = null;
17
+ let versionGl = null;
18
+ let basepathGl = null;
19
+ let globalRequestGl = null;
20
+ let returnRawGl = false;
21
+ let encodePath = true;
22
+
23
+ // INTERNAL FUNCTIONS
24
+ /*
25
+ * INTERNAL FUNCTION: Get the best match for the mock data response
26
+ */
27
+ function matchResponse(uriPath, method, type, mockresponses) {
28
+ // Go through the mock data keys to find the proper data to return
29
+ for (let p = 0; p < mockresponses.length; p += 1) {
30
+ // is this the mock data for this call
31
+ if (Object.hasOwnProperty.call(mockresponses[p], 'name')
32
+ && uriPath === mockresponses[p].name) {
33
+ if (Object.hasOwnProperty.call(mockresponses[p], 'method')
34
+ && method.toUpperCase() === mockresponses[p].method.toUpperCase()) {
35
+ if (Object.hasOwnProperty.call(mockresponses[p], 'type')
36
+ && type.toUpperCase() === mockresponses[p].type.toUpperCase()) {
37
+ // This is the Key we really want as it best matches the request
38
+ if (Object.hasOwnProperty.call(mockresponses[p], 'key')) {
39
+ return mockresponses[p].key;
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ return null;
47
+ }
48
+
49
+ /*
50
+ * INTERNAL FUNCTION: recursively inspect body data if heirarchical
51
+ */
52
+ function checkBodyData(uriPath, method, reqBdObj, mockresponses) {
53
+ let specificResp = null;
54
+
55
+ if (reqBdObj) {
56
+ const reqBKeys = Object.keys(reqBdObj);
57
+
58
+ // go through each key in the passed in object
59
+ for (let k = 0; k < reqBKeys.length; k += 1) {
60
+ const bVal = reqBdObj[reqBKeys[k]];
61
+
62
+ if (bVal !== undefined && bVal !== null && bVal !== '') {
63
+ // if the field is an object and not an array - recursively call with the new field value
64
+ if (typeof bVal === 'object' && !Array.isArray(bVal)) {
65
+ specificResp = checkBodyData(uriPath, method, bVal, mockresponses);
66
+ } else if (Array.isArray(bVal) && bVal.length > 0 && (typeof bVal[0] === 'object')) {
67
+ // if the field is an array containing objects - recursively call with each object in the array
68
+ for (let a = 0; a < bVal.length; a += 1) {
69
+ specificResp = checkBodyData(uriPath, method, bVal[a], mockresponses);
70
+
71
+ // if the data match is found break the for loop - will return below
72
+ if (specificResp !== null) {
73
+ break;
74
+ }
75
+ }
76
+ } else if (Array.isArray(bVal)) {
77
+ // if an array of data, need to check each data in the array
78
+ for (let a = 0; a < bVal.length; a += 1) {
79
+ // should match fieldName-fieldValue
80
+ const compStr = `${reqBKeys[k]}-${bVal[a]}`;
81
+ specificResp = matchResponse(uriPath, method, compStr, mockresponses);
82
+
83
+ // if the data match is found break the for loop - will return below
84
+ if (specificResp !== null) {
85
+ break;
86
+ }
87
+ }
88
+ } else {
89
+ // should match fieldName-fieldValue
90
+ const compStr = `${reqBKeys[k]}-${bVal}`;
91
+ specificResp = matchResponse(uriPath, method, compStr, mockresponses);
92
+ }
93
+
94
+ if (specificResp !== null) {
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ }
100
+ return specificResp;
101
+ }
102
+
103
+ /**
104
+ * INTERNAL FUNCTION
105
+ *
106
+ * @summary Standard rest entity(ies) extracted as it it would be redundant code.
107
+ *
108
+ * @function handleRestRequest
109
+ * @param {Object} request - the request to make (required)
110
+ * @param {String} entityId - the id of the entity we are retrieving (optional)
111
+ * @param {String} entitySchema - the entity schema (required)
112
+ * @param {Object} callProperties - properties to override on this call (optional)
113
+ * @param {String} filter - json query filter to apply to the returned data (optional)
114
+ * @param {Boolean} retReqHdr - whether to return the request headers (optional)
115
+ * @param {Function} callback - a callback function to return the result of the request
116
+ */
117
+ function handleRestRequest(request, entityId, entitySchema, callProperties, filter, retReqHdr, callback) {
118
+ const origin = `${id}-restHandler-handleRestRequest`;
119
+ log.trace(origin);
120
+
121
+ try {
122
+ // perform the request to get entity(ies)
123
+ return connectorInst.performRequest(request, entitySchema, callProperties, (resObj, perror) => {
124
+ if (perror) {
125
+ let retError = null;
126
+ const retErrorObj = perror;
127
+
128
+ // if the request header is not needed remove it
129
+ if (retReqHdr === false && retErrorObj.reqHdr) {
130
+ delete retErrorObj.reqHdr;
131
+ }
132
+
133
+ // set the normal headers based on the type of data for the call
134
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'PLAIN') {
135
+ // return the error response
136
+ return callback(null, retErrorObj);
137
+ }
138
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'XML') {
139
+ // return the error response
140
+ return callback(null, retErrorObj);
141
+ }
142
+
143
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'XML2JSON') {
144
+ try {
145
+ // if we have a response, try to parse it to JSON
146
+ const parser = new xml2js.Parser({ explicitArray: false, attrkey: '_attr' });
147
+ if (perror.response) {
148
+ return parser.parseString(perror.response, (error, result) => {
149
+ if (error) {
150
+ log.warn(`${origin}: Unable to parse xml to json ${error}`);
151
+ return callback(null, retErrorObj);
152
+ }
153
+ retErrorObj.response = result;
154
+ return callback(null, retErrorObj);
155
+ });
156
+ }
157
+ return callback(null, retErrorObj);
158
+ } catch (ex) {
159
+ log.warn(`${origin}: Unable to parse json ${ex}`);
160
+ return callback(null, retErrorObj);
161
+ }
162
+ }
163
+
164
+ // process the error response - parse it if possible
165
+ if (perror.response) {
166
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'URLENCODE') {
167
+ // return the response
168
+ retError = querystring.parse(perror.response.trim());
169
+ } else {
170
+ try {
171
+ retError = JSON.parse(perror.response.trim());
172
+ } catch (ex) {
173
+ // otherwise log parse failure but still return the unparsed error
174
+ log.error(`${origin}: An error occurred parsing the error JSON: ${ex}`);
175
+ }
176
+ }
177
+ }
178
+
179
+ // if the return error message was JSON then return the parsed object
180
+ if (retError !== null) {
181
+ retErrorObj.response = retError;
182
+ }
183
+
184
+ // return the error response
185
+ return callback(null, retErrorObj);
186
+ }
187
+
188
+ let respObjKey = null;
189
+
190
+ if (entitySchema.responseObjects) {
191
+ const responseKeys = entitySchema.responseObjects;
192
+ const uriPath = request.origPath;
193
+ const method = request.method.toUpperCase();
194
+ const reqBody = request.body;
195
+ const reqPath = request.path;
196
+
197
+ // if there is a request body, see if there is something that matches a specific input
198
+ if (reqBody && (!entitySchema || !entitySchema.requestDatatype
199
+ || entitySchema.requestDatatype.toUpperCase() === 'JSON' || entitySchema.requestDatatype.toUpperCase() === 'URLENCODE')) {
200
+ let reqBdObj = null;
201
+ if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'URLENCODE') {
202
+ reqBdObj = querystring.parse(reqBody.trim());
203
+ } else {
204
+ reqBdObj = JSON.parse(reqBody.trim());
205
+ }
206
+
207
+ respObjKey = checkBodyData(uriPath, method, reqBdObj, responseKeys);
208
+ }
209
+
210
+ // if there are path variables, see if there is something that matches a specific variable
211
+ if (respObjKey === null && uriPath.indexOf('{pathv') >= 0) {
212
+ const uriTemp = uriPath.split('?');
213
+ const actTemp = reqPath.split('?');
214
+ uriTemp[0] = uriTemp[0].replace(/{pathv/g, '/{pathv');
215
+ uriTemp[0] = uriTemp[0].replace(/{version/g, '/{version');
216
+ uriTemp[0] = uriTemp[0].replace(/{base/g, '/{base');
217
+ uriTemp[0] = uriTemp[0].replace(/\/\//g, '/');
218
+
219
+ // remove basepath from both paths
220
+ // get rid of base path from the uriPath
221
+ uriTemp[0] = uriTemp[0].replace(/\/{base_path}/g, '');
222
+ // if a base path was added to the request, remove it
223
+ if (callProperties && callProperties.base_path && callProperties.base_path !== '/') {
224
+ actTemp[0] = actTemp[0].replace(callProperties.base_path, '');
225
+ } else if (basepathGl && basepathGl !== '/') {
226
+ actTemp[0] = actTemp[0].replace(basepathGl, '');
227
+ }
228
+
229
+ // remove version from both paths
230
+ // get rid of version from the uriPath
231
+ uriTemp[0] = uriTemp[0].replace(/\/{version}/g, '');
232
+ // if a version was added to the request, remove it
233
+ if (callProperties && callProperties.version) {
234
+ actTemp[0] = actTemp[0].replace(`/${callProperties.version}`, '');
235
+ } else if (versionGl && versionGl !== '/') {
236
+ actTemp[0] = actTemp[0].replace(`/${versionGl}`, '');
237
+ }
238
+
239
+ const uriArray = uriTemp[0].split('/');
240
+ const actArray = actTemp[0].split('/');
241
+
242
+ // the number of items in both should be the same
243
+ if (uriArray.length === actArray.length) {
244
+ for (let i = 0; i < uriArray.length; i += 1) {
245
+ if (uriArray[i].indexOf('{pathv') >= 0) {
246
+ respObjKey = matchResponse(uriPath, method, actArray[i], responseKeys);
247
+
248
+ if (respObjKey !== null) {
249
+ break;
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ // if there are queiries or options, see if there is something that matches a specific input
257
+ if (respObjKey === null && reqPath.indexOf('?') >= 0) {
258
+ const queries = reqPath.substring(reqPath.indexOf('?') + 1);
259
+ const queryArr = queries.split('&');
260
+
261
+ for (let q = 0; q < queryArr.length; q += 1) {
262
+ let qval = queryArr[q];
263
+ if (qval !== undefined && qval !== null && qval !== '') {
264
+ // stringifies it - in case it was not a string
265
+ qval = `${qval}`;
266
+ respObjKey = matchResponse(uriPath, method, qval, responseKeys);
267
+
268
+ if (respObjKey !== null) {
269
+ break;
270
+ }
271
+ }
272
+ }
273
+ }
274
+
275
+ // if there is a request body, see if there is a specific response for body
276
+ if (respObjKey === null && reqBody) {
277
+ respObjKey = matchResponse(uriPath, method, 'WITHBODY', responseKeys);
278
+ }
279
+
280
+ // if there are path variables, see if there is a specific response for path vars
281
+ if (respObjKey === null && uriPath.indexOf('{pathv') >= 0) {
282
+ const uriTemp = uriPath.split('?');
283
+ const actTemp = reqPath.split('?');
284
+ uriTemp[0] = uriTemp[0].replace(/{pathv/g, '/{pathv');
285
+ uriTemp[0] = uriTemp[0].replace(/{version/g, '/{version');
286
+ uriTemp[0] = uriTemp[0].replace(/{base/g, '/{base');
287
+ uriTemp[0] = uriTemp[0].replace(/\/\//g, '/');
288
+
289
+ // remove basepath from both paths
290
+ // get rid of base path from the uriPath
291
+ uriTemp[0] = uriTemp[0].replace(/\/{base_path}/g, '');
292
+ // if a base path was added to the request, remove it
293
+ if (callProperties && callProperties.base_path && callProperties.base_path !== '/') {
294
+ actTemp[0] = actTemp[0].replace(callProperties.base_path, '');
295
+ } else if (basepathGl && basepathGl !== '/') {
296
+ actTemp[0] = actTemp[0].replace(basepathGl, '');
297
+ }
298
+
299
+ // remove version from both paths
300
+ // get rid of version from the uriPath
301
+ uriTemp[0] = uriTemp[0].replace(/\/{version}/g, '');
302
+ // if a version was added to the request, remove it
303
+ if (callProperties && callProperties.version) {
304
+ actTemp[0] = actTemp[0].replace(`/${callProperties.version}`, '');
305
+ } else if (versionGl && versionGl !== '/') {
306
+ actTemp[0] = actTemp[0].replace(`/${versionGl}`, '');
307
+ }
308
+
309
+ const uriArray = uriTemp[0].split('/');
310
+ const actArray = actTemp[0].split('/');
311
+
312
+ // the number of items in both should be the same
313
+ if (uriArray.length === actArray.length) {
314
+ let cnt = 1;
315
+ for (let i = 0; i < uriArray.length; i += 1) {
316
+ if (uriArray[i].indexOf('{pathv') >= 0) {
317
+ respObjKey = matchResponse(uriPath, method, `WITHPATHV${cnt}`, responseKeys);
318
+
319
+ if (respObjKey !== null) {
320
+ break;
321
+ }
322
+ cnt += 1;
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ // if there are queiries or options, see if there is a specific response for query or options
329
+ if (respObjKey === null && uriPath.indexOf('?') >= 0) {
330
+ respObjKey = matchResponse(uriPath, method, 'WITHQUERY', responseKeys);
331
+
332
+ if (respObjKey === null) {
333
+ respObjKey = matchResponse(uriPath, method, 'WITHOPTIONS', responseKeys);
334
+ }
335
+ }
336
+
337
+ if (respObjKey === null) {
338
+ respObjKey = matchResponse(uriPath, method, 'DEFAULT', responseKeys);
339
+ }
340
+
341
+ if (respObjKey === null) {
342
+ respObjKey = '';
343
+ }
344
+ }
345
+
346
+ let retResponse = resObj.response;
347
+ const retObject = resObj;
348
+
349
+ // if the request header is not needed remove it
350
+ if (retReqHdr === false && retObject.reqHdr) {
351
+ delete retObject.reqHdr;
352
+ }
353
+
354
+ // if we want the raw response
355
+ if (returnRawGl || (callProperties && callProperties.request && callProperties.request.return_raw)) {
356
+ retObject.raw = resObj.response;
357
+ }
358
+
359
+ // if id, log response (if all - too much to log all)
360
+ if (entityId === 'nomap') {
361
+ log.debug(`${origin}: RESPONSE: ${resObj.response}`);
362
+
363
+ // if no mapping (do not care about response just that we did not
364
+ // error) set response
365
+ retObject.response = 'success';
366
+ return callback(retObject);
367
+ }
368
+
369
+ // if the data is not json we can not perform the extended capabilities so just return it
370
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'PLAIN') {
371
+ log.debug(`${origin}: RESPONSE: ${resObj.response}`);
372
+
373
+ // return the response
374
+ return callback(retObject);
375
+ }
376
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'XML') {
377
+ log.debug(`${origin}: RESPONSE: ${resObj.response}`);
378
+
379
+ // return the response
380
+ return callback(retObject);
381
+ }
382
+
383
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'XML2JSON') {
384
+ log.debug(`${origin}: RESPONSE: ${resObj.response}`);
385
+
386
+ try {
387
+ const parser = new xml2js.Parser({ explicitArray: false, attrkey: '_attr' });
388
+ return parser.parseString(resObj.response, (error, result) => {
389
+ if (error) {
390
+ log.warn(`${origin}: Unable to parse xml to json ${error}`);
391
+ return callback(retObject);
392
+ }
393
+ retObject.response = result;
394
+ return callback(retObject);
395
+ });
396
+ } catch (ex) {
397
+ log.warn(`${origin}: Unable to get json from xml ${ex}`);
398
+ return callback(retObject);
399
+ }
400
+ }
401
+
402
+ // what if nothing comes back - nothing to do
403
+ if (resObj.response === null || resObj.response === '' || resObj.response === '""') {
404
+ log.warn(`${origin}: No data returned on call`);
405
+ return callback(retObject);
406
+ }
407
+
408
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'URLENCODE') {
409
+ // return the response
410
+ retResponse = querystring.parse(resObj.response.trim());
411
+ } else {
412
+ // process the response - parse it
413
+ try {
414
+ retResponse = JSON.parse(resObj.response.trim());
415
+ } catch (ex) {
416
+ // otherwise log parse failure and return the unparsed response
417
+ log.warn(`${origin}: An error occurred parsing the resulting JSON: ${ex}`);
418
+ return callback(retObject);
419
+ }
420
+ }
421
+
422
+ // Make the call to translate the received Entity to Pronghorn Entity
423
+ if (respObjKey !== '') {
424
+ // get the return data and added the translated response to the return Object
425
+ const returnFieldData = jsonQuery(respObjKey, { data: retResponse }).value;
426
+
427
+ // if the response is an array, log the first item
428
+ if (Array.isArray(returnFieldData)) {
429
+ log.debug(`${origin}: RESPONSE (FIRST): ${JSON.stringify(returnFieldData[0])}`);
430
+ } else {
431
+ log.debug(`${origin}: RESPONSE: ${JSON.stringify(returnFieldData)}`);
432
+ }
433
+
434
+ // if the data is not an object - just return what it is
435
+ if (!Array.isArray(returnFieldData) && typeof returnFieldData !== 'object') {
436
+ retObject.response = returnFieldData;
437
+ return callback(retObject);
438
+ }
439
+
440
+ retObject.response = transUtilInst.mapFromOutboundEntity(returnFieldData, entitySchema.responseSchema);
441
+
442
+ // if filtering, filter the data
443
+ if (filter) {
444
+ retObject.response = jsonQuery(filter, { data: retObject.response }).value;
445
+ }
446
+
447
+ return callback(retObject);
448
+ }
449
+
450
+ if (Array.isArray(retResponse)) {
451
+ // if the response is an array, log the first item
452
+ log.debug(`${origin}: RESPONSE (FIRST): ${JSON.stringify(retResponse[0])}`);
453
+ } else {
454
+ log.debug(`${origin}: RESPONSE: ${JSON.stringify(retResponse)}`);
455
+ }
456
+
457
+ // if the data is not an object - just return what it is
458
+ if (!Array.isArray(retResponse) && typeof retResponse !== 'object') {
459
+ retObject.response = retResponse;
460
+ return callback(retObject);
461
+ }
462
+
463
+ // added the translated response to the return Object
464
+ retObject.response = transUtilInst.mapFromOutboundEntity(retResponse, entitySchema.responseSchema);
465
+
466
+ // if filtering, filter the data
467
+ if (filter) {
468
+ retObject.response = jsonQuery(filter, { data: retObject.response }).value;
469
+ }
470
+
471
+ return callback(retObject);
472
+ });
473
+ } catch (e) {
474
+ // create the error object
475
+ const errorObj = {
476
+ origin,
477
+ type: 'Caught Exception',
478
+ vars: [],
479
+ exception: e
480
+ };
481
+
482
+ log.error(`${origin}: Caught Exception: ${e}`);
483
+ return callback(null, errorObj);
484
+ }
485
+ }
486
+
487
+ /**
488
+ * @summary Build the path for the request
489
+ *
490
+ * @function buildRequestPath
491
+ * @param {String} entity - the name of the entity action is on. (required)
492
+ * @param {String} action - the name of the action being executed. (required)
493
+ * @param {Object} entitySchema - the entity schema for the entity and action. (required)
494
+ * @param {String} reqPath - the entitypath from the entity action (required)
495
+ * @param {Array} uriPathVars - the array of path variables (optional)
496
+ * @param {Object} uriQuery - the object containing the query to add to the url (optional)
497
+ * @param {Object} uriOptions - the object containing the options to add to the url (optional)
498
+ */
499
+ function buildRequestPath(entity, action, entitySchema, reqPath, uriPathVars, uriQuery, uriOptions, callProperties) {
500
+ const origin = `${id}-restHandler-buildRequestPath`;
501
+ log.trace(origin);
502
+
503
+ // create the generic part of an error object
504
+ const errorObj = {
505
+ origin
506
+ };
507
+
508
+ try {
509
+ let uriPath = reqPath;
510
+
511
+ // if the path has a base path parameter in it, need to replace it
512
+ let bpathStr = '{base_path}';
513
+ if (uriPath.indexOf(bpathStr) >= 0) {
514
+ // be able to support this if the base path has a slash before it or not
515
+ if (uriPath.indexOf('/{base_path}') >= 0) {
516
+ bpathStr = '/{base_path}';
517
+ }
518
+
519
+ // replace with base path if we have one, otherwise remove base path
520
+ if (callProperties && callProperties.base_path) {
521
+ // if no leading /, insert one
522
+ if (callProperties.base_path.indexOf('/') !== 0) {
523
+ uriPath = uriPath.replace(bpathStr, `/${callProperties.base_path}`);
524
+ } else {
525
+ uriPath = uriPath.replace(bpathStr, callProperties.base_path);
526
+ }
527
+ } else if (basepathGl) {
528
+ // if no leading /, insert one
529
+ if (basepathGl.indexOf('/') !== 0) {
530
+ uriPath = uriPath.replace(bpathStr, `/${basepathGl}`);
531
+ } else {
532
+ uriPath = uriPath.replace(bpathStr, basepathGl);
533
+ }
534
+ } else {
535
+ uriPath = uriPath.replace(bpathStr, '');
536
+ }
537
+ }
538
+
539
+ // if the path has a version parameter in it, need to replace it
540
+ let versStr = '{version}';
541
+ if (uriPath.indexOf(versStr) >= 0) {
542
+ // be able to support this if the version has a slash before it or not
543
+ if (uriPath.indexOf('/{version}') >= 0) {
544
+ versStr = '/{version}';
545
+ }
546
+
547
+ // replace with version if we have one, otherwise remove version
548
+ if (callProperties && callProperties.version) {
549
+ uriPath = uriPath.replace(versStr, `/${encodeURIComponent(callProperties.version)}`);
550
+ } else if (versionGl) {
551
+ uriPath = uriPath.replace(versStr, `/${encodeURIComponent(versionGl)}`);
552
+ } else {
553
+ uriPath = uriPath.replace(versStr, '');
554
+ }
555
+ }
556
+
557
+ // if there are URI path variables that have been provided, need to add
558
+ // them to the path
559
+ if (uriPathVars && uriPathVars.length > 0) {
560
+ for (let p = 0; p < uriPathVars.length; p += 1) {
561
+ const vnum = p + 1;
562
+ const holder = `pathv${vnum.toString()}`;
563
+ const hindex = uriPath.indexOf(holder);
564
+
565
+ // if path variable is in the url, replace it!!!
566
+ if (hindex >= 0 && uriPathVars[p] !== null && uriPathVars[p] !== '') {
567
+ // with the provided id
568
+ let idString = '';
569
+
570
+ // check if the current URI path ends with a slash (may require
571
+ // slash at end)
572
+ if (uriPath[hindex - 2] === '/' || uriPath[hindex - 2] === ':') {
573
+ // ends with a slash need to add slash to end
574
+ if (encodePath === true) {
575
+ idString = encodeURIComponent(uriPathVars[p]);
576
+ } else {
577
+ idString = uriPathVars[p];
578
+ }
579
+ } else {
580
+ // otherwise add / to start
581
+ idString = '/';
582
+ if (encodePath === true) {
583
+ idString += encodeURIComponent(uriPathVars[p]);
584
+ } else {
585
+ idString += uriPathVars[p];
586
+ }
587
+ }
588
+
589
+ // replace the id in url with the id string
590
+ uriPath = uriPath.replace(`{${holder}}`, idString);
591
+ }
592
+ }
593
+ }
594
+
595
+ // need to remove all of the remaining path holders from the URI
596
+ while (uriPath.indexOf('{pathv') >= 0) {
597
+ let sIndex = uriPath.indexOf('{pathv');
598
+ const eIndex = uriPath.indexOf('}', sIndex);
599
+
600
+ // if there is a / before the {pathv} need to remove it
601
+ if (uriPath[sIndex - 1] === '/' || uriPath[sIndex - 1] === ':') {
602
+ sIndex -= 1;
603
+ }
604
+
605
+ if (sIndex > 0) {
606
+ // add the start of the path
607
+ let tempStr = uriPath.substring(0, sIndex);
608
+
609
+ if (eIndex < uriPath.length) {
610
+ // add the end of the path
611
+ tempStr += uriPath.substring(eIndex + 1);
612
+ }
613
+
614
+ uriPath = tempStr;
615
+ } else if (eIndex > 0 && eIndex < uriPath.length) {
616
+ // add the end of the path
617
+ uriPath = uriPath.substring(eIndex + 1);
618
+ } else {
619
+ // should not get here - there is some issue in the uripath - missing
620
+ // an end or the path is just {pathv#}
621
+ // add the specific pieces of the error object
622
+ errorObj.type = 'Invalid Action File';
623
+ errorObj.vars = ['missing entity path', `${entity}/${action}`];
624
+
625
+ // log and throw the error
626
+ log.error(`${origin}: Path is required for ${entity}-${action}`);
627
+ throw new Error(JSON.stringify(errorObj));
628
+ }
629
+ }
630
+
631
+ // prepare the uri options we received
632
+ let thisOdata = transUtilInst.formatInputData(uriOptions);
633
+
634
+ // only add global options if there are global options to add
635
+ if (globalRequestGl && globalRequestGl.uriOptions
636
+ && Object.keys(globalRequestGl.uriOptions).length > 0) {
637
+ thisOdata = transUtilInst.mergeObjects(thisOdata, globalRequestGl.uriOptions);
638
+ }
639
+ let optionString = '';
640
+
641
+ // need to format the option string
642
+ if (thisOdata !== null) {
643
+ optionString += querystring.stringify(thisOdata);
644
+ }
645
+
646
+ // prepare the query parameters we received
647
+ const thisQdata = transUtilInst.formatInputData(uriQuery);
648
+
649
+ // if this is a get with query parameters, need to make them part of
650
+ // the request
651
+ if (uriPath.indexOf('{query}') >= 0 && thisQdata !== null && Object.keys(thisQdata).length > 0) {
652
+ // request type set for determining required fields
653
+ thisQdata.ph_request_type = action;
654
+
655
+ // map the data we received for query
656
+ const systemQuery = transUtilInst.mapToOutboundEntity(thisQdata, entitySchema.requestSchema);
657
+
658
+ if (!systemQuery) {
659
+ // should not get here - there is some issue in the uripath - missing
660
+ // an end or the path is just {pathv#}
661
+ // add the specific pieces of the error object
662
+ errorObj.type = 'Query Not Translated';
663
+ errorObj.vars = [];
664
+
665
+ // log and throw the error
666
+ log.error(`${origin}: Query not translated`);
667
+ throw new Error(JSON.stringify(errorObj));
668
+ }
669
+
670
+ let addquery = '';
671
+
672
+ // make sure we still have queries (that what was in the query is
673
+ // legit)
674
+ if (Object.keys(systemQuery).length > 0) {
675
+ // need to format the option string
676
+ if (entitySchema.querykey) {
677
+ addquery = entitySchema.querykey;
678
+ }
679
+ if (systemQuery !== null) {
680
+ addquery += querystring.stringify(systemQuery);
681
+ }
682
+ }
683
+
684
+ // if there is a query key in the path and the query
685
+ if (addquery.indexOf('?') >= 0 && uriPath.indexOf('?') >= 0) {
686
+ // need to remove one of them
687
+ const squery = uriPath.indexOf('?');
688
+ let equery = uriPath.indexOf('{query}');
689
+ equery += 7;
690
+ let tempPath = uriPath.substring(0, squery);
691
+ tempPath += addquery;
692
+
693
+ if (equery < uriPath.length) {
694
+ tempPath += uriPath.substring(equery + 7);
695
+ }
696
+
697
+ uriPath = tempPath;
698
+ } else {
699
+ // if not, just replace the query
700
+ uriPath = uriPath.replace('{query}', addquery);
701
+ }
702
+
703
+ // if there are options, add them to the URL
704
+ if (optionString !== '') {
705
+ uriPath += `&${optionString}`;
706
+ }
707
+
708
+ // verify that the uriPath starts with a slash and only 1 slash
709
+ while (uriPath.indexOf('//') === 0) {
710
+ uriPath = uriPath.substring(1);
711
+ }
712
+ if (uriPath.indexOf('/') !== 0) {
713
+ uriPath = `/${uriPath}`;
714
+ }
715
+
716
+ // remove any double slashes that may be in the path - can happen if base path is / or ends in a /
717
+ uriPath = uriPath.replace(/\/\//g, '/');
718
+
719
+ const result = {
720
+ path: uriPath
721
+ };
722
+
723
+ return result;
724
+ }
725
+
726
+ // if there is a query key in the path
727
+ if (uriPath.indexOf('{query}') >= 0 && uriPath.indexOf('?') >= 0) {
728
+ // need to remove the key as well
729
+ const squery = uriPath.indexOf('?');
730
+ let equery = uriPath.indexOf('{query}');
731
+ equery += 7;
732
+ let tempPath = uriPath.substring(0, squery);
733
+
734
+ if (equery < uriPath.length) {
735
+ tempPath += uriPath.substring(equery);
736
+ }
737
+
738
+ uriPath = tempPath;
739
+ } else if (uriPath.indexOf('{query}') >= 0) {
740
+ // if not, just replace the query
741
+ uriPath = uriPath.replace('{query}', '');
742
+ }
743
+
744
+ // if there are options, add them to the URL
745
+ if (optionString !== '') {
746
+ if (uriPath.indexOf('?') < 0) {
747
+ uriPath += `?${optionString}`;
748
+ } else {
749
+ uriPath += `${optionString}`;
750
+ }
751
+ }
752
+
753
+ // verify that the uriPath starts with a slash and only 1 slash
754
+ while (uriPath.indexOf('//') === 0) {
755
+ uriPath = uriPath.substring(1);
756
+ }
757
+ if (uriPath.indexOf('/') !== 0) {
758
+ uriPath = `/${uriPath}`;
759
+ }
760
+
761
+ // remove any double slashes that may be in the path - can happen if base path is / or ends in a /
762
+ uriPath = uriPath.replace(/\/\//g, '/');
763
+
764
+ const result = {
765
+ path: uriPath
766
+ };
767
+
768
+ return result;
769
+ } catch (e) {
770
+ return transUtilInst.checkAndThrow(e, origin, 'Issue building request path');
771
+ }
772
+ }
773
+
774
+ /**
775
+ * @summary Method to merge the headers for the request
776
+ *
777
+ * @function mergeHeaders
778
+ * @param {Object} addlHeaders - the headers from the request (optional)
779
+ * @param {Object} entitySchema - the entity schema for the entity and action. (optional)
780
+ *
781
+ * @return {Object} - the merged headers
782
+ */
783
+ function mergeHeaders(addlHeaders, entitySchema) {
784
+ const origin = `${id}-restHandler-mergeHeaders`;
785
+ log.trace(origin);
786
+
787
+ // prepare the additional headers we received
788
+ let thisAHdata = transUtilInst.formatInputData(addlHeaders);
789
+
790
+ // only add action headers if there are action headers to add
791
+ if (entitySchema && entitySchema.headers && Object.keys(entitySchema.headers).length > 0) {
792
+ thisAHdata = transUtilInst.mergeObjects(thisAHdata, entitySchema.headers);
793
+ }
794
+
795
+ // only add global headers if there are global headers to add
796
+ if (globalRequestGl && globalRequestGl.addlHeaders && Object.keys(globalRequestGl.addlHeaders).length > 0) {
797
+ thisAHdata = transUtilInst.mergeObjects(thisAHdata, globalRequestGl.addlHeaders);
798
+ }
799
+
800
+ // if no header data passed in create empty
801
+ if (!thisAHdata) {
802
+ thisAHdata = {};
803
+ }
804
+
805
+ // set the Content Type headers based on the type of request data for the call
806
+ if (thisAHdata['Content-Type'] === undefined || thisAHdata['Content-Type'] === null) {
807
+ if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'PLAIN') {
808
+ // add the Plain headers if they were not set already
809
+ thisAHdata['Content-Type'] = 'text/plain';
810
+ } else if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'XML') {
811
+ // add the XML headers if they were not set already
812
+ thisAHdata['Content-Type'] = 'application/xml';
813
+ } else if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'URLENCODE') {
814
+ // add the URLENCODE headers if they were not set already
815
+ thisAHdata['Content-Type'] = 'application/x-www-form-urlencoded';
816
+ } else {
817
+ // add the JSON headers if they were not set already
818
+ thisAHdata['Content-Type'] = 'application/json';
819
+ }
820
+ }
821
+ // set the Accept headers based on the type of response data for the call
822
+ if (thisAHdata.Accept === undefined || thisAHdata.Accept === null) {
823
+ if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'PLAIN') {
824
+ // add the Plain headers if they were not set already
825
+ thisAHdata.Accept = 'text/plain';
826
+ } else if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'XML') {
827
+ // add the XML headers if they were not set already
828
+ thisAHdata.Accept = 'application/xml';
829
+ } else if (entitySchema && entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'URLENCODE') {
830
+ // add the URLENCODE headers if they were not set already
831
+ thisAHdata.Accept = 'application/x-www-form-urlencoded';
832
+ } else {
833
+ // add the JSON headers if they were not set already
834
+ thisAHdata.Accept = 'application/json';
835
+ }
836
+ }
837
+
838
+ if (thisAHdata.Accept === '') {
839
+ delete thisAHdata.Accept;
840
+ }
841
+ if (thisAHdata['Content-Type'] === '') {
842
+ delete thisAHdata['Content-Type'];
843
+ }
844
+
845
+ return thisAHdata;
846
+ }
847
+
848
+ /**
849
+ * @summary Build the payload for the request
850
+ *
851
+ * @function buildPayload
852
+ * @param {String} entity - the name of the entity action is on. (required)
853
+ * @param {String} action - the name of the action being executed. (required)
854
+ * @param {Object} entitySchema - the entity schema for the entity and action. (required)
855
+ * @param {Object} payload - an object that contains the payload prior to translation
856
+ * (optional). Can be a stringified Object.
857
+ */
858
+ function buildPayload(entity, action, entitySchema, payload) {
859
+ const origin = `${id}-restHandler-buildPayload`;
860
+ log.trace(origin);
861
+
862
+ try {
863
+ // prepare the body parameters we received
864
+ let thisBdata = transUtilInst.formatInputData(payload);
865
+
866
+ // return the payload if just sending plain text and got plain text
867
+ if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'PLAIN') {
868
+ if (!thisBdata) {
869
+ thisBdata = '';
870
+ }
871
+ if (typeof thisBdata !== 'object') {
872
+ return thisBdata;
873
+ }
874
+ }
875
+ // return the payload if just sending xml and got xml (as string)
876
+ if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'XML') {
877
+ if (!thisBdata) {
878
+ thisBdata = '';
879
+ }
880
+ if (typeof thisBdata !== 'object') {
881
+ return thisBdata;
882
+ }
883
+ }
884
+
885
+ // only add body if there is payload to add and it is not a GET or if it is a GET and we need to send a body
886
+ if ((entitySchema.method.toUpperCase() !== 'GET' || entitySchema.sendGetBody) && globalRequestGl && globalRequestGl.payload) {
887
+ // if both are objects, merge the objects
888
+ if (!Array.isArray(thisBdata) && typeof thisBdata === 'object' && !Array.isArray(globalRequestGl.payload)
889
+ && typeof globalRequestGl.payload === 'object' && Object.keys(globalRequestGl.payload).length > 0) {
890
+ thisBdata = transUtilInst.mergeObjects(thisBdata, globalRequestGl.payload);
891
+ } else if (Array.isArray(thisBdata) && !Array.isArray(globalRequestGl.payload) && typeof globalRequestGl.payload === 'object'
892
+ && Object.keys(globalRequestGl.payload).length > 0) {
893
+ // if payload is an array of objects, add the global payload to each object - only one level deep
894
+ for (let a = 0; a < thisBdata.length; a += 1) {
895
+ if (!Array.isArray(thisBdata[a]) && typeof thisBdata[a] === 'object') {
896
+ thisBdata[a] = transUtilInst.mergeObjects(thisBdata[a], globalRequestGl.payload);
897
+ }
898
+ }
899
+ } else {
900
+ log.warn(`${origin}: Payload and Gloabl Payload can not be merged!`);
901
+ }
902
+ }
903
+
904
+ // handle input as JSON
905
+ if (!thisBdata) {
906
+ thisBdata = {};
907
+ }
908
+
909
+ // request type set for determining required fields
910
+ thisBdata.ph_request_type = action;
911
+
912
+ // map the data we received to a [System] Entity
913
+ const systemEntity = transUtilInst.mapToOutboundEntity(thisBdata, entitySchema.requestSchema);
914
+
915
+ if (!systemEntity) {
916
+ // create the error object
917
+ const errorObj = {
918
+ origin,
919
+ type: 'Payload Not Translated',
920
+ vars: []
921
+ };
922
+
923
+ // log and throw the error
924
+ log.error(`${origin}: Payload not translated`);
925
+ throw new Error(JSON.stringify(errorObj));
926
+ }
927
+
928
+ if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'URLENCODE') {
929
+ return querystring.stringify(systemEntity);
930
+ }
931
+
932
+ if (entitySchema && entitySchema.requestDatatype && entitySchema.requestDatatype.toUpperCase() === 'JSON2XML') {
933
+ try {
934
+ return jsonxml(systemEntity);
935
+ } catch (ex) {
936
+ log.warn(`${origin}: Unable to get xml from json ${ex}`);
937
+ return '';
938
+ }
939
+ }
940
+
941
+ // return the payload
942
+ return JSON.stringify(systemEntity);
943
+ } catch (e) {
944
+ return transUtilInst.checkAndThrow(e, origin, 'Issue building payload');
945
+ }
946
+ }
947
+
948
+ class RestHandler {
949
+ /**
950
+ * Rest Entity
951
+ * @constructor
952
+ */
953
+ constructor(prongId, properties, connectorCl, transUtilCl) {
954
+ id = prongId;
955
+ this.myid = prongId;
956
+
957
+ // reference to the needed classes for class methods
958
+ this.connector = connectorCl;
959
+ connectorInst = this.connector;
960
+ this.transUtil = transUtilCl;
961
+ transUtilInst = this.transUtil;
962
+
963
+ // set up the properties I care about
964
+ this.refreshProperties(properties);
965
+ }
966
+
967
+ /**
968
+ * refreshProperties is used to set up all of the properties for the rest handler.
969
+ * It allows properties to be changed later by simply calling refreshProperties rather
970
+ * than having to restart the rest handler.
971
+ *
972
+ * @function refreshProperties
973
+ * @param {Object} properties - an object containing all of the properties
974
+ */
975
+ refreshProperties(properties) {
976
+ const origin = `${this.myid}-restHandler-refreshProperties`;
977
+ log.trace(origin);
978
+
979
+ if (!properties) {
980
+ log.error(`${origin}: Rest Handler received no properties!`);
981
+ return;
982
+ }
983
+
984
+ this.version = properties.version;
985
+ versionGl = this.version;
986
+ this.basepath = properties.base_path;
987
+ basepathGl = this.basepath;
988
+ this.globalRequest = null;
989
+ this.encode = properties.encode_pathvars;
990
+ encodePath = this.encode;
991
+
992
+ // only need to set returnRaw if the property is true - defaults to false
993
+ if (properties.request && properties.request.return_raw) {
994
+ returnRawGl = properties.request.return_raw;
995
+ }
996
+
997
+ // set the request archiving flag (optional - default is false)
998
+ if (properties.request.global_request && typeof properties.request.global_request === 'object') {
999
+ this.globalRequest = properties.request.global_request;
1000
+ globalRequestGl = this.globalRequest;
1001
+ }
1002
+ }
1003
+
1004
+ /**
1005
+ * @summary Formats and makes the REST call
1006
+ *
1007
+ * @function genericRestRequest
1008
+ * @param {String} entity - the name of the entity for this request.
1009
+ * (required)
1010
+ * @param {String} action - the name of the action being executed. (required)
1011
+ * @param {Object} entitySchema - the schema for the entity the request is
1012
+ * for. (required)
1013
+ * @param {Object} requestObj - an object that contains all of the possible
1014
+ * parts of the request (payload, uriPathVars,
1015
+ * uriQuery, uriOptions and addlHeaders
1016
+ * (optional). Can be a stringified Object.
1017
+ * @param {Boolean} translate - whether to translate the response. Defaults
1018
+ * to true. If no translation will just return
1019
+ * "success" or an error message
1020
+ * @param {Function} callback - a callback function to return the result of the request
1021
+ */
1022
+ genericRestRequest(entity, action, entitySchema, requestObj, translate, callback) {
1023
+ const origin = `${this.myid}-restHandler-genericRestRequest`;
1024
+ log.trace(`${origin}: ${entity}-${action}`);
1025
+
1026
+ try {
1027
+ // verify parameters passed are valid
1028
+ if (!entity) {
1029
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Missing Data', ['Entity'], null, null, null);
1030
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1031
+ return callback(null, errorObj);
1032
+ }
1033
+ if (!action) {
1034
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Missing Data', ['Action'], null, null, null);
1035
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1036
+ return callback(null, errorObj);
1037
+ }
1038
+ if (!entitySchema) {
1039
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Missing Data', ['Entity Schema'], null, null, null);
1040
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1041
+ return callback(null, errorObj);
1042
+ }
1043
+
1044
+ // verify path for call
1045
+ if (!entitySchema.entitypath) {
1046
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing entity path', `${entity}/${action}`], null, null, null);
1047
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1048
+ return callback(null, errorObj);
1049
+ }
1050
+
1051
+ // verify method for call
1052
+ if (!entitySchema.method) {
1053
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing method', `${entity}/${action}`], null, null, null);
1054
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1055
+ return callback(null, errorObj);
1056
+ }
1057
+
1058
+ // set the translate flag - defaults to true
1059
+ let translateFlag = true;
1060
+ if (typeof translate === 'boolean') {
1061
+ translateFlag = translate;
1062
+ }
1063
+
1064
+ // get the path from the entity schema
1065
+ let uriPath = entitySchema.entitypath;
1066
+ const callMeth = entitySchema.method;
1067
+
1068
+ // break out the variables in the requestObj
1069
+ let payload = null;
1070
+ let uriPathVars = null;
1071
+ let uriQuery = null;
1072
+ let uriOptions = null;
1073
+ let addlHeaders = null;
1074
+ let authData = null;
1075
+ let callProperties = null;
1076
+ let filter = null;
1077
+ let priority = -1;
1078
+ let event = null;
1079
+ let retReqHdr = false;
1080
+
1081
+ if (requestObj !== null) {
1082
+ if (requestObj.payload) {
1083
+ ({ payload } = requestObj);
1084
+ }
1085
+ if (requestObj.uriPathVars) {
1086
+ ({ uriPathVars } = requestObj);
1087
+ }
1088
+ if (requestObj.uriQuery) {
1089
+ ({ uriQuery } = requestObj);
1090
+ }
1091
+ if (requestObj.uriOptions) {
1092
+ ({ uriOptions } = requestObj);
1093
+ }
1094
+ if (requestObj.addlHeaders) {
1095
+ ({ addlHeaders } = requestObj);
1096
+ }
1097
+ if (requestObj.authData) {
1098
+ ({ authData } = requestObj);
1099
+ }
1100
+ if (requestObj.callProperties) {
1101
+ ({ callProperties } = requestObj);
1102
+ }
1103
+ if (requestObj.filter) {
1104
+ ({ filter } = requestObj);
1105
+ }
1106
+ if (requestObj.priority) {
1107
+ ({ priority } = requestObj);
1108
+ }
1109
+ if (requestObj.event) {
1110
+ ({ event } = requestObj);
1111
+ }
1112
+ if (requestObj.retReqHdr) {
1113
+ ({ retReqHdr } = requestObj);
1114
+ }
1115
+ }
1116
+
1117
+ // build the request path from the information provided
1118
+ const result = buildRequestPath(entity, action, entitySchema, uriPath, uriPathVars, uriQuery, uriOptions, callProperties);
1119
+
1120
+ // reset the local variables
1121
+ uriPath = result.path;
1122
+
1123
+ // merge the additional headers
1124
+ const thisAHdata = mergeHeaders(addlHeaders, entitySchema);
1125
+
1126
+ // build the request path from the information provided
1127
+ const bodyString = buildPayload(entity, action, entitySchema, payload);
1128
+
1129
+ if ((callMeth !== 'GET' || entitySchema.sendGetBody) && bodyString !== '{}') {
1130
+ thisAHdata['Content-length'] = Buffer.byteLength(bodyString);
1131
+ }
1132
+
1133
+ // set up the request to be sent
1134
+ const request = {
1135
+ method: callMeth,
1136
+ path: uriPath,
1137
+ addlHeaders: thisAHdata,
1138
+ body: bodyString,
1139
+ origPath: entitySchema.entitypath,
1140
+ priority,
1141
+ event
1142
+ };
1143
+
1144
+ if (authData) {
1145
+ request.authData = authData;
1146
+ }
1147
+
1148
+ // actual call for the request
1149
+ if (translateFlag) {
1150
+ return handleRestRequest(request, 'map', entitySchema, callProperties, filter, retReqHdr, callback);
1151
+ }
1152
+
1153
+ return handleRestRequest(request, 'nomap', entitySchema, callProperties, filter, retReqHdr, callback);
1154
+ } catch (e) {
1155
+ // handle any exception
1156
+ const errorObj = this.transUtil.checkAndReturn(e, origin, 'Issue during generic request');
1157
+ return callback(null, errorObj);
1158
+ }
1159
+ }
1160
+
1161
+ /**
1162
+ * @summary Formats and makes the healthcheck call
1163
+ *
1164
+ * @function healthcheckRest
1165
+ * @param {Object} healthSchema - the schema for the healthcheck (optional)
1166
+ * @param {Object} requestObj - an object that contains all of the possible
1167
+ * parts of the request (payload, uriPathVars,
1168
+ * uriQuery, uriOptions and addlHeaders
1169
+ * (optional). Can be a stringified Object.
1170
+ * @param {Function} callback - a callback function to return the result of the healthcheck
1171
+ */
1172
+ healthcheckRest(healthSchema, requestObj, callback) {
1173
+ const origin = `${this.myid}-restHandler-healthcheckRest`;
1174
+ log.trace(origin);
1175
+
1176
+ try {
1177
+ // break out the variables in the requestObj
1178
+ let payload = null;
1179
+ let uriPathVars = null;
1180
+ let uriQuery = null;
1181
+ let uriOptions = null;
1182
+ let addlHeaders = {};
1183
+ let authData = null;
1184
+ let callProperties = null;
1185
+ let filter = null;
1186
+ let priority = -1;
1187
+ let event = null;
1188
+ let retReqHdr = false;
1189
+
1190
+ if (requestObj !== null) {
1191
+ if (requestObj.payload) {
1192
+ ({ payload } = requestObj);
1193
+ }
1194
+ if (requestObj.uriPathVars) {
1195
+ ({ uriPathVars } = requestObj);
1196
+ }
1197
+ if (requestObj.uriQuery) {
1198
+ ({ uriQuery } = requestObj);
1199
+ }
1200
+ if (requestObj.uriOptions) {
1201
+ ({ uriOptions } = requestObj);
1202
+ }
1203
+ if (requestObj.addlHeaders) {
1204
+ ({ addlHeaders } = requestObj);
1205
+ }
1206
+ if (requestObj.authData) {
1207
+ ({ authData } = requestObj);
1208
+ }
1209
+ if (requestObj.callProperties) {
1210
+ ({ callProperties } = requestObj);
1211
+ }
1212
+ if (requestObj.filter) {
1213
+ ({ filter } = requestObj);
1214
+ }
1215
+ if (requestObj.priority) {
1216
+ ({ priority } = requestObj);
1217
+ }
1218
+ if (requestObj.event) {
1219
+ ({ event } = requestObj);
1220
+ }
1221
+ if (requestObj.retReqHdr) {
1222
+ ({ retReqHdr } = requestObj);
1223
+ }
1224
+ }
1225
+
1226
+ if (healthSchema) {
1227
+ // verify path for call
1228
+ if (!healthSchema.entitypath) {
1229
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing entity path', '.system/healthcheck'], null, null, null);
1230
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1231
+ return callback(null, errorObj);
1232
+ }
1233
+
1234
+ // verify method for call
1235
+ if (!healthSchema.method) {
1236
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing method', '.system/healthcheck'], null, null, null);
1237
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1238
+ return callback(null, errorObj);
1239
+ }
1240
+
1241
+ // get the path from the entity schema
1242
+ let uriPath = healthSchema.entitypath;
1243
+ const callMeth = healthSchema.method;
1244
+
1245
+ // build the request path from the information provided
1246
+ const result = buildRequestPath('.system', 'healthcheck', healthSchema, uriPath, uriPathVars, uriQuery, uriOptions, callProperties);
1247
+
1248
+ // reset the local variables
1249
+ uriPath = result.path;
1250
+
1251
+ // merge the additional headers
1252
+ const thisAHdata = mergeHeaders(addlHeaders, healthSchema);
1253
+
1254
+ // build the request path from the information provided
1255
+ const bodyString = buildPayload('.system', 'healthcheck', healthSchema, payload);
1256
+
1257
+ if ((callMeth !== 'GET' || healthSchema.sendGetBody) && bodyString !== '{}') {
1258
+ thisAHdata['Content-length'] = Buffer.byteLength(bodyString);
1259
+ }
1260
+
1261
+ // set up the request to be sent
1262
+ const request = {
1263
+ method: callMeth,
1264
+ path: uriPath,
1265
+ addlHeaders: thisAHdata,
1266
+ body: bodyString,
1267
+ origPath: healthSchema.entitypath,
1268
+ priority,
1269
+ event
1270
+ };
1271
+
1272
+ if (authData) {
1273
+ request.authData = authData;
1274
+ }
1275
+
1276
+ // actual call for the request
1277
+ return handleRestRequest(request, 'nomap', healthSchema, callProperties, filter, retReqHdr, callback);
1278
+ }
1279
+
1280
+ // call to run healthcheck - if using properties
1281
+ return this.connector.healthCheck(healthSchema, null, addlHeaders, callProperties, callback);
1282
+ } catch (e) {
1283
+ // handle any exception
1284
+ const errorObj = this.transUtil.checkAndReturn(e, origin, 'Issue during healthcheck request');
1285
+ return callback(null, errorObj);
1286
+ }
1287
+ }
1288
+
1289
+ /**
1290
+ * getQueue is used to get information for all of the requests currently in the queue.
1291
+ *
1292
+ * @function getQueue
1293
+ * @param {Function} callback - a callback function to return the queue
1294
+ */
1295
+ getQueue(callback) {
1296
+ const origin = `${this.myid}-restHandler-getQueue`;
1297
+ log.trace(origin);
1298
+
1299
+ try {
1300
+ return this.connector.getQueue(callback);
1301
+ } catch (e) {
1302
+ // handle any exception
1303
+ const errorObj = this.transUtil.checkAndReturn(e, origin, 'Issue getting queue');
1304
+ return callback(null, errorObj);
1305
+ }
1306
+ }
1307
+ }
1308
+
1309
+ module.exports = RestHandler;