account-lookup-service 15.6.0-iso.2 → 15.6.0-iso.21

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.
Files changed (53) hide show
  1. package/.circleci/config.yml +1 -1
  2. package/.ncurc.yaml +1 -2
  3. package/audit-ci.jsonc +3 -1
  4. package/jest.config.js +2 -0
  5. package/package.json +15 -17
  6. package/src/constants.js +2 -1
  7. package/src/domain/oracle/oracle.js +63 -4
  8. package/src/domain/participants/participants.js +259 -133
  9. package/src/domain/parties/getPartiesByTypeAndID.js +36 -15
  10. package/src/domain/parties/parties.js +44 -14
  11. package/src/domain/parties/utils.js +13 -6
  12. package/src/domain/timeout/dto.js +4 -10
  13. package/src/domain/timeout/index.js +12 -1
  14. package/src/handlers/index.js +4 -4
  15. package/src/handlers/monitoring/index.js +1 -1
  16. package/src/interface/api-swagger-iso20022-parties.yaml +7 -6
  17. package/src/interface/api-swagger.yaml +7 -6
  18. package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2043 -1583
  19. package/src/lib/config.js +1 -1
  20. package/src/lib/index.js +1 -2
  21. package/src/models/currency/currency.js +10 -1
  22. package/src/models/endpointType/endpointType.js +10 -1
  23. package/src/models/oracle/facade.js +24 -3
  24. package/src/models/oracle/oracleEndpoint.js +64 -10
  25. package/src/models/oracle/oracleEndpointCached.js +22 -3
  26. package/src/models/participantEndpoint/facade.js +61 -23
  27. package/src/models/partyIdType/partyIdType.js +10 -1
  28. package/src/plugins.js +20 -9
  29. package/src/server.js +11 -19
  30. package/test/fixtures/index.js +30 -6
  31. package/test/fixtures/iso.js +1 -1
  32. package/test/unit/api/health.test.js +3 -0
  33. package/test/unit/api/participants/participants.test.js +5 -7
  34. package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +0 -3
  35. package/test/unit/api/participants/{Type}/{ID}.test.js +0 -3
  36. package/test/unit/api/participants.test.js +36 -3
  37. package/test/unit/domain/oracle/oracle.test.js +8 -0
  38. package/test/unit/domain/participants/participants.test.js +83 -48
  39. package/test/unit/domain/parties/parties.test.js +11 -3
  40. package/test/unit/domain/parties/utils.test.js +60 -0
  41. package/test/unit/domain/timeout/dto.test.js +1 -2
  42. package/test/unit/domain/timeout/index.test.js +8 -0
  43. package/test/unit/lib/TransformFacades.test.js +2 -1
  44. package/test/unit/lib/config.test.js +7 -0
  45. package/test/unit/models/participantEndpoint/facade.test.js +25 -8
  46. package/test/unit/plugins.test.js +4 -2
  47. package/test/util/apiClients/BasicApiClient.js +2 -2
  48. package/src/handlers/monitoring/plugins/metrics.js +0 -48
  49. package/src/lib/requestLogger.js +0 -54
  50. package/src/metrics/handler.js +0 -33
  51. package/src/metrics/plugin.js +0 -52
  52. package/src/metrics/routes.js +0 -43
  53. package/test/unit/lib/requestLogger.test.js +0 -115
@@ -28,7 +28,6 @@
28
28
 
29
29
  const Enums = require('@mojaloop/central-services-shared').Enum
30
30
  const { decodePayload } = require('@mojaloop/central-services-shared').Util.StreamingProtocol
31
- const Logger = require('@mojaloop/central-services-logger')
32
31
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
33
32
  const EventSdk = require('@mojaloop/event-sdk')
34
33
  const Metrics = require('@mojaloop/central-services-metrics')
@@ -36,6 +35,10 @@ const Metrics = require('@mojaloop/central-services-metrics')
36
35
  const oracle = require('../../models/oracle/facade')
37
36
  const participant = require('../../models/participantEndpoint/facade')
38
37
  const Config = require('../../lib/config')
38
+ const { logger } = require('../../lib')
39
+ const { ERROR_MESSAGES } = require('../../constants')
40
+
41
+ const { FSPIOPErrorCodes } = ErrorHandler.Enums
39
42
 
40
43
  /**
41
44
  * @function getParticipantsByTypeAndID
@@ -55,57 +58,97 @@ const getParticipantsByTypeAndID = async (headers, params, method, query, span,
55
58
  'Get participants by ID',
56
59
  ['success']
57
60
  ).startTimer()
61
+ const errorCounter = Metrics.getCounter('errorCount')
62
+ const log = logger.child('getParticipantsByTypeAndID')
58
63
  const type = params.Type
59
- const partySubIdOrType = params.SubId || undefined
60
- const requesterName = headers[Enums.Http.Headers.FSPIOP.SOURCE]
61
- const callbackEndpointType = partySubIdOrType ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT
62
- const errorCallbackEndpointType = params.SubId ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
64
+ const partySubIdOrType = params.SubId
65
+ const source = headers[Enums.Http.Headers.FSPIOP.SOURCE]
66
+ const callbackEndpointType = partySubIdOrType
67
+ ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT
68
+ : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT
69
+ const errorCallbackEndpointType = params.SubId
70
+ ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR
71
+ : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
72
+
63
73
  let fspiopError
74
+ let step
75
+
64
76
  try {
65
- Logger.isInfoEnabled && Logger.info('getParticipantsByTypeAndID::begin')
66
- const requesterParticipantModel = await participant.validateParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], childSpan)
67
- if (requesterParticipantModel) {
68
- const response = await oracle.oracleRequest(headers, method, params, query, undefined, cache)
69
- if (response && response.data && Array.isArray(response.data.partyList) && response.data.partyList.length > 0) {
70
- let options = {
71
- partyIdType: type,
72
- partyIdentifier: params.ID
73
- }
74
- options = partySubIdOrType ? { ...options, partySubIdOrType } : options
75
- const payload = {
76
- fspId: response.data.partyList[0].fspId
77
- }
78
- const clonedHeaders = { ...headers }
79
- if (!clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] || clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] === '') {
80
- clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE]
81
- }
82
- clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
83
- await participant.sendRequest(clonedHeaders, requesterName, callbackEndpointType, Enums.Http.RestMethods.PUT, payload, options, childSpan)
84
- } else {
85
- await participant.sendErrorToParticipant(requesterName, errorCallbackEndpointType,
86
- ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND).toApiErrorObject(Config.ERROR_HANDLING), headers, params, childSpan)
77
+ log.info('processing started...', { source, params })
78
+ step = 'validateParticipant-1'
79
+ const requesterParticipantModel = await participant.validateParticipant(source)
80
+
81
+ if (!requesterParticipantModel) {
82
+ const errMessage = ERROR_MESSAGES.sourceFspNotFound
83
+ logger.warn(errMessage, { requesterName: source })
84
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
85
+ }
86
+ step = 'oracleRequest-2'
87
+ const response = await oracle.oracleRequest(headers, method, params, query, undefined, cache)
88
+ if (response?.data && Array.isArray(response.data.partyList) && response.data.partyList.length > 0) {
89
+ const options = {
90
+ partyIdType: type,
91
+ partyIdentifier: params.ID,
92
+ ...(partySubIdOrType && { partySubIdOrType })
93
+ }
94
+ const payload = {
95
+ fspId: response.data.partyList[0].fspId
87
96
  }
88
- Logger.isInfoEnabled && Logger.info('getParticipantsByTypeAndID::end')
97
+ const clonedHeaders = { ...headers }
98
+ if (!clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] || clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] === '') {
99
+ clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE]
100
+ }
101
+ clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
102
+ step = 'sendRequest-3'
103
+ await participant.sendRequest(
104
+ clonedHeaders,
105
+ source,
106
+ callbackEndpointType,
107
+ Enums.Http.RestMethods.PUT,
108
+ payload,
109
+ options,
110
+ childSpan
111
+ )
89
112
  } else {
90
- Logger.isErrorEnabled && Logger.error('Requester FSP not found')
91
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, 'Requester FSP not found')
113
+ step = 'sendErrorToParticipant-4'
114
+ await participant.sendErrorToParticipant(
115
+ source,
116
+ errorCallbackEndpointType,
117
+ ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND).toApiErrorObject(Config.ERROR_HANDLING),
118
+ headers,
119
+ params,
120
+ childSpan
121
+ )
92
122
  }
123
+ log.info('processing finished', { source, params })
124
+
93
125
  if (childSpan && !childSpan.isFinished) {
94
126
  await childSpan.finish()
95
127
  }
96
128
  } catch (err) {
97
- Logger.isErrorEnabled && Logger.error(err)
129
+ log.warn('error in getParticipantsByTypeAndID', err)
98
130
  fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err, ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR)
131
+ const extensions = err.extensions || []
132
+ const system = extensions.find((element) => element.key === 'system')?.value || ''
133
+ errorCounter.inc({
134
+ code: fspiopError?.apiErrorCode,
135
+ system,
136
+ operation: 'getParticipantsByTypeAndID',
137
+ step
138
+ })
99
139
  try {
100
- const errorCallbackEndpointType = params.SubId ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
101
140
  await participant.sendErrorToParticipant(
102
- headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
103
- fspiopError.toApiErrorObject(Config.ERROR_HANDLING), headers, params, childSpan)
141
+ headers[Enums.Http.Headers.FSPIOP.SOURCE],
142
+ errorCallbackEndpointType,
143
+ fspiopError.toApiErrorObject(Config.ERROR_HANDLING),
144
+ headers,
145
+ params,
146
+ childSpan
147
+ )
104
148
  } catch (exc) {
105
- fspiopError = ErrorHandler.Factory.reformatFSPIOPError(exc)
106
149
  // We can't do anything else here- we _must_ handle all errors _within_ this function because
107
150
  // we've already sent a sync response- we cannot throw.
108
- Logger.isErrorEnabled && Logger.error(exc)
151
+ log.error('error in final participant.sendErrorToParticipant', exc)
109
152
  }
110
153
  } finally {
111
154
  if (childSpan && !childSpan.isFinished && fspiopError) {
@@ -137,15 +180,19 @@ const putParticipantsByTypeAndID = async (headers, params, method, payload, cach
137
180
  'Put participants by type and ID',
138
181
  ['success']
139
182
  ).startTimer()
183
+ const errorCounter = Metrics.getCounter('errorCount')
184
+ let step
140
185
  try {
141
- Logger.isInfoEnabled && Logger.info('putParticipantsByTypeAndID::begin')
186
+ logger.info('putParticipantsByTypeAndID::begin')
142
187
  const type = params.Type
143
188
  const partySubIdOrType = params.SubId || undefined
144
189
  const callbackEndpointType = partySubIdOrType ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT
145
190
  const errorCallbackEndpointType = partySubIdOrType ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
146
191
  if (Object.values(Enums.Accounts.PartyAccountTypes).includes(type)) {
192
+ step = 'validateParticipant-1'
147
193
  const requesterParticipantModel = await participant.validateParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE])
148
194
  if (requesterParticipantModel) {
195
+ step = 'oracleRequest-2'
149
196
  const response = await oracle.oracleRequest(headers, method, params, undefined, payload, cache)
150
197
  if (response && response.data) {
151
198
  const responsePayload = {
@@ -171,32 +218,45 @@ const putParticipantsByTypeAndID = async (headers, params, method, payload, cach
171
218
  clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = payload.fspId
172
219
  clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
173
220
  }
221
+ step = 'sendRequest-3'
174
222
  await participant.sendRequest(clonedHeaders, clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION], callbackEndpointType, Enums.Http.RestMethods.PUT, responsePayload, options)
175
223
  } else {
224
+ step = 'sendErrorToParticipant-4'
176
225
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
177
226
  ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR).toApiErrorObject(Config.ERROR_HANDLING), headers, params)
178
227
  }
179
228
  } else {
180
- Logger.isErrorEnabled && Logger.error('Requester FSP not found')
181
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, 'Requester FSP not found')
229
+ logger.warn(ERROR_MESSAGES.sourceFspNotFound)
230
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.sourceFspNotFound)
182
231
  }
183
232
  } else {
233
+ step = 'sendErrorToParticipant-5'
184
234
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
185
235
  ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR).toApiErrorObject(Config.ERROR_HANDLING), headers, params)
186
236
  }
187
- Logger.isInfoEnabled && Logger.info('putParticipantsByTypeAndID::end')
237
+ logger.info('putParticipantsByTypeAndID::end')
188
238
  histTimerEnd({ success: true })
189
239
  } catch (err) {
190
- Logger.isErrorEnabled && Logger.error(err)
240
+ logger.error('error in putParticipantsByTypeAndID:', err)
241
+ let fspiopError
191
242
  try {
192
243
  const errorCallbackEndpointType = params.SubId ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
244
+ fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err, ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR)
193
245
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
194
- ErrorHandler.Factory.reformatFSPIOPError(err, ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR).toApiErrorObject(Config.ERROR_HANDLING), headers, params)
246
+ fspiopError.toApiErrorObject(Config.ERROR_HANDLING), headers, params)
195
247
  } catch (exc) {
196
248
  // We can't do anything else here- we _must_ handle all errors _within_ this function because
197
249
  // we've already sent a sync response- we cannot throw.
198
- Logger.isErrorEnabled && Logger.error(exc)
250
+ logger.error('error in participant.sendErrorToParticipant:', exc)
199
251
  }
252
+ const extensions = err.extensions || []
253
+ const system = extensions.find((element) => element.key === 'system')?.value || ''
254
+ errorCounter.inc({
255
+ code: fspiopError?.apiErrorCode,
256
+ system,
257
+ operation: 'putParticipantsByTypeAndID',
258
+ step
259
+ })
200
260
  histTimerEnd({ success: false })
201
261
  }
202
262
  }
@@ -220,38 +280,63 @@ const putParticipantsErrorByTypeAndID = async (headers, params, payload, dataUri
220
280
  'Put participants error by type and ID',
221
281
  ['success']
222
282
  ).startTimer()
283
+ const errorCounter = Metrics.getCounter('errorCount')
284
+ let step
223
285
  try {
224
286
  const partySubIdOrType = params.SubId || undefined
225
- const callbackEndpointType = partySubIdOrType ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
287
+ const callbackEndpointType = partySubIdOrType
288
+ ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR
289
+ : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
290
+ step = 'validateParticipant-1'
226
291
  const destinationParticipant = await participant.validateParticipant(headers[Enums.Http.Headers.FSPIOP.DESTINATION])
227
292
  if (destinationParticipant) {
228
293
  const decodedPayload = decodePayload(dataUri, { asParsed: false })
294
+ step = 'sendErrorToParticipant-2'
229
295
  await participant.sendErrorToParticipant(
230
296
  headers[Enums.Http.Headers.FSPIOP.DESTINATION],
231
297
  callbackEndpointType,
232
298
  decodedPayload.body.toString(),
233
299
  headers,
234
- params)
300
+ params
301
+ )
235
302
  } else {
303
+ step = 'sendErrorToParticipant-3'
236
304
  await participant.sendErrorToParticipant(
237
305
  headers[Enums.Http.Headers.FSPIOP.SOURCE],
238
306
  callbackEndpointType,
239
307
  ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR).toApiErrorObject(),
240
308
  headers,
241
309
  params,
242
- payload)
310
+ payload
311
+ )
243
312
  }
244
313
  histTimerEnd({ success: true })
245
314
  } catch (err) {
246
- Logger.isErrorEnabled && Logger.error(err)
315
+ logger.error('error in putParticipantsErrorByTypeAndID:', err)
247
316
  try {
248
- const callbackEndpointType = params.SubId ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
249
- await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], callbackEndpointType,
250
- ErrorHandler.Factory.reformatFSPIOPError(err).toApiErrorObject(), headers, params)
317
+ const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err)
318
+ const callbackEndpointType = params.SubId
319
+ ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR
320
+ : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
321
+ await participant.sendErrorToParticipant(
322
+ headers[Enums.Http.Headers.FSPIOP.SOURCE],
323
+ callbackEndpointType,
324
+ fspiopError.toApiErrorObject(),
325
+ headers,
326
+ params
327
+ )
328
+ const extensions = err.extensions || []
329
+ const system = extensions.find((element) => element.key === 'system')?.value || ''
330
+ errorCounter.inc({
331
+ code: fspiopError?.apiErrorCode,
332
+ system,
333
+ operation: 'putParticipantsErrorByTypeAndID',
334
+ step
335
+ })
251
336
  } catch (exc) {
252
337
  // We can't do anything else here- we _must_ handle all errors _within_ this function because
253
338
  // we've already sent a sync response- we cannot throw.
254
- Logger.isErrorEnabled && Logger.error(exc)
339
+ logger.error('error in participant.sendErrorToParticipant:', exc)
255
340
  }
256
341
  histTimerEnd({ success: false })
257
342
  }
@@ -274,10 +359,12 @@ const postParticipants = async (headers, method, params, payload, span, cache) =
274
359
  'Post participants',
275
360
  ['success']
276
361
  ).startTimer()
362
+ const errorCounter = Metrics.getCounter('errorCount')
277
363
  const childSpan = span ? span.getChild('postParticipants') : undefined
278
364
  let fspiopError
365
+ let step
279
366
  try {
280
- Logger.isInfoEnabled && Logger.info('postParticipants::begin')
367
+ logger.info('postParticipants::begin')
281
368
  const type = params.Type
282
369
  const partySubIdOrType = params.SubId
283
370
  const callbackEndpointType = partySubIdOrType
@@ -288,8 +375,10 @@ const postParticipants = async (headers, method, params, payload, span, cache) =
288
375
  : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
289
376
 
290
377
  if (Object.values(Enums.Accounts.PartyAccountTypes).includes(type)) {
378
+ step = 'validateParticipant-1'
291
379
  const requesterParticipantModel = await participant.validateParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], childSpan)
292
380
  if (requesterParticipantModel) {
381
+ step = 'oracleRequest-2'
293
382
  const response = await oracle.oracleRequest(headers, method, params, undefined, payload, cache)
294
383
  if (response && response.status === Enums.Http.ReturnCodes.CREATED.CODE) {
295
384
  const responsePayload = {
@@ -315,18 +404,21 @@ const postParticipants = async (headers, method, params, payload, span, cache) =
315
404
  clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = payload.fspId
316
405
  clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
317
406
  }
407
+ step = 'sendRequest-3'
318
408
  await participant.sendRequest(clonedHeaders, clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION], callbackEndpointType, Enums.Http.RestMethods.PUT, responsePayload, options, childSpan)
319
409
  if (childSpan && !childSpan.isFinished) {
320
410
  await childSpan.finish()
321
411
  }
322
412
  } else {
323
413
  fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR)
414
+ step = 'sendErrorToParticipant-4'
324
415
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
325
416
  fspiopError.toApiErrorObject(Config.ERROR_HANDLING), headers, params, childSpan)
326
417
  }
327
418
  } else {
328
- fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, 'Requester FSP not found')
329
- Logger.isErrorEnabled && Logger.error('Requester FSP not found')
419
+ const errMessage = ERROR_MESSAGES.sourceFspNotFound
420
+ logger.error(errMessage)
421
+ fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
330
422
  throw fspiopError
331
423
  }
332
424
  } else {
@@ -334,11 +426,19 @@ const postParticipants = async (headers, method, params, payload, span, cache) =
334
426
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
335
427
  fspiopError.toApiErrorObject(Config.ERROR_HANDLING), headers, params, childSpan)
336
428
  }
337
- Logger.isInfoEnabled && Logger.info('postParticipants::end')
429
+ logger.info('postParticipants::end')
338
430
  histTimerEnd({ success: true })
339
431
  } catch (err) {
340
- Logger.isErrorEnabled && Logger.error(`error in postParticipants: ${err?.message}`)
432
+ logger.error('error in postParticipants:', err)
341
433
  fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err, ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR)
434
+ const extensions = err.extensions || []
435
+ const system = extensions.find((element) => element.key === 'system')?.value || ''
436
+ errorCounter.inc({
437
+ code: fspiopError?.apiErrorCode,
438
+ system,
439
+ operation: 'postParticipants',
440
+ step
441
+ })
342
442
  try {
343
443
  const errorCallbackEndpointType = params.SubId
344
444
  ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR
@@ -348,7 +448,7 @@ const postParticipants = async (headers, method, params, payload, span, cache) =
348
448
  } catch (exc) {
349
449
  // We can't do anything else here- we _must_ handle all errors _within_ this function because
350
450
  // we've already sent a sync response- we cannot throw.
351
- Logger.isErrorEnabled && Logger.error(`failed to handle exception in postParticipants due to error: ${exc?.stack}`)
451
+ logger.error('failed to handle exception in postParticipants:', exc)
352
452
  }
353
453
  histTimerEnd({ success: false })
354
454
  } finally {
@@ -376,100 +476,108 @@ const postParticipantsBatch = async (headers, method, requestPayload, span) => {
376
476
  'Post participants batch',
377
477
  ['success']
378
478
  ).startTimer()
479
+ const errorCounter = Metrics.getCounter('errorCount')
480
+ const requestId = requestPayload.requestId
481
+ const log = logger.child({ context: 'postParticipantsBatch', requestId })
379
482
  const childSpan = span ? span.getChild('postParticipantsBatch') : undefined
380
483
  let fspiopError
484
+ let step
381
485
  try {
382
- Logger.isInfoEnabled && Logger.info('postParticipantsBatch::begin')
486
+ log.info('postParticipantsBatch::begin', { headers, requestPayload })
383
487
  const typeMap = new Map()
384
488
  const overallReturnList = []
385
- const requestId = requestPayload.requestId
489
+ const pushPartyError = (party, errCode) => {
490
+ log.debug('party error details:', { party, errCode })
491
+ overallReturnList.push({
492
+ partyId: party,
493
+ ...ErrorHandler.Factory.createFSPIOPError(errCode, undefined, undefined, undefined, [{
494
+ key: party.partyIdType,
495
+ value: party.partyIdentifier
496
+ }]).toApiErrorObject(Config.ERROR_HANDLING)
497
+ })
498
+ }
499
+ step = 'validateParticipant-1'
386
500
  const requesterParticipantModel = await participant.validateParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], childSpan)
387
- if (requesterParticipantModel) {
388
- for (const party of requestPayload.partyList) {
389
- if (Object.values(Enums.Accounts.PartyAccountTypes).includes(party.partyIdType)) {
390
- party.currency = requestPayload.currency
391
- if (party.fspId === headers[Enums.Http.Headers.FSPIOP.SOURCE]) {
392
- if (typeMap.get(party.partyIdType)) {
393
- const partyList = typeMap.get(party.partyIdType)
394
- partyList.push(party)
395
- typeMap.set(party.partyIdType, partyList)
396
- } else {
397
- typeMap.set(party.partyIdType, [party])
398
- }
399
- } else {
400
- overallReturnList.push(ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND, undefined, undefined, undefined, [{
401
- key: party.partyIdType,
402
- value: party.partyIdentifier
403
- }]).toApiErrorObject(Config.ERROR_HANDLING))
404
- }
405
- } else {
406
- overallReturnList.push(ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, undefined, undefined, undefined, [{
407
- key: party.partyIdType,
408
- value: party.partyIdentifier
409
- }]).toApiErrorObject(Config.ERROR_HANDLING))
410
- }
411
- }
501
+ if (!requesterParticipantModel) {
502
+ const errMessage = ERROR_MESSAGES.sourceFspNotFound
503
+ log.error(errMessage)
504
+ fspiopError = ErrorHandler.Factory.createFSPIOPError(FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
505
+ throw fspiopError
506
+ }
412
507
 
413
- for (const [key, value] of typeMap) {
414
- const payload = {
415
- requestId,
416
- partyList: value
417
- }
418
- Logger.isInfoEnabled && Logger.info(`postParticipantsBatch::oracleBatchRequest::type=${key}`)
419
- const response = await oracle.oracleBatchRequest(headers, method, requestPayload, key, payload)
420
- if (response && (response.data !== null || response.data !== undefined)) {
421
- if (Array.isArray(response.data.partyList) && response.data.partyList.length > 0) {
422
- for (const party of response.data.partyList) {
423
- party.partyId.currency = undefined
424
- overallReturnList.push(party)
425
- }
508
+ for (const party of requestPayload.partyList) {
509
+ if (Object.values(Enums.Accounts.PartyAccountTypes).includes(party.partyIdType)) {
510
+ party.currency = requestPayload.currency
511
+ if (party.fspId === headers[Enums.Http.Headers.FSPIOP.SOURCE]) {
512
+ if (typeMap.get(party.partyIdType)) {
513
+ const partyList = typeMap.get(party.partyIdType)
514
+ partyList.push(party)
515
+ typeMap.set(party.partyIdType, partyList)
426
516
  } else {
427
- for (const party of value) {
428
- overallReturnList.push(ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, undefined, undefined, undefined, [{
429
- key: party.partyIdType,
430
- value: party.partyIdentifier
431
- }]).toApiErrorObject(Config.ERROR_HANDLING))
432
- }
517
+ typeMap.set(party.partyIdType, [party])
433
518
  }
434
519
  } else {
435
- for (const party of value) {
436
- overallReturnList.push(ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, undefined, undefined, undefined, [{
437
- key: party.partyIdType,
438
- value: party.partyIdentifier
439
- }]).toApiErrorObject(Config.ERROR_HANDLING))
440
- }
520
+ pushPartyError(party, FSPIOPErrorCodes.PARTY_NOT_FOUND)
441
521
  }
522
+ } else {
523
+ pushPartyError(party, FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR)
442
524
  }
525
+ }
526
+
527
+ for (const [key, value] of typeMap) {
443
528
  const payload = {
444
- partyList: overallReturnList,
445
- currency: requestPayload.currency
529
+ requestId,
530
+ partyList: value
446
531
  }
447
- const clonedHeaders = { ...headers }
448
- if (!clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] || clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] === '') {
449
- clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = payload.partyList[0].partyId.fspId
450
- clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
451
- }
452
- await participant.sendRequest(clonedHeaders, clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION], Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT, Enums.Http.RestMethods.PUT, payload, { requestId }, childSpan)
453
- if (childSpan && !childSpan.isFinished) {
454
- await childSpan.finish()
532
+ log.info(`postParticipantsBatch::oracleBatchRequest::type=${key}`, { payload })
533
+ step = 'oracleBatchRequest-2'
534
+ const response = await oracle.oracleBatchRequest(headers, method, requestPayload, key, payload)
535
+ if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
536
+ for (const party of response.data.partyList) {
537
+ party.partyId.currency = undefined
538
+ overallReturnList.push(party)
539
+ }
540
+ } else {
541
+ for (const party of value) {
542
+ pushPartyError(party, FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR)
543
+ }
455
544
  }
456
- Logger.isInfoEnabled && Logger.info('postParticipantsBatch::end')
457
- } else {
458
- Logger.isErrorEnabled && Logger.error('Requester FSP not found')
459
- fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, 'Requester FSP not found')
460
- throw fspiopError
461
545
  }
546
+
547
+ const payload = {
548
+ partyList: overallReturnList,
549
+ currency: requestPayload.currency
550
+ }
551
+ const clonedHeaders = { ...headers }
552
+ if (!clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] || clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] === '') {
553
+ clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = headers[Enums.Http.Headers.FSPIOP.SOURCE]
554
+ clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
555
+ }
556
+ await participant.sendRequest(clonedHeaders, clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION], Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT, Enums.Http.RestMethods.PUT, payload, { requestId }, childSpan)
557
+ if (childSpan && !childSpan.isFinished) {
558
+ await childSpan.finish()
559
+ }
560
+ log.info('postParticipantsBatch::end')
561
+
462
562
  histTimerEnd({ success: true })
463
563
  } catch (err) {
464
- Logger.isErrorEnabled && Logger.error(err)
564
+ log.error('error in postParticipantsBatch', err)
465
565
  fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err)
566
+ const extensions = err.extensions || []
567
+ const system = extensions.find((element) => element.key === 'system')?.value || ''
568
+ errorCounter.inc({
569
+ code: fspiopError?.apiErrorCode,
570
+ system,
571
+ operation: 'postParticipantsBatch',
572
+ step
573
+ })
466
574
  try {
467
575
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT_ERROR,
468
576
  fspiopError.toApiErrorObject(Config.ERROR_HANDLING), headers, undefined, requestPayload)
469
577
  } catch (exc) {
470
578
  // We can't do anything else here- we _must_ handle all errors _within_ this function because
471
579
  // we've already sent a sync response- we cannot throw.
472
- Logger.isErrorEnabled && Logger.error(exc)
580
+ log.error('error in participant.sendErrorToParticipant', exc)
473
581
  }
474
582
  histTimerEnd({ success: false })
475
583
  } finally {
@@ -498,15 +606,20 @@ const deleteParticipants = async (headers, params, method, query, cache) => {
498
606
  'Delete participants',
499
607
  ['success']
500
608
  ).startTimer()
609
+ const errorCounter = Metrics.getCounter('errorCount')
610
+ const log = logger.child('deleteParticipants')
611
+ let step
501
612
  try {
502
- Logger.isInfoEnabled && Logger.info('deleteParticipants::begin')
613
+ log.debug('deleteParticipants::begin', { headers, params })
503
614
  const type = params.Type
504
615
  const partySubIdOrType = params.SubId || undefined
505
616
  const callbackEndpointType = partySubIdOrType ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT
506
617
  const errorCallbackEndpointType = partySubIdOrType ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
507
618
  if (Object.values(Enums.Accounts.PartyAccountTypes).includes(type)) {
619
+ step = 'validateParticipant-1'
508
620
  const requesterParticipantModel = await participant.validateParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE])
509
621
  if (requesterParticipantModel) {
622
+ step = 'oracleRequest-2'
510
623
  const response = await oracle.oracleRequest(headers, method, params, query, undefined, cache)
511
624
  if (response) {
512
625
  const responsePayload = {
@@ -520,31 +633,44 @@ const deleteParticipants = async (headers, params, method, query, cache) => {
520
633
  const clonedHeaders = { ...headers }
521
634
  clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION] = headers[Enums.Http.Headers.FSPIOP.SOURCE]
522
635
  clonedHeaders[Enums.Http.Headers.FSPIOP.SOURCE] = Config.HUB_NAME
636
+ step = 'sendRequest-3'
523
637
  await participant.sendRequest(clonedHeaders, clonedHeaders[Enums.Http.Headers.FSPIOP.DESTINATION], callbackEndpointType, Enums.Http.RestMethods.PUT, responsePayload, options)
524
638
  } else {
639
+ step = 'sendErrorToParticipant-4'
525
640
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
526
641
  ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DELETE_PARTY_INFO_ERROR).toApiErrorObject(Config.ERROR_HANDLING), headers, params)
527
642
  }
528
643
  } else {
529
- Logger.isErrorEnabled && Logger.error('Requester FSP not found')
530
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, 'Requester FSP not found')
644
+ const errMessage = ERROR_MESSAGES.sourceFspNotFound
645
+ log.error(errMessage)
646
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
531
647
  }
532
648
  } else {
649
+ step = 'sendErrorToParticipant-5'
533
650
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
534
651
  ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DELETE_PARTY_INFO_ERROR).toApiErrorObject(Config.ERROR_HANDLING), headers, params)
535
652
  }
536
- Logger.isInfoEnabled && Logger.info('deleteParticipants::end')
653
+ log.info('deleteParticipants::end')
537
654
  histTimerEnd({ success: true })
538
655
  } catch (err) {
539
- Logger.isErrorEnabled && Logger.error(err)
656
+ log.error('error in deleteParticipants', err)
540
657
  try {
658
+ const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err, ErrorHandler.Enums.FSPIOPErrorCodes.DELETE_PARTY_INFO_ERROR)
541
659
  const errorCallbackEndpointType = params.SubId ? Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR : Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
542
660
  await participant.sendErrorToParticipant(headers[Enums.Http.Headers.FSPIOP.SOURCE], errorCallbackEndpointType,
543
- ErrorHandler.Factory.reformatFSPIOPError(err, ErrorHandler.Enums.FSPIOPErrorCodes.DELETE_PARTY_INFO_ERROR).toApiErrorObject(Config.ERROR_HANDLING), headers, params)
661
+ fspiopError.toApiErrorObject(Config.ERROR_HANDLING), headers, params)
662
+ const extensions = err.extensions || []
663
+ const system = extensions.find((element) => element.key === 'system')?.value || ''
664
+ errorCounter.inc({
665
+ code: fspiopError?.apiErrorCode,
666
+ system,
667
+ operation: 'deleteParticipants',
668
+ step
669
+ })
544
670
  } catch (exc) {
545
671
  // We can't do anything else here- we _must_ handle all errors _within_ this function because
546
672
  // we've already sent a sync response- we cannot throw.
547
- Logger.isErrorEnabled && Logger.error(exc)
673
+ log.error('error in participant.sendErrorToParticipant', exc)
548
674
  }
549
675
  histTimerEnd({ success: false })
550
676
  }