Exception Handler Framework - Node-RED UI Injection Node Example

A reusable framework for handling exceptions within Node-RED flows.

You can find a complete description of the framework here: https://developer.ibm.com/recipes/tutorials/nodered-exception-handling-framework/

[{"id":"414e9c28.b4196c","type":"tab","label":"Execption - Inject Node"},{"id":"42897537.52c8b4","type":"catch","z":"414e9c28.b4196c","name":"Catch for all other nodes","scope":["f6f53b9f.4d221","4dd4ef66.03e1b8","864ded33.dae1a","59caa2df.7c1fd4","410951de.14a398","79314e61.054b78","f428e5ca.4c08","56f733de.3ca7a4","5ef5f561.bb2aec"],"x":127,"y":624,"wires":[["bc568f94.f889a"]]},{"id":"bc568f94.f889a","type":"debug","z":"414e9c28.b4196c","name":"Uncaught Exceptions from Other Nodes","active":true,"console":"true","complete":"true","x":475.5,"y":624.25,"wires":[]},{"id":"5b7df849.9c367","type":"catch","z":"414e9c28.b4196c","name":"Exception Handler Catch","scope":["e7cf452b.698028"],"x":133.5,"y":522,"wires":[["d69b1ec7.8487f8"]]},{"id":"5ef5f561.bb2aec","type":"inject","z":"414e9c28.b4196c","name":"Zero Divisor","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":164,"y":306,"wires":[["e7cf452b.698028"]]},{"id":"e7cf452b.698028","type":"function","z":"414e9c28.b4196c","name":"computeFraction","func":"//Add a trace to a function with node.log\n//node.log(\"Entering the computeFraction node\");\n\n//  Compute Fraction\nfunction computeFraction(divisor) {\n    var fncResult = 1 / divisor;\n    return (fncResult);\n}\n\n//Evaluate Divisor and determine if we will compute the fraction.\nvar divisorValue = msg.payload;\ntry {\n\tif (typeof(divisorValue) === 'number') {\n\t\tif (divisorValue === 0) {\n\t\t\tthrow \"isZero\";\n\t\t} else {\n\t\t\tmsg.fraction = computeFraction(divisorValue);\n\t\t}\n\t} \n\telse {\t\t// Parameter is not numeric.\n\t\tif (divisorValue === \"\") {\t\n\t\t\tthrow \"isEmpty\";\n\t\t} else {\t// Divisor is some other non-numeric value.\n        \t\tthrow \"isNaN\";       \n    \t\t}\n\t}\n}\n\ncatch (e) {\n    \n    //  Raise error and terminate processing.  This will invoke custom error handler.\n    node.error(e, msg);\n    return; \n\n} finally {\n\t//executes whether or not an exception is thrown.\n}\n\nreturn msg;","outputs":"1","noerr":0,"x":434,"y":295.5,"wires":[["83220f16.204"]]},{"id":"59caa2df.7c1fd4","type":"inject","z":"414e9c28.b4196c","name":"Numeric Divisor (> zero)","topic":"","payload":"2","payloadType":"num","repeat":"","crontab":"","once":false,"x":132,"y":226,"wires":[["e7cf452b.698028"]]},{"id":"4dd4ef66.03e1b8","type":"inject","z":"414e9c28.b4196c","name":"Non-numeric Divisor","topic":"","payload":"$","payloadType":"str","repeat":"","crontab":"","once":false,"x":145,"y":346,"wires":[["e7cf452b.698028"]]},{"id":"83220f16.204","type":"debug","z":"414e9c28.b4196c","name":"Test Harness Output","active":true,"console":"false","complete":"true","x":794,"y":88.25,"wires":[]},{"id":"4ddb520c.49c444","type":"catch","z":"414e9c28.b4196c","name":"Catch for Exception Message Lookup","scope":["d69b1ec7.8487f8"],"x":170.5,"y":577.25,"wires":[["16de264a.e02ab2"]]},{"id":"16de264a.e02ab2","type":"debug","z":"414e9c28.b4196c","name":"Exceptions from Message Lookup","active":true,"console":"true","complete":"true","x":550.5,"y":576.5,"wires":[]},{"id":"864ded33.dae1a","type":"inject","z":"414e9c28.b4196c","name":"Numeric Divisor (< zero)","topic":"","payload":"-2","payloadType":"num","repeat":"","crontab":"","once":false,"x":134,"y":266,"wires":[["e7cf452b.698028"]]},{"id":"f6f53b9f.4d221","type":"inject","z":"414e9c28.b4196c","name":"Empty Divisor","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"x":165,"y":386,"wires":[["e7cf452b.698028"]]},{"id":"823066ce.fddbb8","type":"comment","z":"414e9c28.b4196c","name":"Inject Node Test Harness","info":"","x":125.5,"y":180.75,"wires":[]},{"id":"d8ba1d3.36f466","type":"comment","z":"414e9c28.b4196c","name":"Exception Handler","info":"","x":116.5,"y":472.75,"wires":[]},{"id":"d69b1ec7.8487f8","type":"function","z":"414e9c28.b4196c","name":"Exception Message Lookup","func":"//Obtain the Application ID.\nvar xcpAppID = flow.get(\"appID\");\nif (!xcpAppID) {\n    msg.exceptionMsg = \"Application error. Application identifier doesn't exist.\";\n    msg.nextAction = 999;\n    return msg;\n}\n\n//Obtain exception message from Throw.\nvar xcpLabel = msg.error.message;\nif (!xcpLabel) {\n    msg.exceptionMsg = \"Application error. Exception lable doesn't exist.\";\n    msg.nextAction = 999;\n    return msg;\n}\n\n//Determin existence of JSON containing exception messages.\nvar xcpMsgObj = global.get(\"xMsgObj\");\nif (!xcpMsgObj) {\n    msg.exceptionMsg = \"Application error. Exception JSON doesn't exist.\";\n    msg.nextAction = 999;\n    return msg;\n}\n\n//Obtain Current Timestamp in ISO format.\nfunction getCurrentTS() {\n    var dtGMT = new Date();\n    var strGMT = dtGMT.toISOString(); \n\n    return strGMT;\n}\n\n//Retrieve exception message by Application ID and exception label.\nfunction getByKey(xcpAppID, xcpLabel, currentTS, xcpMsgObj) {\n     var rslt = {\n        exceptionMsg: null,\n        nextStep: null\n        };\n\n    for (var i = 0; i < xcpMsgObj.length; i++) {\n        var xcpRecord = xcpMsgObj[i];\n        if ((xcpRecord.applicationID == xcpAppID) && \n        (xcpRecord.exceptionLabel == xcpLabel) && \n        (xcpRecord.activationTS <= currentTS) &&\n        (xcpRecord.deactivationTS >= currentTS)\n        ) {\n            rslt.exceptionMsg = xcpRecord.exceptionMsg;\n            rslt.nextStep = xcpRecord.nextStep;\n        }\n    }\n    return rslt;\n}\n\n//Retrieve Current Timestamp.\nvar currentTS = getCurrentTS();\n\n//Call the message lookup function to obtain exception message.\nvar xcpResult = getByKey(xcpAppID, xcpLabel, currentTS, xcpMsgObj);\nif (xcpResult) {\n    msg.exceptionMessage = xcpResult.exceptionMsg;\n    msg.nextStep = xcpResult.nextStep;\n} else {\n    msg.exceptionMessage = \"Application error. Exception message not found in data store.\";\n    msg.nextStep = 999;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":522,"wires":[["5f18d74d.0956e"]]},{"id":"79314e61.054b78","type":"inject","z":"414e9c28.b4196c","name":"Set Application ID","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":true,"x":186.5,"y":73.25,"wires":[["410951de.14a398"]]},{"id":"410951de.14a398","type":"function","z":"414e9c28.b4196c","name":"Set Application ID in Flow Context","func":"//Set the Application ID to be used to retrieve an exception message.\nflow.set(\"appID\", msg.payload);\n\nreturn msg;","outputs":1,"noerr":0,"x":452.5,"y":72.75,"wires":[["83220f16.204"]]},{"id":"56f733de.3ca7a4","type":"inject","z":"414e9c28.b4196c","name":"Set Exception Msg Object","topic":"","payload":"[{ \t\"applicationID\": \"1\", \t\"exceptionLabel\": \"isNaN\", \t\"exceptionMsg\": \"The divisor entered is not numeric.\", \t\"activationTS\": \"2017-05-23T18:30:30.000Z\", \t\"deactivationTS\": \"2019-05-23T18:30:30.000Z\", \t\"nextStep\": null }, { \t\"applicationID\": \"1\", \t\"exceptionLabel\": \"isZero\", \t\"exceptionMsg\": \"This message will be replaced during an alternate exception process.\", \t\"activationTS\": \"2017-05-23T18:30:30.000Z\", \t\"deactivationTS\": \"2019-05-23T18:30:30.000Z\", \t\"nextStep\": 55 }, { \t\"applicationID\": \"1\", \t\"exceptionLabel\": \"isEmpty\", \t\"exceptionMsg\": \"The divisor is empty.\", \t\"activationTS\": \"2017-05-23T18:30:30.000Z\", \t\"deactivationTS\": \"2019-05-23T18:30:30.000Z\", \t\"nextStep\": null }, { \t\"applicationID\": \"2\", \t\"exceptionLabel\": \"isNaN\", \t\"exceptionMsg\": \"The divisor entered is not numeric. Please retry.\", \t\"activationTS\": \"2017-05-23T18:30:30.000Z\", \t\"deactivationTS\": \"2019-05-23T18:30:30.000Z\", \t\"nextStep\": null }, { \t\"applicationID\": \"2\", \t\"exceptionLabel\": \"isZero\", \t\"exceptionMsg\": \"This message will be replaced during an alternate exception process.\", \t\"activationTS\": \"2017-05-23T18:30:30.000Z\", \t\"deactivationTS\": \"2019-05-23T18:30:30.000Z\", \t\"nextStep\": 55 }, { \t\"applicationID\": \"2\", \t\"exceptionLabel\": \"isEmpty\", \t\"exceptionMsg\": \"The divisor is empty. Please retry.\", \t\"activationTS\": \"2017-05-23T18:30:30.000Z\", \t\"deactivationTS\": \"2019-05-23T18:30:30.000Z\", \t\"nextStep\": null }]","payloadType":"json","repeat":"","crontab":"","once":true,"x":158.5,"y":112.25,"wires":[["f428e5ca.4c08"]]},{"id":"f428e5ca.4c08","type":"function","z":"414e9c28.b4196c","name":"Set Exception Object in Global Context","func":"//Set the message object exception messages will be retrieved from.\nglobal.set(\"xMsgObj\", msg.payload);\n\nreturn msg;","outputs":1,"noerr":0,"x":467,"y":112,"wires":[["83220f16.204"]]},{"id":"9d71953d.9031a8","type":"comment","z":"414e9c28.b4196c","name":"Set Application ID and Load JSON Message Object","info":"","x":205,"y":31,"wires":[]},{"id":"16c6f1a5.9df1a6","type":"debug","z":"414e9c28.b4196c","name":"Result from Exception Message Lookup","active":true,"console":"true","complete":"true","x":1038.5,"y":418.5,"wires":[]},{"id":"5f18d74d.0956e","type":"switch","z":"414e9c28.b4196c","name":"Next Step Action","property":"nextStep","propertyType":"msg","rules":[{"t":"eq","v":"55","vt":"num"},{"t":"else"}],"checkall":"true","outputs":2,"x":681,"y":522,"wires":[["20346fe0.34b01"],["16c6f1a5.9df1a6"]]},{"id":"20346fe0.34b01","type":"function","z":"414e9c28.b4196c","name":"Alternate Flow","func":"var inpMsg = \"The divisor entered (Zero) will cause a divide by zero error. Refer to: https://en.wikipedia.org/wiki/Division_by_zero\";\n\nmsg.exceptionMessage = inpMsg;\n\nreturn msg;","outputs":1,"noerr":0,"x":832,"y":348,"wires":[["16c6f1a5.9df1a6"]]}]
Behr3rd

Flow Info

created 2 weeks, 2 days ago

Node Types

Core
  • catch (x3)
  • comment (x3)
  • debug (x4)
  • function (x5)
  • inject (x7)
  • switch (x1)
Other
  • tab (x1)

Tags

  • exception
  • exceptionhandler
  • error
  • errorhandler
  • framework
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option